Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 90 additions & 2 deletions rust/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1037,10 +1037,98 @@ pub unsafe extern "C-unwind" fn refresh_iam_token(
);
},
};

async_panic_guard.panicked = false;
});

panic_guard.panicked = false;
}

/// Update connection password
///
/// # Arguments
/// * `client_ptr` - Pointer to the client
/// * `callback_index` - Callback index for async response
/// * `password` - New password (null for password removal)
/// * `immediate_auth` - Whether to authenticate immediately
///
/// # Safety
/// * `client_ptr` must be a valid pointer to a Client
/// * `password` must be a valid C string or null
#[unsafe(no_mangle)]
pub unsafe extern "C-unwind" fn update_connection_password(
client_ptr: *const c_void,
callback_index: usize,
password_ptr: *const c_char,
immediate_auth: bool,
) {
// Build client and add panic guard.
let client = unsafe {
Arc::increment_strong_count(client_ptr);
Arc::from_raw(client_ptr as *mut Client)
};
let core = client.core.clone();

let mut panic_guard = PanicGuard {
panicked: true,
failure_callback: core.failure_callback,
callback_index,
};

// Build password option.
let password = if password_ptr.is_null() {
None
} else {
match unsafe { CStr::from_ptr(password_ptr).to_str() } {
Ok(password_str) => {
if password_str.is_empty() {
None
} else {
Some(password_str.into())
}
}
Err(_) => {
unsafe {
report_error(
core.failure_callback,
callback_index,
"Invalid password argument".into(),
RequestErrorType::Unspecified,
);
}
panic_guard.panicked = false;
return;
}
}
};

// Run password update.
client.runtime.spawn(async move {
let mut async_panic_guard = PanicGuard {
panicked: true,
failure_callback: core.failure_callback,
callback_index,
};

let result = core.client.clone().update_connection_password(password, immediate_auth).await;
match result {
Ok(value) => {
let response = ResponseValue::from_value(value);
let ptr = Box::into_raw(Box::new(response));
unsafe { (core.success_callback)(callback_index, ptr) };
}
Err(err) => unsafe {
report_error(
core.failure_callback,
callback_index,
error_message(&err),
error_type(&err),
);
},
};

async_panic_guard.panicked = false;
drop(async_panic_guard);
});

panic_guard.panicked = false;
drop(panic_guard);
}
60 changes: 60 additions & 0 deletions sources/Valkey.Glide/BaseClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,66 @@ public async Task RefreshIamTokenAsync()
}
}

/// <summary>
/// Update the current connection with a new password.
/// </summary>
/// <param name="password">The new password to update the connection with</param>
/// <param name="immediateAuth">If <c>true</c>, re-authenticate immediately after updating password</param>
/// <exception cref="ArgumentException">Thrown if <paramref name="password"/> is <c>null</c> or empty.</exception>
/// <returns>A task that completes when the password is updated</returns>
public async Task UpdateConnectionPasswordAsync(string password, bool immediateAuth = false)
{
if (password == null)
{
throw new ArgumentException("Password cannot be null", nameof(password));
}

if (password.Length == 0)
{
throw new ArgumentException("Password cannot be empty", nameof(password));
}

Message message = MessageContainer.GetMessageForCall();
IntPtr passwordPtr = Marshal.StringToHGlobalAnsi(password);
try
{
UpdateConnectionPasswordFfi(ClientPointer, (ulong)message.Index, passwordPtr, immediateAuth);
IntPtr response = await message;
try
{
HandleResponse(response);
}
finally
{
FreeResponse(response);
}
}
finally
{
Marshal.FreeHGlobal(passwordPtr);
}
}

/// <summary>
/// Clear the password from the current connection.
/// </summary>
/// <param name="immediateAuth">If <c>true</c>, re-authenticate immediately after clearing password</param>
/// <returns>A task that completes when the password is cleared</returns>
public async Task ClearConnectionPasswordAsync(bool immediateAuth = false)
{
Message message = MessageContainer.GetMessageForCall();

UpdateConnectionPasswordFfi(ClientPointer, (ulong)message.Index, IntPtr.Zero, immediateAuth);
IntPtr response = await message;
try
{
HandleResponse(response);
}
finally
{
FreeResponse(response);
}
}
#endregion public methods

#region protected methods
Expand Down
10 changes: 8 additions & 2 deletions sources/Valkey.Glide/Internals/FFI.methods.cs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ public static partial void InvokeScriptFfi(
[UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
public static partial void RemoveClusterScanCursorFfi(IntPtr cursorId);

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

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

[DllImport("libglide_rs", CallingConvention = CallingConvention.Cdecl, EntryPoint = "free_drop_script_error")]
public static extern void FreeDropScriptError(IntPtr errorBuffer);

[DllImport("libglide_rs", CallingConvention = CallingConvention.Cdecl, EntryPoint = "invoke_script")]
public static extern void InvokeScriptFfi(
IntPtr client,
Expand All @@ -121,7 +124,10 @@ public static extern void InvokeScriptFfi(

[DllImport("libglide_rs", CallingConvention = CallingConvention.Cdecl, EntryPoint = "remove_cluster_scan_cursor")]
public static extern void RemoveClusterScanCursorFfi(IntPtr cursorId);


[DllImport("libglide_rs", CallingConvention = CallingConvention.Cdecl, EntryPoint = "update_connection_password")]
public static extern void UpdateConnectionPasswordFfi(IntPtr client, ulong index, IntPtr password, [MarshalAs(UnmanagedType.U1)] bool immediateAuth);

[DllImport("libglide_rs", CallingConvention = CallingConvention.Cdecl, EntryPoint = "refresh_iam_token")]
public static extern void RefreshIamTokenFfi(IntPtr client, ulong index);
#endif
Expand Down
Loading
Loading