use serde::{Deserialize, Serialize}; use serde_json::Value; use std::collections::HashMap; use std::sync::Arc; use tauri::{AppHandle, Manager, State, Window}; use tracing::{error, info, warn}; use crate::events::EventBus; use crate::plugins::PluginManager; use crate::settings::SettingsManager; use crate::hotkeys::HotkeyManager; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct PluginInfo { pub id: String, pub name: String, pub version: String, pub author: String, pub description: String, pub active: bool, pub has_overlay: bool, pub hotkey: Option, } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct SettingSchema { pub key: String, pub label: String, pub description: String, pub type_: String, pub default: Value, pub value: Value, } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct HotkeyConfig { pub action: String, pub shortcut: String, pub enabled: bool, } pub struct PluginAPI { app_handle: AppHandle, event_bus: Arc, settings: Arc, } impl PluginAPI { pub fn new( app_handle: AppHandle, event_bus: Arc, settings: Arc, ) -> Self { Self { app_handle, event_bus, settings, } } } // Window management commands #[tauri::command] pub fn show_settings_window(app: AppHandle) { if let Some(window) = app.get_window("settings") { window.show().unwrap(); window.set_focus().unwrap(); } else { tauri::WindowBuilder::new( &app, "settings", tauri::WindowUrl::App("/#/settings".into()) ) .title("Settings") .inner_size(900.0, 700.0) .center() .build() .unwrap(); } } #[tauri::command] pub fn show_plugins_window(app: AppHandle) { if let Some(window) = app.get_window("plugins") { window.show().unwrap(); window.set_focus().unwrap(); } else { tauri::WindowBuilder::new( &app, "plugins", tauri::WindowUrl::App("/#/plugins".into()) ) .title("Plugins") .inner_size(1000.0, 800.0) .center() .build() .unwrap(); } } #[tauri::command] pub fn open_overlay(app: AppHandle) { if let Some(window) = app.get_window("overlay") { window.show().unwrap(); window.set_always_on_top(true).unwrap(); } } #[tauri::command] pub fn close_overlay(app: AppHandle) { if let Some(window) = app.get_window("overlay") { window.hide().unwrap(); } } #[tauri::command] pub fn toggle_overlay(app: AppHandle) { if let Some(window) = app.get_window("overlay") { if window.is_visible().unwrap() { window.hide().unwrap(); } else { window.show().unwrap(); window.set_always_on_top(true).unwrap(); } } } // Plugin management #[tauri::command] pub async fn get_plugins( plugin_manager: State<'_, Arc> ) -> Result, String> { Ok(plugin_manager.get_plugins().await) } #[tauri::command] pub async fn activate_plugin( id: String, plugin_manager: State<'_, Arc> ) -> Result<(), String> { plugin_manager.activate(&id).await.map_err(|e| e.to_string()) } #[tauri::command] pub async fn deactivate_plugin( id: String, plugin_manager: State<'_, Arc> ) -> Result<(), String> { plugin_manager.deactivate(&id).await.map_err(|e| e.to_string()) } // Settings #[tauri::command] pub fn get_settings( settings: State<'_, Arc> ) -> Result { settings.get_all().map_err(|e| e.to_string()) } #[tauri::command] pub fn set_settings( key: String, value: Value, settings: State<'_, Arc> ) -> Result<(), String> { settings.set(&key, value).map_err(|e| e.to_string()) } // Hotkeys #[tauri::command] pub fn get_hotkeys( hotkey_manager: State<'_, Arc> ) -> Result, String> { Ok(hotkey_manager.get_hotkeys()) } #[tauri::command] pub fn set_hotkey( action: String, shortcut: String, hotkey_manager: State<'_, Arc> ) -> Result<(), String> { hotkey_manager.set_hotkey(&action, &shortcut).map_err(|e| e.to_string()) } // Notifications #[tauri::command] pub fn show_notification( title: String, body: String, _app: AppHandle ) -> Result<(), String> { use notify_rust::Notification; Notification::new() .summary(&title) .body(&body) .show() .map_err(|e| e.to_string())?; Ok(()) } // Log reader #[tauri::command] pub fn read_log_lines( count: usize, settings: State<'_, Arc> ) -> Result, String> { // Implementation would read from Entropia log file Ok(vec![]) } // Nexus API #[tauri::command] pub async fn search_nexus( query: String, entity_type: Option, limit: Option ) -> Result { crate::nexus::search(&query, entity_type.as_deref(), limit.unwrap_or(20) ).await.map_err(|e| e.to_string()) } #[tauri::command] pub async fn get_item_details( item_id: String ) -> Result { crate::nexus::get_item_details(&item_id).await.map_err(|e| e.to_string()) } // Screen capture and OCR #[tauri::command] pub fn capture_screen( region: Option<(i32, i32, i32, i32)> ) -> Result { // Returns base64 encoded image Err("Not implemented".to_string()) } #[tauri::command] pub fn recognize_text( region: Option<(i32, i32, i32, i32)> ) -> Result { Err("Not implemented".to_string()) } // Clipboard #[tauri::command] pub fn copy_to_clipboard(text: String) -> Result<(), String> { use arboard::Clipboard; let mut clipboard = Clipboard::new().map_err(|e| e.to_string())?; clipboard.set_text(text).map_err(|e| e.to_string()) } #[tauri::command] pub fn paste_from_clipboard() -> Result { use arboard::Clipboard; let mut clipboard = Clipboard::new().map_err(|e| e.to_string())?; clipboard.get_text().map_err(|e| e.to_string()) } // Event system #[tauri::command] pub fn subscribe_event( event_type: String, callback_id: String, event_bus: State<'_, Arc> ) -> Result { let id = event_bus.subscribe(&event_type, callback_id); Ok(id) } #[tauri::command] pub fn unsubscribe_event( subscription_id: String, event_bus: State<'_, Arc> ) { event_bus.unsubscribe(&subscription_id); } #[tauri::command] pub fn publish_event( event_type: String, data: Value, event_bus: State<'_, Arc> ) { event_bus.publish(&event_type, data); } // Plugin data storage #[tauri::command] pub fn save_plugin_data( plugin_id: String, key: String, data: Value, app: AppHandle ) -> Result<(), String> { let path = app.path_resolver() .app_data_dir() .ok_or("Cannot get data dir")? .join("plugins") .join(&plugin_id); std::fs::create_dir_all(&path).map_err(|e| e.to_string())?; let file_path = path.join(format!("{}.json", key)); let json = serde_json::to_string_pretty(&data).map_err(|e| e.to_string())?; std::fs::write(file_path, json).map_err(|e| e.to_string())?; Ok(()) } #[tauri::command] pub fn load_plugin_data( plugin_id: String, key: String, app: AppHandle ) -> Result { let path = app.path_resolver() .app_data_dir() .ok_or("Cannot get data dir")? .join("plugins") .join(&plugin_id) .join(format!("{}.json", key)); if !path.exists() { return Ok(Value::Null); } let json = std::fs::read_to_string(path).map_err(|e| e.to_string())?; let data = serde_json::from_str(&json).map_err(|e| e.to_string())?; Ok(data) } // HTTP Client #[tauri::command] pub async fn http_get( url: String, headers: Option> ) -> Result { let client = reqwest::Client::new(); let mut request = client.get(&url); if let Some(h) = headers { for (key, value) in h { request = request.header(&key, &value); } } let response = request.send().await.map_err(|e| e.to_string())?; let json = response.json::().await.map_err(|e| e.to_string())?; Ok(json) } #[tauri::command] pub async fn http_post( url: String, body: Value, headers: Option> ) -> Result { let client = reqwest::Client::new(); let mut request = client.post(&url).json(&body); if let Some(h) = headers { for (key, value) in h { request = request.header(&key, &value); } } let response = request.send().await.map_err(|e| e.to_string())?; let json = response.json::().await.map_err(|e| e.to_string())?; Ok(json) } // Audio #[tauri::command] pub fn play_sound(sound_path: String) -> Result<(), String> { // Implementation would play audio file Ok(()) } // OCR Commands #[tauri::command] pub fn get_ocr_calibration( settings: State<'_, Arc> ) -> Result { let calibration = settings.get("ocr.calibration") .unwrap_or_else(|_| serde_json::to_value(crate::ocr::OCRCalibration::default()).unwrap()); Ok(calibration) } #[tauri::command] pub fn set_ocr_calibration( calibration: Value, settings: State<'_, Arc> ) -> Result<(), String> { settings.set("ocr.calibration", calibration).map_err(|e| e.to_string()) } #[tauri::command] pub async fn recognize_screen_region( region_name: String, app: AppHandle ) -> Result { // Capture screen and perform OCR on specified region Err("Not yet implemented".to_string()) } #[tauri::command] pub async fn detect_ui_elements( app: AppHandle ) -> Result { // Auto-detect UI elements on screen // Returns detected regions for HP bar, radar, etc. let detected = serde_json::json!({ "hp_bar": { "found": false, "confidence": 0.0 }, "radar": { "found": false, "confidence": 0.0 }, "skill_window": { "found": false, "confidence": 0.0 }, }); Ok(detected) } #[tauri::command] pub fn save_ocr_template( region_name: String, template_data: Vec, app: AppHandle ) -> Result<(), String> { let path = app.path_resolver() .app_data_dir() .ok_or("Cannot get data dir")? .join("ocr_templates") .join(format!("{}.png", region_name)); std::fs::create_dir_all(path.parent().unwrap()).map_err(|e| e.to_string())?; std::fs::write(path, template_data).map_err(|e| e.to_string())?; Ok(()) } #[tauri::command] pub async fn test_ocr_region( region: Value, app: AppHandle ) -> Result { // Test OCR on a specific region Ok(OCRTestResult { text: "Test recognition".to_string(), confidence: 0.95, success: true, }) } #[derive(serde::Serialize)] pub struct OCRTestResult { text: String, confidence: f32, success: bool, }