Configured sidecar

- Add the sidecar to start the .NET server when running the app
- Add proper logging
- Add message handling for communication between .NET and Rust/Tauri
- Add dynamic port allocation for the .NET server
- Add transition to .NET app, i.e., a loading screen
This commit is contained in:
Thorsten Sommer 2024-05-12 14:40:06 +02:00
parent c633053663
commit b44a95c67b
Signed by: tsommer
GPG Key ID: 371BBA77A02C0108
4 changed files with 726 additions and 39 deletions

445
runtime/Cargo.lock generated
View File

@ -157,7 +157,7 @@ dependencies = [
"polling 2.8.0",
"rustix 0.37.27",
"slab",
"socket2",
"socket2 0.4.10",
"waker-fn",
]
@ -448,6 +448,9 @@ name = "bytes"
version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9"
dependencies = [
"serde",
]
[[package]]
name = "cairo-rs"
@ -914,7 +917,7 @@ dependencies = [
"rustc_version",
"toml 0.8.12",
"vswhom",
"winreg",
"winreg 0.52.0",
]
[[package]]
@ -1090,6 +1093,21 @@ dependencies = [
"miniz_oxide",
]
[[package]]
name = "flexi_logger"
version = "0.28.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f248c29a6d4bc5d065c9e9068d858761a0dcd796759f7801cc14db35db23abd8"
dependencies = [
"chrono",
"glob",
"is-terminal",
"log",
"nu-ansi-term 0.49.0",
"regex",
"thiserror",
]
[[package]]
name = "fnv"
version = "1.0.7"
@ -1573,6 +1591,25 @@ dependencies = [
"syn 1.0.109",
]
[[package]]
name = "h2"
version = "0.3.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb2c4422095b67ee78da96fbb51a4cc413b3b25883c7717ff7ca1ab31022c9c9"
dependencies = [
"bytes",
"fnv",
"futures-core",
"futures-sink",
"futures-util",
"http",
"indexmap 2.2.6",
"slab",
"tokio",
"tokio-util",
"tracing",
]
[[package]]
name = "hashbrown"
version = "0.12.3"
@ -1661,12 +1698,72 @@ dependencies = [
"itoa 1.0.11",
]
[[package]]
name = "http-body"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2"
dependencies = [
"bytes",
"http",
"pin-project-lite",
]
[[package]]
name = "http-range"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "21dec9db110f5f872ed9699c3ecf50cf16f423502706ba5c72462e28d3157573"
[[package]]
name = "httparse"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904"
[[package]]
name = "httpdate"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
[[package]]
name = "hyper"
version = "0.14.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80"
dependencies = [
"bytes",
"futures-channel",
"futures-core",
"futures-util",
"h2",
"http",
"http-body",
"httparse",
"httpdate",
"itoa 1.0.11",
"pin-project-lite",
"socket2 0.5.7",
"tokio",
"tower-service",
"tracing",
"want",
]
[[package]]
name = "hyper-tls"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905"
dependencies = [
"bytes",
"hyper",
"native-tls",
"tokio",
"tokio-native-tls",
]
[[package]]
name = "iana-time-zone"
version = "0.1.60"
@ -1808,6 +1905,23 @@ dependencies = [
"windows-sys 0.48.0",
]
[[package]]
name = "ipnet"
version = "2.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3"
[[package]]
name = "is-terminal"
version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b"
dependencies = [
"hermit-abi",
"libc",
"windows-sys 0.52.0",
]
[[package]]
name = "itoa"
version = "0.4.8"
@ -2067,16 +2181,25 @@ dependencies = [
"autocfg",
]
[[package]]
name = "mime"
version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
[[package]]
name = "mindwork-ai-studio"
version = "0.1.0"
dependencies = [
"arboard",
"flexi_logger",
"keyring",
"log",
"serde",
"serde_json",
"tauri",
"tauri-build",
"tokio",
]
[[package]]
@ -2089,6 +2212,35 @@ dependencies = [
"simd-adler32",
]
[[package]]
name = "mio"
version = "0.8.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09"
dependencies = [
"libc",
"wasi 0.11.0+wasi-snapshot-preview1",
"windows-sys 0.48.0",
]
[[package]]
name = "native-tls"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e"
dependencies = [
"lazy_static",
"libc",
"log",
"openssl",
"openssl-probe",
"openssl-sys",
"schannel",
"security-framework",
"security-framework-sys",
"tempfile",
]
[[package]]
name = "ndk"
version = "0.6.0"
@ -2151,6 +2303,15 @@ dependencies = [
"winapi",
]
[[package]]
name = "nu-ansi-term"
version = "0.49.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c073d3c1930d0751774acf49e66653acecb416c3a54c6ec095a9b11caddb5a68"
dependencies = [
"windows-sys 0.48.0",
]
[[package]]
name = "num"
version = "0.4.1"
@ -2377,6 +2538,50 @@ dependencies = [
"windows-sys 0.42.0",
]
[[package]]
name = "openssl"
version = "0.10.59"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a257ad03cd8fb16ad4172fedf8094451e1af1c4b70097636ef2eac9a5f0cc33"
dependencies = [
"bitflags 2.5.0",
"cfg-if",
"foreign-types 0.3.2",
"libc",
"once_cell",
"openssl-macros",
"openssl-sys",
]
[[package]]
name = "openssl-macros"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.55",
]
[[package]]
name = "openssl-probe"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
[[package]]
name = "openssl-sys"
version = "0.9.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40a4130519a360279579c2053038317e40eff64d13fd3f004f9e1b72b8a6aaf9"
dependencies = [
"cc",
"libc",
"pkg-config",
"vcpkg",
]
[[package]]
name = "ordered-stream"
version = "0.2.0"
@ -2387,6 +2592,16 @@ dependencies = [
"pin-project-lite",
]
[[package]]
name = "os_pipe"
version = "1.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57119c3b893986491ec9aa85056780d3a0f3cf4da7cc09dd3650dbd6c6738fb9"
dependencies = [
"libc",
"windows-sys 0.52.0",
]
[[package]]
name = "overload"
version = "0.1.1"
@ -2916,6 +3131,48 @@ version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56"
[[package]]
name = "reqwest"
version = "0.11.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c6920094eb85afde5e4a138be3f2de8bbdf28000f0029e72c45025a56b042251"
dependencies = [
"base64 0.21.7",
"bytes",
"encoding_rs",
"futures-core",
"futures-util",
"h2",
"http",
"http-body",
"hyper",
"hyper-tls",
"ipnet",
"js-sys",
"log",
"mime",
"native-tls",
"once_cell",
"percent-encoding",
"pin-project-lite",
"rustls-pemfile",
"serde",
"serde_json",
"serde_urlencoded",
"sync_wrapper",
"system-configuration",
"tokio",
"tokio-native-tls",
"tokio-util",
"tower-service",
"url",
"wasm-bindgen",
"wasm-bindgen-futures",
"wasm-streams",
"web-sys",
"winreg 0.50.0",
]
[[package]]
name = "rustc-demangle"
version = "0.1.23"
@ -2958,6 +3215,15 @@ dependencies = [
"windows-sys 0.52.0",
]
[[package]]
name = "rustls-pemfile"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c"
dependencies = [
"base64 0.21.7",
]
[[package]]
name = "rustversion"
version = "1.0.14"
@ -2979,6 +3245,15 @@ dependencies = [
"winapi-util",
]
[[package]]
name = "schannel"
version = "0.1.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88"
dependencies = [
"windows-sys 0.48.0",
]
[[package]]
name = "scoped-tls"
version = "1.0.1"
@ -3114,6 +3389,18 @@ dependencies = [
"serde",
]
[[package]]
name = "serde_urlencoded"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd"
dependencies = [
"form_urlencoded",
"itoa 1.0.11",
"ryu",
"serde",
]
[[package]]
name = "serde_with"
version = "3.7.0"
@ -3207,6 +3494,16 @@ dependencies = [
"lazy_static",
]
[[package]]
name = "shared_child"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0d94659ad3c2137fef23ae75b03d5241d633f8acded53d672decfa0e6e0caef"
dependencies = [
"libc",
"winapi",
]
[[package]]
name = "signal-hook-registry"
version = "1.4.1"
@ -3253,6 +3550,16 @@ dependencies = [
"winapi",
]
[[package]]
name = "socket2"
version = "0.5.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c"
dependencies = [
"libc",
"windows-sys 0.52.0",
]
[[package]]
name = "soup2"
version = "0.2.1"
@ -3362,6 +3669,33 @@ dependencies = [
"unicode-ident",
]
[[package]]
name = "sync_wrapper"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160"
[[package]]
name = "system-configuration"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7"
dependencies = [
"bitflags 1.3.2",
"core-foundation",
"system-configuration-sys",
]
[[package]]
name = "system-configuration-sys"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9"
dependencies = [
"core-foundation-sys",
"libc",
]
[[package]]
name = "system-deps"
version = "5.0.0"
@ -3470,6 +3804,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f078117725e36d55d29fafcbb4b1e909073807ca328ae8deb8c0b3843aac0fed"
dependencies = [
"anyhow",
"bytes",
"cocoa",
"dirs-next",
"dunce",
@ -3483,18 +3818,22 @@ dependencies = [
"heck 0.4.1",
"http",
"ignore",
"indexmap 1.9.3",
"objc",
"once_cell",
"open",
"os_pipe",
"percent-encoding",
"rand 0.8.5",
"raw-window-handle",
"regex",
"reqwest",
"semver",
"serde",
"serde_json",
"serde_repr",
"serialize-to-javascript",
"shared_child",
"state",
"tar",
"tauri-macros",
@ -3775,8 +4114,36 @@ checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787"
dependencies = [
"backtrace",
"bytes",
"libc",
"mio",
"num_cpus",
"pin-project-lite",
"socket2 0.5.7",
"windows-sys 0.48.0",
]
[[package]]
name = "tokio-native-tls"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2"
dependencies = [
"native-tls",
"tokio",
]
[[package]]
name = "tokio-util"
version = "0.7.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15"
dependencies = [
"bytes",
"futures-core",
"futures-sink",
"pin-project-lite",
"tokio",
"tracing",
]
[[package]]
@ -3847,6 +4214,12 @@ dependencies = [
"winnow 0.6.5",
]
[[package]]
name = "tower-service"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52"
[[package]]
name = "tracing"
version = "0.1.40"
@ -3897,7 +4270,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b"
dependencies = [
"matchers",
"nu-ansi-term",
"nu-ansi-term 0.46.0",
"once_cell",
"regex",
"sharded-slab",
@ -3917,6 +4290,12 @@ dependencies = [
"serde_json",
]
[[package]]
name = "try-lock"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
[[package]]
name = "typenum"
version = "1.17.0"
@ -3994,6 +4373,12 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
[[package]]
name = "vcpkg"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
[[package]]
name = "version-compare"
version = "0.0.11"
@ -4048,6 +4433,15 @@ dependencies = [
"winapi-util",
]
[[package]]
name = "want"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e"
dependencies = [
"try-lock",
]
[[package]]
name = "wasi"
version = "0.9.0+wasi-snapshot-preview1"
@ -4085,6 +4479,18 @@ dependencies = [
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-futures"
version = "0.4.41"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "877b9c3f61ceea0e56331985743b13f3d25c406a7098d45180fb5f09bc19ed97"
dependencies = [
"cfg-if",
"js-sys",
"wasm-bindgen",
"web-sys",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.92"
@ -4114,6 +4520,29 @@ version = "0.2.92"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96"
[[package]]
name = "wasm-streams"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b65dc4c90b63b118468cf747d8bf3566c1913ef60be765b5730ead9e0a3ba129"
dependencies = [
"futures-util",
"js-sys",
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
]
[[package]]
name = "web-sys"
version = "0.3.68"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96565907687f7aceb35bc5fc03770a8a0471d82e479f25832f54a0e3f4b28446"
dependencies = [
"js-sys",
"wasm-bindgen",
]
[[package]]
name = "webkit2gtk"
version = "0.18.2"
@ -4546,6 +4975,16 @@ dependencies = [
"memchr",
]
[[package]]
name = "winreg"
version = "0.50.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1"
dependencies = [
"cfg-if",
"windows-sys 0.48.0",
]
[[package]]
name = "winreg"
version = "0.52.0"

View File

@ -9,11 +9,14 @@ authors = ["Thorsten Sommer"]
tauri-build = { version = "1.5", features = [] }
[dependencies]
tauri = { version = "1.6", features = [ "path-all", "shell-open"] }
tauri = { version = "1.6", features = [ "http-all", "shell-sidecar", "path-all", "shell-open"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
keyring = "2"
arboard = "3.4.0"
tokio = "1.37.0"
flexi_logger = "0.28"
log = "0.4"
[features]
# this feature is used for production builds or when `devPath` points to the filesystem

View File

@ -1,30 +1,230 @@
// Prevents an additional console window on Windows in release, DO NOT REMOVE!!
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
extern crate core;
use std::net::TcpListener;
use std::sync::{Arc, Mutex};
use arboard::Clipboard;
use keyring::Entry;
use serde::Serialize;
use tauri::{Manager, Url, Window, WindowUrl};
use tauri::api::process::{Command, CommandChild, CommandEvent};
use tauri::utils::config::AppUrl;
use tokio::time;
use flexi_logger::{AdaptiveFormat, Logger};
use log::{debug, error, info, warn};
fn main() {
Logger::try_with_str("debug").expect("Cannot create logging")
.log_to_stdout()
.adaptive_format_for_stdout(AdaptiveFormat::Detailed)
.start().expect("Cannot start logging");
if is_dev() {
warn!("Running in development mode.");
} else {
info!("Running in production mode.");
}
let port = match is_dev() {
true => 5000,
false => get_available_port().unwrap(),
};
let url = match Url::parse(format!("http://localhost:{port}").as_str())
{
Ok(url) => url,
Err(msg) => {
error!("Error while parsing URL: {msg}");
return;
}
};
let app_url = AppUrl::Url(WindowUrl::External(url.clone()));
let app_url_log = app_url.clone();
info!("Try to start the .NET server on {app_url_log}...");
// Arc for the server process to stop it later:
let server: Arc<Mutex<Option<CommandChild>>> = Arc::new(Mutex::new(None));
let server_spawn_clone = server.clone();
// Channel to communicate with the server process:
let (sender, mut receiver) = tauri::async_runtime::channel(100);
if is_prod() {
tauri::async_runtime::spawn(async move {
let (mut rx, child) = Command::new_sidecar("mindworkAIStudio")
.expect("Failed to create sidecar")
.args([format!("{port}").as_str()])
.spawn()
.expect("Failed to spawn .NET server process.");
let server_pid = child.pid();
debug!(".NET server process started with PID={server_pid}.");
// Save the server process to stop it later:
*server_spawn_clone.lock().unwrap() = Some(child);
info!("Waiting for .NET server to boot...");
while let Some(CommandEvent::Stdout(line)) = rx.recv().await {
let line_lower = line.to_lowercase();
let line_cleared = line_lower.trim();
match line_cleared
{
"rust/tauri server started" => _ = sender.send(ServerEvent::Started).await,
_ if line_cleared.contains("fail") || line_cleared.contains("error") || line_cleared.contains("exception") => _ = sender.send(ServerEvent::Error(line)).await,
_ if line_cleared.contains("warn") => _ = sender.send(ServerEvent::Warning(line)).await,
_ if line_cleared.contains("404") => _ = sender.send(ServerEvent::NotFound(line)).await,
_ => (),
}
}
let sending_stop_result = sender.send(ServerEvent::Stopped).await;
match sending_stop_result {
Ok(_) => (),
Err(e) => error!("Was not able to send the server stop message: {e}."),
}
});
}
let main_window: Arc<Mutex<Option<Window>>> = Arc::new(Mutex::new(None));
let main_window_spawn_clone = main_window.clone();
let server_receive_clone = server.clone();
// Create a thread to handle server events:
tauri::async_runtime::spawn(async move {
loop {
match receiver.recv().await {
Some(ServerEvent::Started) => {
info!("The .NET server was booted successfully.");
// Try to get the main window. If it is not available yet, wait for it:
let mut main_window_ready = false;
let mut main_window_status_reported = false;
while !main_window_ready
{
main_window_ready = {
let main_window = main_window_spawn_clone.lock().unwrap();
main_window.is_some()
};
if !main_window_ready {
if !main_window_status_reported {
info!("Waiting for main window to be ready, because .NET was faster than Tauri.");
main_window_status_reported = true;
}
time::sleep(time::Duration::from_millis(100)).await;
}
}
let main_window = main_window_spawn_clone.lock().unwrap();
let js_location_change = format!("window.location = '{url}';");
let location_change_result = main_window.as_ref().unwrap().eval(js_location_change.as_str());
match location_change_result {
Ok(_) => info!("Location was changed to {url}."),
Err(e) => error!("Failed to change location to {url}: {e}."),
}
},
Some(ServerEvent::NotFound(line)) => {
warn!("The .NET server issued a 404 error: {line}.");
},
Some(ServerEvent::Warning(line)) => {
warn!("The .NET server issued a warning: {line}.");
},
Some(ServerEvent::Error(line)) => {
error!("The .NET server issued an error: {line}.");
},
Some(ServerEvent::Stopped) => {
warn!("The .NET server was stopped.");
*server_receive_clone.lock().unwrap() = None;
},
None => {
debug!("Server event channel was closed.");
break;
},
}
}
});
info!("Starting Tauri app...");
tauri::Builder::default()
.setup(move |app| {
let window = app.get_window("main").expect("Failed to get main window.");
*main_window.lock().unwrap() = Some(window);
Ok(())
})
.invoke_handler(tauri::generate_handler![store_secret, get_secret, delete_secret, set_clipboard])
.run(tauri::generate_context!())
.expect("error while running tauri application");
.expect("Error while running Tauri application");
info!("Tauri app was stopped.");
if is_prod() {
info!("Try to stop the .NET server as well...");
if let Some(server_process) = server.lock().unwrap().take() {
let server_kill_result = server_process.kill();
match server_kill_result {
Ok(_) => info!("The .NET server process was stopped."),
Err(e) => error!("Failed to stop the .NET server process: {e}."),
}
} else {
warn!("The .NET server process was not started or already stopped.");
}
}
}
// Enum for server events:
enum ServerEvent {
Started,
NotFound(String),
Warning(String),
Error(String),
Stopped,
}
pub fn is_dev() -> bool {
cfg!(dev)
}
pub fn is_prod() -> bool {
!is_dev()
}
fn get_available_port() -> Option<u16> {
TcpListener::bind(("127.0.0.1", 0))
.map(|listener| listener.local_addr().unwrap().port())
.ok()
}
#[tauri::command]
fn store_secret(destination: String, user_name: String, secret: String) -> StoreSecretResponse {
let entry = Entry::new(&format!("mindwork-ai-studio::{}", destination), user_name.as_str()).unwrap();
let service = format!("mindwork-ai-studio::{}", destination);
let entry = Entry::new(service.as_str(), user_name.as_str()).unwrap();
let result = entry.set_password(secret.as_str());
match result {
Ok(_) => StoreSecretResponse {
success: true,
issue: String::from(""),
Ok(_) => {
info!("Secret for {service} and user {user_name} was stored successfully.");
StoreSecretResponse {
success: true,
issue: String::from(""),
}
},
Err(e) => StoreSecretResponse {
success: false,
issue: e.to_string(),
Err(e) => {
error!("Failed to store secret for {service} and user {user_name}: {e}.");
StoreSecretResponse {
success: false,
issue: e.to_string(),
}
},
}
}
@ -37,19 +237,26 @@ struct StoreSecretResponse {
#[tauri::command]
fn get_secret(destination: String, user_name: String) -> RequestedSecret {
let entry = Entry::new(&format!("mindwork-ai-studio::{}", destination), user_name.as_str()).unwrap();
let service = format!("mindwork-ai-studio::{}", destination);
let entry = Entry::new(service.as_str(), user_name.as_str()).unwrap();
let secret = entry.get_password();
match secret {
Ok(s) => RequestedSecret {
success: true,
secret: s,
issue: String::from(""),
Ok(s) => {
info!("Secret for {service} and user {user_name} was retrieved successfully.");
RequestedSecret {
success: true,
secret: s,
issue: String::from(""),
}
},
Err(e) => RequestedSecret {
success: false,
secret: String::from(""),
issue: e.to_string(),
Err(e) => {
error!("Failed to retrieve secret for {service} and user {user_name}: {e}.");
RequestedSecret {
success: false,
secret: String::from(""),
issue: e.to_string(),
}
},
}
}
@ -63,17 +270,24 @@ struct RequestedSecret {
#[tauri::command]
fn delete_secret(destination: String, user_name: String) -> DeleteSecretResponse {
let entry = Entry::new(&format!("mindwork-ai-studio::{}", destination), user_name.as_str()).unwrap();
let service = format!("mindwork-ai-studio::{}", destination);
let entry = Entry::new(service.as_str(), user_name.as_str()).unwrap();
let result = entry.delete_password();
match result {
Ok(_) => DeleteSecretResponse {
success: true,
issue: String::from(""),
Ok(_) => {
warn!("Secret for {service} and user {user_name} was deleted successfully.");
DeleteSecretResponse {
success: true,
issue: String::from(""),
}
},
Err(e) => DeleteSecretResponse {
success: false,
issue: e.to_string(),
Err(e) => {
error!("Failed to delete secret for {service} and user {user_name}: {e}.");
DeleteSecretResponse {
success: false,
issue: e.to_string(),
}
},
}
}
@ -89,22 +303,31 @@ fn set_clipboard(text: String) -> SetClipboardResponse {
let clipboard_result = Clipboard::new();
let mut clipboard = match clipboard_result {
Ok(clipboard) => clipboard,
Err(e) => return SetClipboardResponse {
success: false,
issue: e.to_string(),
Err(e) => {
error!("Failed to get the clipboard instance: {e}.");
return SetClipboardResponse {
success: false,
issue: e.to_string(),
}
},
};
let set_text_result = clipboard.set_text(text);
match set_text_result {
Ok(_) => SetClipboardResponse {
success: true,
issue: String::from(""),
Ok(_) => {
debug!("Text was set to the clipboard successfully.");
SetClipboardResponse {
success: true,
issue: String::from(""),
}
},
Err(e) => SetClipboardResponse {
success: false,
issue: e.to_string(),
Err(e) => {
error!("Failed to set text to the clipboard: {e}.");
SetClipboardResponse {
success: false,
issue: e.to_string(),
}
},
}
}

View File

@ -12,11 +12,26 @@
"allowlist": {
"all": false,
"shell": {
"sidecar": true,
"all": false,
"open": true
"open": true,
"scope": [
{
"name": "../app/MindWork AI Studio/bin/dist/mindworkAIStudio",
"sidecar": true,
"args": true
}
]
},
"path": {
"all": true
},
"http" : {
"all": true,
"request": true,
"scope": [
"http://localhost"
]
}
},
"windows": [
@ -29,12 +44,19 @@
}
],
"security": {
"csp": null
"csp": null,
"dangerousUseHttpScheme": true
},
"bundle": {
"active": true,
"targets": "all",
"identifier": "org.tsommer.mindwork-ai-studio",
"externalBin": [
"../app/MindWork AI Studio/bin/dist/mindworkAIStudio"
],
"macOS": {
"exceptionDomain": "localhost"
},
"icon": [
"icons/32x32.png",
"icons/128x128.png",