462 lines
11 KiB
Rust
462 lines
11 KiB
Rust
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<String>,
|
|
}
|
|
|
|
#[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<EventBus>,
|
|
settings: Arc<SettingsManager>,
|
|
}
|
|
|
|
impl PluginAPI {
|
|
pub fn new(
|
|
app_handle: AppHandle,
|
|
event_bus: Arc<EventBus>,
|
|
settings: Arc<SettingsManager>,
|
|
) -> 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<PluginManager>>
|
|
) -> Result<Vec<PluginInfo>, String> {
|
|
Ok(plugin_manager.get_plugins().await)
|
|
}
|
|
|
|
#[tauri::command]
|
|
pub async fn activate_plugin(
|
|
id: String,
|
|
plugin_manager: State<'_, Arc<PluginManager>>
|
|
) -> 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<PluginManager>>
|
|
) -> Result<(), String> {
|
|
plugin_manager.deactivate(&id).await.map_err(|e| e.to_string())
|
|
}
|
|
|
|
// Settings
|
|
#[tauri::command]
|
|
pub fn get_settings(
|
|
settings: State<'_, Arc<SettingsManager>>
|
|
) -> Result<Value, String> {
|
|
settings.get_all().map_err(|e| e.to_string())
|
|
}
|
|
|
|
#[tauri::command]
|
|
pub fn set_settings(
|
|
key: String,
|
|
value: Value,
|
|
settings: State<'_, Arc<SettingsManager>>
|
|
) -> Result<(), String> {
|
|
settings.set(&key, value).map_err(|e| e.to_string())
|
|
}
|
|
|
|
// Hotkeys
|
|
#[tauri::command]
|
|
pub fn get_hotkeys(
|
|
hotkey_manager: State<'_, Arc<HotkeyManager>>
|
|
) -> Result<Vec<HotkeyConfig>, String> {
|
|
Ok(hotkey_manager.get_hotkeys())
|
|
}
|
|
|
|
#[tauri::command]
|
|
pub fn set_hotkey(
|
|
action: String,
|
|
shortcut: String,
|
|
hotkey_manager: State<'_, Arc<HotkeyManager>>
|
|
) -> 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<SettingsManager>>
|
|
) -> Result<Vec<String>, String> {
|
|
// Implementation would read from Entropia log file
|
|
Ok(vec![])
|
|
}
|
|
|
|
// Nexus API
|
|
#[tauri::command]
|
|
pub async fn search_nexus(
|
|
query: String,
|
|
entity_type: Option<String>,
|
|
limit: Option<usize>
|
|
) -> Result<Value, String> {
|
|
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<Value, String> {
|
|
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<String, String> {
|
|
// Returns base64 encoded image
|
|
Err("Not implemented".to_string())
|
|
}
|
|
|
|
#[tauri::command]
|
|
pub fn recognize_text(
|
|
region: Option<(i32, i32, i32, i32)>
|
|
) -> Result<String, String> {
|
|
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<String, String> {
|
|
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<EventBus>>
|
|
) -> Result<String, String> {
|
|
let id = event_bus.subscribe(&event_type, callback_id);
|
|
Ok(id)
|
|
}
|
|
|
|
#[tauri::command]
|
|
pub fn unsubscribe_event(
|
|
subscription_id: String,
|
|
event_bus: State<'_, Arc<EventBus>>
|
|
) {
|
|
event_bus.unsubscribe(&subscription_id);
|
|
}
|
|
|
|
#[tauri::command]
|
|
pub fn publish_event(
|
|
event_type: String,
|
|
data: Value,
|
|
event_bus: State<'_, Arc<EventBus>>
|
|
) {
|
|
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<Value, String> {
|
|
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<HashMap<String, String>>
|
|
) -> Result<Value, String> {
|
|
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::<Value>().await.map_err(|e| e.to_string())?;
|
|
|
|
Ok(json)
|
|
}
|
|
|
|
#[tauri::command]
|
|
pub async fn http_post(
|
|
url: String,
|
|
body: Value,
|
|
headers: Option<HashMap<String, String>>
|
|
) -> Result<Value, String> {
|
|
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::<Value>().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<SettingsManager>>
|
|
) -> Result<Value, String> {
|
|
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<SettingsManager>>
|
|
) -> 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<String, String> {
|
|
// 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<Value, String> {
|
|
// 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<u8>,
|
|
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<OCRTestResult, String> {
|
|
// 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,
|
|
}
|