Skip to content

Commit c29750d

Browse files
authored
feat: Support password update (#135)
Signed-off-by: currantw <[email protected]>
1 parent 8c98090 commit c29750d

File tree

4 files changed

+377
-4
lines changed

4 files changed

+377
-4
lines changed

rust/src/lib.rs

Lines changed: 90 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1037,10 +1037,98 @@ pub unsafe extern "C-unwind" fn refresh_iam_token(
10371037
);
10381038
},
10391039
};
1040+
1041+
async_panic_guard.panicked = false;
1042+
});
1043+
1044+
panic_guard.panicked = false;
1045+
}
1046+
1047+
/// Update connection password
1048+
///
1049+
/// # Arguments
1050+
/// * `client_ptr` - Pointer to the client
1051+
/// * `callback_index` - Callback index for async response
1052+
/// * `password` - New password (null for password removal)
1053+
/// * `immediate_auth` - Whether to authenticate immediately
1054+
///
1055+
/// # Safety
1056+
/// * `client_ptr` must be a valid pointer to a Client
1057+
/// * `password` must be a valid C string or null
1058+
#[unsafe(no_mangle)]
1059+
pub unsafe extern "C-unwind" fn update_connection_password(
1060+
client_ptr: *const c_void,
1061+
callback_index: usize,
1062+
password_ptr: *const c_char,
1063+
immediate_auth: bool,
1064+
) {
1065+
// Build client and add panic guard.
1066+
let client = unsafe {
1067+
Arc::increment_strong_count(client_ptr);
1068+
Arc::from_raw(client_ptr as *mut Client)
1069+
};
1070+
let core = client.core.clone();
1071+
1072+
let mut panic_guard = PanicGuard {
1073+
panicked: true,
1074+
failure_callback: core.failure_callback,
1075+
callback_index,
1076+
};
1077+
1078+
// Build password option.
1079+
let password = if password_ptr.is_null() {
1080+
None
1081+
} else {
1082+
match unsafe { CStr::from_ptr(password_ptr).to_str() } {
1083+
Ok(password_str) => {
1084+
if password_str.is_empty() {
1085+
None
1086+
} else {
1087+
Some(password_str.into())
1088+
}
1089+
}
1090+
Err(_) => {
1091+
unsafe {
1092+
report_error(
1093+
core.failure_callback,
1094+
callback_index,
1095+
"Invalid password argument".into(),
1096+
RequestErrorType::Unspecified,
1097+
);
1098+
}
1099+
panic_guard.panicked = false;
1100+
return;
1101+
}
1102+
}
1103+
};
1104+
1105+
// Run password update.
1106+
client.runtime.spawn(async move {
1107+
let mut async_panic_guard = PanicGuard {
1108+
panicked: true,
1109+
failure_callback: core.failure_callback,
1110+
callback_index,
1111+
};
1112+
1113+
let result = core.client.clone().update_connection_password(password, immediate_auth).await;
1114+
match result {
1115+
Ok(value) => {
1116+
let response = ResponseValue::from_value(value);
1117+
let ptr = Box::into_raw(Box::new(response));
1118+
unsafe { (core.success_callback)(callback_index, ptr) };
1119+
}
1120+
Err(err) => unsafe {
1121+
report_error(
1122+
core.failure_callback,
1123+
callback_index,
1124+
error_message(&err),
1125+
error_type(&err),
1126+
);
1127+
},
1128+
};
1129+
10401130
async_panic_guard.panicked = false;
1041-
drop(async_panic_guard);
10421131
});
10431132

10441133
panic_guard.panicked = false;
1045-
drop(panic_guard);
10461134
}

sources/Valkey.Glide/BaseClient.cs

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,66 @@ public async Task RefreshIamTokenAsync()
5858
}
5959
}
6060

