Migrated the clipboard function from Tauri JS to the runtime API using encryption

This commit is contained in:
Thorsten Sommer 2024-08-27 20:25:28 +02:00
parent 79afd42195
commit 1d12facd58
Signed by: tsommer
GPG Key ID: 371BBA77A02C0108
5 changed files with 61 additions and 42 deletions

View File

@ -165,7 +165,7 @@ public abstract partial class AssistantBase : ComponentBase
protected async Task CopyToClipboard()
{
await this.Rust.CopyText2Clipboard(this.JsRuntime, this.Snackbar, this.Result2Copy());
await this.Rust.CopyText2Clipboard(this.Snackbar, this.Result2Copy());
}
private static string? GetButtonIcon(string icon)

View File

@ -100,7 +100,7 @@ public partial class ContentBlockComponent : ComponentBase
{
case ContentType.TEXT:
var textContent = (ContentText) this.Content;
await this.Rust.CopyText2Clipboard(this.JsRuntime, this.Snackbar, textContent.Text);
await this.Rust.CopyText2Clipboard(this.Snackbar, textContent.Text);
break;
default:

View File

@ -78,37 +78,45 @@ public sealed class Rust(string apiPort) : IDisposable
/// <summary>
/// Tries to copy the given text to the clipboard.
/// </summary>
/// <param name="jsRuntime">The JS runtime to access the Rust code.</param>
/// <param name="snackbar">The snackbar to show the result.</param>
/// <param name="text">The text to copy to the clipboard.</param>
public async Task CopyText2Clipboard(IJSRuntime jsRuntime, ISnackbar snackbar, string text)
public async Task CopyText2Clipboard(ISnackbar snackbar, string text)
{
var response = await jsRuntime.InvokeAsync<SetClipboardResponse>("window.__TAURI__.invoke", "set_clipboard", new SetClipboardText(text));
var msg = response.Success switch
var message = "Successfully copied the text to your clipboard";
var iconColor = Color.Error;
var severity = Severity.Error;
try
{
true => "Successfully copied text to clipboard!",
false => $"Failed to copy text to clipboard: {response.Issue}",
};
var response = await this.http.PostAsync("/clipboard/set", new StringContent(await text.Encrypt(this.encryptor!)));
if (!response.IsSuccessStatusCode)
{
this.logger!.LogError($"Failed to copy the text to the clipboard due to an network error: '{response.StatusCode}'");
message = "Failed to copy the text to your clipboard.";
return;
}
var severity = response.Success switch
var state = await response.Content.ReadFromJsonAsync<SetClipboardResponse>();
if (!state.Success)
{
true => Severity.Success,
false => Severity.Error,
};
this.logger!.LogError("Failed to copy the text to the clipboard.");
message = "Failed to copy the text to your clipboard.";
return;
}
snackbar.Add(msg, severity, config =>
iconColor = Color.Success;
severity = Severity.Success;
this.logger!.LogDebug("Successfully copied the text to the clipboard.");
}
finally
{
snackbar.Add(message, severity, config =>
{
config.Icon = Icons.Material.Filled.ContentCopy;
config.IconSize = Size.Large;
config.IconColor = severity switch
{
Severity.Success => Color.Success,
Severity.Error => Color.Error,
_ => Color.Default,
};
config.IconColor = iconColor;
});
}
}
public async Task<UpdateResponse> CheckForUpdate(IJSRuntime jsRuntime)
{

View File

@ -6,10 +6,8 @@ namespace AIStudio.Tools.Services;
/// Wire up the clipboard service to copy Markdown to the clipboard.
/// We use our own Rust-based clipboard service for this.
/// </summary>
public sealed class MarkdownClipboardService(Rust rust, IJSRuntime jsRuntime, ISnackbar snackbar) : IMudMarkdownClipboardService
public sealed class MarkdownClipboardService(Rust rust, ISnackbar snackbar) : IMudMarkdownClipboardService
{
private IJSRuntime JsRuntime { get; } = jsRuntime;
private ISnackbar Snackbar { get; } = snackbar;
private Rust Rust { get; } = rust;
@ -18,5 +16,5 @@ public sealed class MarkdownClipboardService(Rust rust, IJSRuntime jsRuntime, IS
/// Gets called when the user wants to copy the Markdown to the clipboard.
/// </summary>
/// <param name="text">The Markdown text to copy.</param>
public async ValueTask CopyToClipboardAsync(string text) => await this.Rust.CopyText2Clipboard(this.JsRuntime, this.Snackbar, text);
public async ValueTask CopyToClipboardAsync(string text) => await this.Rust.CopyText2Clipboard(this.Snackbar, text);
}

View File

@ -194,7 +194,7 @@ async fn main() {
//
tauri::async_runtime::spawn(async move {
_ = rocket::custom(figment)
.mount("/", routes![dotnet_port, dotnet_ready])
.mount("/", routes![dotnet_port, dotnet_ready, set_clipboard])
.ignite().await.unwrap()
.launch().await.unwrap();
});
@ -312,7 +312,7 @@ async fn main() {
})
.plugin(tauri_plugin_window_state::Builder::default().build())
.invoke_handler(tauri::generate_handler![
store_secret, get_secret, delete_secret, set_clipboard,
store_secret, get_secret, delete_secret,
check_for_update, install_update
])
.build(tauri::generate_context!())
@ -848,36 +848,49 @@ struct DeleteSecretResponse {
issue: String,
}
#[tauri::command]
fn set_clipboard(text: String) -> SetClipboardResponse {
#[post("/clipboard/set", data = "<encrypted_text>")]
fn set_clipboard(encrypted_text: EncryptedText) -> Json<SetClipboardResponse> {
// Decrypt this text first:
let decrypted_text = match ENCRYPTION.decrypt(&encrypted_text) {
Ok(text) => text,
Err(e) => {
error!(Source = "Clipboard"; "Failed to decrypt the text: {e}.");
return Json(SetClipboardResponse {
success: false,
issue: e,
})
},
};
let clipboard_result = Clipboard::new();
let mut clipboard = match clipboard_result {
Ok(clipboard) => clipboard,
Err(e) => {
error!(Source = "Clipboard"; "Failed to get the clipboard instance: {e}.");
return SetClipboardResponse {
return Json(SetClipboardResponse {
success: false,
issue: e.to_string(),
}
})
},
};
let set_text_result = clipboard.set_text(text);
let set_text_result = clipboard.set_text(decrypted_text);
match set_text_result {
Ok(_) => {
debug!(Source = "Clipboard"; "Text was set to the clipboard successfully.");
SetClipboardResponse {
Json(SetClipboardResponse {
success: true,
issue: String::from(""),
}
})
},
Err(e) => {
error!(Source = "Clipboard"; "Failed to set text to the clipboard: {e}.");
SetClipboardResponse {
Json(SetClipboardResponse {
success: false,
issue: e.to_string(),
}
})
},
}
}