400 lines
16 KiB
Rust
400 lines
16 KiB
Rust
use tauri::{Manager, Emitter};
|
|
use serde::{Serialize, Deserialize};
|
|
|
|
struct Counter(std::sync::Mutex<u32>);
|
|
struct DebugMessages(std::sync::Mutex<Vec<DebugPayload>>);
|
|
|
|
#[derive(Serialize, Deserialize)]
|
|
struct Payload {
|
|
prompt: String,
|
|
files: Vec<String>,
|
|
dst: String,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize)]
|
|
struct IPCMessage {
|
|
#[serde(rename = "type")]
|
|
message_type: String,
|
|
data: serde_json::Value,
|
|
timestamp: Option<u64>,
|
|
id: Option<String>,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize)]
|
|
struct CounterPayload {
|
|
count: u32,
|
|
message: Option<String>,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Clone)]
|
|
struct DebugPayload {
|
|
level: String,
|
|
message: String,
|
|
data: Option<serde_json::Value>,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize)]
|
|
struct ImagePayload {
|
|
base64: String,
|
|
#[serde(rename = "mimeType")]
|
|
mime_type: String,
|
|
filename: Option<String>,
|
|
}
|
|
|
|
// Learn more about Tauri commands at https://tauri.app/develop/calling-rust/
|
|
#[tauri::command]
|
|
fn submit_prompt(prompt: &str, files: Vec<String>, dst: &str, window: tauri::Window) {
|
|
// Use eprintln! for debug logs so they go to stderr, not stdout
|
|
eprintln!("[RUST LOG]: submit_prompt command called.");
|
|
eprintln!("[RUST LOG]: - Prompt: {}", prompt);
|
|
eprintln!("[RUST LOG]: - Files: {:?}", files);
|
|
eprintln!("[RUST LOG]: - Dst: {}", dst);
|
|
|
|
let payload = Payload {
|
|
prompt: prompt.to_string(),
|
|
files,
|
|
dst: dst.to_string(),
|
|
};
|
|
let json_payload = serde_json::to_string(&payload).unwrap();
|
|
|
|
eprintln!("[RUST LOG]: - Sending JSON payload to stdout: {}", json_payload);
|
|
println!("{}", json_payload); // The actual payload - ONLY this should go to stdout
|
|
let _ = window.app_handle().exit(0);
|
|
}
|
|
|
|
#[tauri::command]
|
|
fn log_error_to_console(error: &str) {
|
|
eprintln!("[WebView ERROR forwarded from JS]: {}", error);
|
|
}
|
|
|
|
#[tauri::command]
|
|
fn increment_counter(state: tauri::State<'_, Counter>) -> Result<u32, String> {
|
|
eprintln!("[RUST LOG]: increment_counter command called.");
|
|
let mut counter = state.0.lock().unwrap();
|
|
*counter += 1;
|
|
let current_value = *counter;
|
|
eprintln!("[RUST LOG]: - Counter incremented to: {}", current_value);
|
|
Ok(current_value)
|
|
}
|
|
|
|
#[tauri::command]
|
|
fn get_counter(state: tauri::State<'_, Counter>) -> Result<u32, String> {
|
|
eprintln!("[RUST LOG]: get_counter command called.");
|
|
let counter = state.0.lock().unwrap();
|
|
let current_value = *counter;
|
|
eprintln!("[RUST LOG]: - Current counter value: {}", current_value);
|
|
Ok(current_value)
|
|
}
|
|
|
|
#[tauri::command]
|
|
fn reset_counter(state: tauri::State<'_, Counter>) -> Result<u32, String> {
|
|
eprintln!("[RUST LOG]: reset_counter command called.");
|
|
let mut counter = state.0.lock().unwrap();
|
|
*counter = 0;
|
|
eprintln!("[RUST LOG]: - Counter reset to: 0");
|
|
Ok(0)
|
|
}
|
|
|
|
#[tauri::command]
|
|
fn add_debug_message(message: String, level: String, data: Option<serde_json::Value>, state: tauri::State<'_, DebugMessages>) -> Result<(), String> {
|
|
eprintln!("[RUST LOG]: add_debug_message command called.");
|
|
eprintln!("[RUST LOG]: - Level: {}", level);
|
|
eprintln!("[RUST LOG]: - Message: {}", message);
|
|
|
|
let debug_payload = DebugPayload {
|
|
level,
|
|
message,
|
|
data,
|
|
};
|
|
|
|
let mut messages = state.0.lock().unwrap();
|
|
messages.push(debug_payload);
|
|
|
|
// Keep only the last 100 messages to prevent memory issues
|
|
if messages.len() > 100 {
|
|
let len = messages.len();
|
|
messages.drain(0..len - 100);
|
|
}
|
|
|
|
eprintln!("[RUST LOG]: - Debug message added. Total messages: {}", messages.len());
|
|
Ok(())
|
|
}
|
|
|
|
#[tauri::command]
|
|
fn get_debug_messages(state: tauri::State<'_, DebugMessages>) -> Result<Vec<DebugPayload>, String> {
|
|
eprintln!("[RUST LOG]: get_debug_messages command called.");
|
|
let messages = state.0.lock().unwrap();
|
|
let result = messages.clone();
|
|
eprintln!("[RUST LOG]: - Returning {} debug messages", result.len());
|
|
Ok(result)
|
|
}
|
|
|
|
#[tauri::command]
|
|
fn clear_debug_messages(state: tauri::State<'_, DebugMessages>) -> Result<(), String> {
|
|
eprintln!("[RUST LOG]: clear_debug_messages command called.");
|
|
let mut messages = state.0.lock().unwrap();
|
|
messages.clear();
|
|
eprintln!("[RUST LOG]: - Debug messages cleared");
|
|
Ok(())
|
|
}
|
|
|
|
#[tauri::command]
|
|
fn send_ipc_message(message_type: String, data: serde_json::Value, _window: tauri::Window) -> Result<(), String> {
|
|
eprintln!("[RUST LOG]: send_ipc_message command called.");
|
|
eprintln!("[RUST LOG]: - Type: {}", message_type);
|
|
eprintln!("[RUST LOG]: - Data: {}", data);
|
|
|
|
let ipc_message = IPCMessage {
|
|
message_type,
|
|
data,
|
|
timestamp: Some(std::time::SystemTime::now()
|
|
.duration_since(std::time::UNIX_EPOCH)
|
|
.unwrap()
|
|
.as_millis() as u64),
|
|
id: Some(format!("msg_{}_{}",
|
|
std::time::SystemTime::now()
|
|
.duration_since(std::time::UNIX_EPOCH)
|
|
.unwrap()
|
|
.as_millis(),
|
|
rand::random::<u32>())),
|
|
};
|
|
|
|
let json_message = serde_json::to_string(&ipc_message).unwrap();
|
|
eprintln!("[RUST LOG]: - Sending IPC message to stdout: {}", json_message);
|
|
println!("{}", json_message);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[tauri::command]
|
|
fn send_message_to_stdout(message: String) -> Result<(), String> {
|
|
eprintln!("[RUST LOG]: send_message_to_stdout command called.");
|
|
eprintln!("[RUST LOG]: - Message: {}", message);
|
|
|
|
// Send directly to stdout (this will be captured by images.ts)
|
|
println!("{}", message);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[tauri::command]
|
|
fn generate_image_via_backend(prompt: String, files: Vec<String>, dst: String) -> Result<(), String> {
|
|
eprintln!("[RUST LOG]: generate_image_via_backend called");
|
|
eprintln!("[RUST LOG]: - Prompt: {}", prompt);
|
|
eprintln!("[RUST LOG]: - Files: {:?}", files);
|
|
eprintln!("[RUST LOG]: - Dst: {}", dst);
|
|
|
|
// Send generation request to images.ts via stdout
|
|
let request = serde_json::json!({
|
|
"type": "generate_request",
|
|
"prompt": prompt,
|
|
"files": files,
|
|
"dst": dst,
|
|
"timestamp": std::time::SystemTime::now()
|
|
.duration_since(std::time::UNIX_EPOCH)
|
|
.unwrap()
|
|
.as_millis()
|
|
});
|
|
|
|
println!("{}", serde_json::to_string(&request).unwrap());
|
|
eprintln!("[RUST LOG]: Generation request sent to images.ts");
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[tauri::command]
|
|
fn request_config_from_images(_app: tauri::AppHandle) -> Result<(), String> {
|
|
eprintln!("[RUST LOG]: request_config_from_images called");
|
|
|
|
// Send request to images.ts via stdout
|
|
let request = serde_json::json!({
|
|
"type": "config_request",
|
|
"timestamp": std::time::SystemTime::now()
|
|
.duration_since(std::time::UNIX_EPOCH)
|
|
.unwrap()
|
|
.as_millis()
|
|
});
|
|
|
|
println!("{}", serde_json::to_string(&request).unwrap());
|
|
eprintln!("[RUST LOG]: Config request sent to images.ts");
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[tauri::command]
|
|
fn forward_config_to_frontend(prompt: Option<String>, dst: Option<String>, api_key: Option<String>, files: Vec<String>, app: tauri::AppHandle) -> Result<(), String> {
|
|
eprintln!("[RUST LOG]: forward_config_to_frontend called");
|
|
|
|
let config_data = serde_json::json!({
|
|
"prompt": prompt,
|
|
"dst": dst,
|
|
"apiKey": api_key,
|
|
"files": files
|
|
});
|
|
|
|
if let Err(e) = app.emit("config-received", &config_data) {
|
|
eprintln!("[RUST LOG]: Failed to emit config-received: {}", e);
|
|
return Err(format!("Failed to emit config: {}", e));
|
|
}
|
|
|
|
eprintln!("[RUST LOG]: Config forwarded to frontend successfully");
|
|
Ok(())
|
|
}
|
|
|
|
#[tauri::command]
|
|
fn forward_image_to_frontend(base64: String, mime_type: String, filename: String, app: tauri::AppHandle) -> Result<(), String> {
|
|
eprintln!("[RUST LOG]: forward_image_to_frontend called for {}", filename);
|
|
|
|
let image_data = serde_json::json!({
|
|
"base64": base64,
|
|
"mimeType": mime_type,
|
|
"filename": filename
|
|
});
|
|
|
|
if let Err(e) = app.emit("image-received", &image_data) {
|
|
eprintln!("[RUST LOG]: Failed to emit image-received: {}", e);
|
|
return Err(format!("Failed to emit image: {}", e));
|
|
}
|
|
|
|
eprintln!("[RUST LOG]: Image forwarded to frontend successfully");
|
|
Ok(())
|
|
}
|
|
|
|
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
|
pub fn run() {
|
|
let app = tauri::Builder::default()
|
|
.manage(Counter(std::sync::Mutex::new(0)))
|
|
.manage(DebugMessages(std::sync::Mutex::new(Vec::new())))
|
|
.plugin(tauri_plugin_opener::init())
|
|
.plugin(tauri_plugin_dialog::init())
|
|
.plugin(tauri_plugin_fs::init())
|
|
.plugin(tauri_plugin_http::init())
|
|
.invoke_handler(tauri::generate_handler![
|
|
submit_prompt,
|
|
log_error_to_console,
|
|
increment_counter,
|
|
get_counter,
|
|
reset_counter,
|
|
add_debug_message,
|
|
get_debug_messages,
|
|
clear_debug_messages,
|
|
send_message_to_stdout,
|
|
send_ipc_message,
|
|
request_config_from_images,
|
|
forward_config_to_frontend,
|
|
forward_image_to_frontend,
|
|
generate_image_via_backend
|
|
])
|
|
.setup(|app| {
|
|
let app_handle = app.handle().clone();
|
|
|
|
// Listen for stdin commands from images.ts
|
|
std::thread::spawn(move || {
|
|
use std::io::{self, BufRead, BufReader};
|
|
let stdin = io::stdin();
|
|
let reader = BufReader::new(stdin);
|
|
|
|
eprintln!("[RUST LOG]: Stdin listener thread started");
|
|
|
|
for line in reader.lines() {
|
|
if let Ok(line_content) = line {
|
|
if line_content.trim().is_empty() {
|
|
continue;
|
|
}
|
|
|
|
// Log stdin command but hide binary data
|
|
let log_content = if line_content.contains("\"base64\"") {
|
|
format!("[COMMAND WITH BASE64 DATA - {} chars]", line_content.len())
|
|
} else {
|
|
line_content.clone()
|
|
};
|
|
eprintln!("[RUST LOG]: Received stdin command: {}", log_content);
|
|
|
|
// Parse command from images.ts
|
|
if let Ok(command) = serde_json::from_str::<serde_json::Value>(&line_content) {
|
|
if let Some(cmd) = command.get("cmd").and_then(|v| v.as_str()) {
|
|
eprintln!("[RUST LOG]: Processing command: {}", cmd);
|
|
|
|
match cmd {
|
|
"forward_config_to_frontend" => {
|
|
eprintln!("[RUST LOG]: Forwarding config to frontend");
|
|
eprintln!("[RUST LOG]: - prompt: {:?}", command.get("prompt"));
|
|
eprintln!("[RUST LOG]: - dst: {:?}", command.get("dst"));
|
|
eprintln!("[RUST LOG]: - apiKey: {:?}", command.get("apiKey").map(|_| "[REDACTED]"));
|
|
eprintln!("[RUST LOG]: - files: {:?}", command.get("files"));
|
|
|
|
let config_data = serde_json::json!({
|
|
"prompt": command.get("prompt"),
|
|
"dst": command.get("dst"),
|
|
"apiKey": command.get("apiKey"),
|
|
"files": command.get("files")
|
|
});
|
|
|
|
if let Err(e) = app_handle.emit("config-received", &config_data) {
|
|
eprintln!("[RUST LOG]: Failed to emit config-received: {}", e);
|
|
} else {
|
|
eprintln!("[RUST LOG]: Config emitted successfully to frontend");
|
|
}
|
|
}
|
|
"forward_image_to_frontend" => {
|
|
if let (Some(filename), Some(base64), Some(mime_type)) = (
|
|
command.get("filename").and_then(|v| v.as_str()),
|
|
command.get("base64").and_then(|v| v.as_str()),
|
|
command.get("mimeType").and_then(|v| v.as_str())
|
|
) {
|
|
eprintln!("[RUST LOG]: Forwarding image to frontend: {}", filename);
|
|
let image_data = serde_json::json!({
|
|
"base64": base64,
|
|
"mimeType": mime_type,
|
|
"filename": filename
|
|
});
|
|
|
|
if let Err(e) = app_handle.emit("image-received", &image_data) {
|
|
eprintln!("[RUST LOG]: Failed to emit image-received: {}", e);
|
|
} else {
|
|
eprintln!("[RUST LOG]: Image emitted successfully: {}", filename);
|
|
}
|
|
}
|
|
}
|
|
"generation_result" => {
|
|
eprintln!("[RUST LOG]: Forwarding generation result to frontend");
|
|
if let Err(e) = app_handle.emit("generation-result", &command) {
|
|
eprintln!("[RUST LOG]: Failed to emit generation-result: {}", e);
|
|
} else {
|
|
eprintln!("[RUST LOG]: Generation result emitted successfully");
|
|
}
|
|
}
|
|
"generation_error" => {
|
|
eprintln!("[RUST LOG]: Forwarding generation error to frontend");
|
|
if let Err(e) = app_handle.emit("generation-error", &command) {
|
|
eprintln!("[RUST LOG]: Failed to emit generation-error: {}", e);
|
|
} else {
|
|
eprintln!("[RUST LOG]: Generation error emitted successfully");
|
|
}
|
|
}
|
|
_ => {
|
|
eprintln!("[RUST LOG]: Unknown command: {}", cmd);
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
eprintln!("[RUST LOG]: Failed to parse command as JSON");
|
|
}
|
|
}
|
|
}
|
|
eprintln!("[RUST LOG]: Stdin listener thread ended");
|
|
});
|
|
|
|
Ok(())
|
|
})
|
|
.build(tauri::generate_context!())
|
|
.expect("error while building tauri application");
|
|
|
|
app.run(|_app_handle, event| match event {
|
|
tauri::RunEvent::ExitRequested { api, .. } => {
|
|
api.prevent_exit();
|
|
}
|
|
_ => {}
|
|
});
|
|
}
|