61+
/// <summary>
62+
/// Update the current connection with a new password.
63+
/// </summary>
64+
/// <param name="password">The new password to update the connection with</param>
65+
/// <param name="immediateAuth">If <c>true</c>, re-authenticate immediately after updating password</param>
66+
/// <exception cref="ArgumentException">Thrown if <paramref name="password"/> is <c>null</c> or empty.</exception>
67+
/// <returns>A task that completes when the password is updated</returns>
68+
public async Task UpdateConnectionPasswordAsync(string password, bool immediateAuth = false)
69+
{
70+
if (password == null)
71+
{
72+
throw new ArgumentException("Password cannot be null", nameof(password));
73+
}
74+
75+
if (password.Length == 0)
76+
{
77+
throw new ArgumentException("Password cannot be empty", nameof(password));
78+
}
79+
80+
Message message = MessageContainer.GetMessageForCall();
81+
IntPtr passwordPtr = Marshal.StringToHGlobalAnsi(password);
82+
try
83+
{
84+
UpdateConnectionPasswordFfi(ClientPointer, (ulong)message.Index, passwordPtr, immediateAuth);
85+
IntPtr response = await message;
86+
try
87+
{
88+
HandleResponse(response);
89+
}
90+
finally
91+
{
92+
FreeResponse(response);
93+
}
94+
}
95+
finally
96+
{
97+
Marshal.FreeHGlobal(passwordPtr);
98+
}
99+
}
100+
101+
/// <summary>
102+
/// Clear the password from the current connection.
103+
/// </summary>
104+
/// <param name="immediateAuth">If <c>true</c>, re-authenticate immediately after clearing password</param>
105+
/// <returns>A task that completes when the password is cleared</returns>
106+
public async Task ClearConnectionPasswordAsync(bool immediateAuth = false)
107+
{
108+
Message message = MessageContainer.GetMessageForCall();
109+
110+
UpdateConnectionPasswordFfi(ClientPointer, (ulong)message.Index, IntPtr.Zero, immediateAuth);
111+
IntPtr response = await message;
112+
try
113+
{
114+
HandleResponse(response);
115+
}
116+
finally
117+
{
118+
FreeResponse(response);
119+
}
120+
}
61121
#endregion public methods
62122

63123
#region protected methods

sources/Valkey.Glide/Internals/FFI.methods.cs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,9 @@ public static partial void InvokeScriptFfi(
7070
[UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
7171
public static partial void RemoveClusterScanCursorFfi(IntPtr cursorId);
7272

73+
[LibraryImport("libglide_rs", EntryPoint = "update_connection_password")]
74+
[UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
75+
public static partial void UpdateConnectionPasswordFfi(IntPtr client, ulong index, IntPtr password, [MarshalAs(UnmanagedType.U1)] bool immediateAuth);
7376

7477
[LibraryImport("libglide_rs", EntryPoint = "refresh_iam_token")]
7578
[UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
@@ -101,7 +104,7 @@ public static partial void InvokeScriptFfi(
101104

102105
[DllImport("libglide_rs", CallingConvention = CallingConvention.Cdecl, EntryPoint = "free_drop_script_error")]
103106
public static extern void FreeDropScriptError(IntPtr errorBuffer);
104-
107+
105108
[DllImport("libglide_rs", CallingConvention = CallingConvention.Cdecl, EntryPoint = "invoke_script")]
106109
public static extern void InvokeScriptFfi(
107110
IntPtr client,
@@ -121,7 +124,10 @@ public static extern void InvokeScriptFfi(
121124

122125
[DllImport("libglide_rs", CallingConvention = CallingConvention.Cdecl, EntryPoint = "remove_cluster_scan_cursor")]
123126
public static extern void RemoveClusterScanCursorFfi(IntPtr cursorId);
124-
127+
128+
[DllImport("libglide_rs", CallingConvention = CallingConvention.Cdecl, EntryPoint = "update_connection_password")]
129+
public static extern void UpdateConnectionPasswordFfi(IntPtr client, ulong index, IntPtr password, [MarshalAs(UnmanagedType.U1)] bool immediateAuth);
130+
125131
[DllImport("libglide_rs", CallingConvention = CallingConvention.Cdecl, EntryPoint = "refresh_iam_token")]
126132
public static extern void RefreshIamTokenFfi(IntPtr client, ulong index);
127133
#endif

0 commit comments

Comments
 (0)