use serde::{Serialize, Deserialize}; use std::collections::HashMap; use std::sync::{Arc, Mutex}; use ucxl_core::*; // Helper functions for creating standard responses fn create_error_response(code: UCXLErrorCode, path: &str, request_id: Option<&str>) -> CoreToUiResponse { let error = UCXLErrorBuilder::new(code) .source("ucxl-browser") .path(path) .request_id(request_id.unwrap_or("unknown")) .build(); CoreToUiResponse::Error(error) } fn create_success_response(code: UCXLResponseCode, data: Option, request_id: Option<&str>) -> CoreToUiResponse where T: serde::Serialize { let response = UCXLResponseBuilder::new(code) .data(serde_json::to_value(data).unwrap_or(serde_json::Value::Null)) .request_id(request_id.unwrap_or("unknown")) .build(); CoreToUiResponse::Success(response) } fn create_envelope_error(code: UCXLErrorCode, envelope_id: &str, path: &str) -> CoreToUiResponse { let error = UCXLErrorBuilder::new(code) .field("envelope_id", envelope_id.into()) .source("ucxl-browser") .path(path) .build(); CoreToUiResponse::Error(error) } fn create_uri_error(uri: &str, path: &str) -> CoreToUiResponse { let error = UCXLErrorBuilder::new(UCXLErrorCode::InvalidAddress) .field("address", uri.into()) .expected_format("ucxl://:@:[//]") .source("ucxl-browser") .path(path) .cause("parse_error") .build(); CoreToUiResponse::Error(error) } // Global state for the application #[derive(Clone)] pub struct AppState { pub store: Arc>, pub dht_store: Arc>>, pub bzzz_gateway: Arc>>, pub temporal_engine: Arc>>>, pub command_executor: Arc>, } impl AppState { pub fn new() -> Self { let store = InMemoryEnvelopeStore::new(); // Initialize BZZZ Gateway with DHT let bzzz_config = BZZZConfig::default(); let bzzz_gateway = BZZZGateway::new(bzzz_config).unwrap(); AppState { store: Arc::new(Mutex::new(store)), dht_store: Arc::new(Mutex::new(None)), bzzz_gateway: Arc::new(Mutex::new(Some(bzzz_gateway))), temporal_engine: Arc::new(Mutex::new(None)), command_executor: Arc::new(Mutex::new(UCXLCommandExecutor::new())), } } pub async fn initialize_dht(&self) -> std::result::Result<(), String> { // Start BZZZ Gateway let mut gateway_clone = { let gateway_opt = self.bzzz_gateway.lock().map_err(|e| e.to_string())?; gateway_opt.clone() }; if let Some(ref mut gateway) = gateway_clone.as_mut() { gateway.start().await.map_err(|e| e.to_string())?; // Update the state with the started gateway if let Ok(mut gateway_opt) = self.bzzz_gateway.lock() { *gateway_opt = gateway_clone; } } Ok(()) } } #[derive(Serialize, Deserialize, Debug, Clone)] pub enum UiToCoreCommand { // Basic envelope operations GetEnvelope { envelope_id: String }, GetEnvelopeByUri { uri: String }, StoreEnvelope { envelope: EnvelopeData }, DeleteEnvelope { envelope_id: String, soft_delete: bool }, // UCXL protocol commands ExecuteUCXLGet { uri: String, version: Option, at_time: Option }, ExecuteUCXLPut { uri: String, content: String, content_type: String, metadata: HashMap }, ExecuteUCXLPost { uri: String, markdown_content: String, author: Option, title: Option }, ExecuteUCXLAnnounce { uri: String, envelope_id: String, announcement_data: HashMap }, ExecuteUCXLDelete { uri: String, version: Option, soft_delete: bool }, // Temporal navigation commands GetTemporalState { doc_id: String, version_id: Option, at_time: Option, branch_name: Option }, GetTimeline { doc_id: String }, DiffVersions { doc_id: String, from_version: String, to_version: String }, // Search commands SearchEnvelopes { query: SearchQueryData }, // Store statistics GetStoreStats, // DHT and BZZZ operations InitializeDHT, GetNetworkStatus, GetBZZZStats, StoreToDHT { envelope: EnvelopeData }, RetrieveFromDHT { envelope_id: String }, GetPeerList, } #[derive(Serialize, Deserialize, Debug, Clone)] pub struct EnvelopeData { pub ucxl_uri: String, pub content: String, pub content_type: String, pub author: Option, pub title: Option, pub tags: Vec, } #[derive(Serialize, Deserialize, Debug, Clone)] pub struct SearchQueryData { pub text: Option, pub tags: Vec, pub author: Option, pub content_type: Option, pub limit: Option, pub offset: Option, } #[derive(Serialize, Deserialize, Debug, Clone)] pub enum CoreToUiResponse { // Standardized UCXL responses Success(UCXLSuccessResponse), Error(UCXLErrorResponse), // Legacy responses for backward compatibility Envelope(Envelope), EnvelopeList(Vec), // UCXL command responses UCXLResponse(UCXLResponse), // Temporal responses TemporalState(TemporalState), Timeline(TimelineView), VersionDiff(VersionDiff), // Store info StoreStats(StoreStats), // DHT and BZZZ responses NetworkStatus(NetworkStatus), BZZZStats(BZZZStats), PeerList(Vec), } // Tauri command handlers #[tauri::command] pub async fn handle_command(command: UiToCoreCommand, state: tauri::State<'_, AppState>) -> std::result::Result { match command { UiToCoreCommand::GetEnvelope { envelope_id } => { // Clone the store for async usage let result = { let store = match state.store.lock() { Ok(store) => store.clone(), Err(e) => return Ok(CoreToUiResponse::Error { error: "Failed to acquire store lock".to_string(), details: Some(e.to_string()), }), }; store.retrieve(&envelope_id).await }; match result { Ok(Some(envelope)) => Ok(CoreToUiResponse::Envelope(envelope)), Ok(None) => Ok(CoreToUiResponse::Error { error: "Envelope not found".to_string(), details: Some(envelope_id), }), Err(e) => Ok(CoreToUiResponse::Error { error: e.to_string(), details: None, }), } } UiToCoreCommand::GetEnvelopeByUri { uri } => { let ucxl_uri = match UCXLUri::new(&uri) { Ok(uri) => uri, Err(_) => return Ok(create_uri_error(&uri, "/envelope/by-uri")), }; let result = { let store = match state.store.lock() { Ok(store) => store.clone(), Err(e) => return Ok(CoreToUiResponse::Error { error: "Failed to acquire store lock".to_string(), details: Some(e.to_string()), }), }; store.retrieve_by_uri(&ucxl_uri).await }; match result { Ok(Some(envelope)) => Ok(CoreToUiResponse::Envelope(envelope)), Ok(None) => Ok(create_envelope_error(UCXLErrorCode::NotFound, &uri, "/envelope/by-uri")), Err(e) => Ok(create_error_response( UCXLErrorCode::InternalError, "/envelope/by-uri", None )), } } UiToCoreCommand::StoreEnvelope { envelope } => { let ucxl_uri = match UCXLUri::new(&envelope.ucxl_uri) { Ok(uri) => uri, Err(e) => return Ok(CoreToUiResponse::Error { error: "Invalid UCXL URI".to_string(), details: Some(e.to_string()), }), }; let metadata = EnvelopeMetadata { author: envelope.author, title: envelope.title, tags: envelope.tags, source: Some("ucxl-browser".to_string()), context_data: HashMap::new(), }; let new_envelope = match Envelope::new(ucxl_uri, envelope.content, envelope.content_type, metadata) { Ok(env) => env, Err(e) => return Ok(CoreToUiResponse::Error { error: "Failed to create envelope".to_string(), details: Some(e.to_string()), }), }; let envelope_id = new_envelope.id.clone(); let result = { let store = match state.store.lock() { Ok(store) => store.clone(), Err(e) => return Ok(CoreToUiResponse::Error { error: "Failed to acquire store lock".to_string(), details: Some(e.to_string()), }), }; store.store(&new_envelope).await }; match result { Ok(()) => Ok(CoreToUiResponse::Success { message: "Envelope stored successfully".to_string(), data: Some(serde_json::json!({ "envelope_id": envelope_id })), }), Err(e) => Ok(CoreToUiResponse::Error { error: e.to_string(), details: None, }), } } UiToCoreCommand::ExecuteUCXLGet { uri, version, at_time } => { let ucxl_uri = match UCXLUri::new(&uri) { Ok(uri) => uri, Err(e) => return Ok(CoreToUiResponse::Error { error: "Invalid UCXL URI".to_string(), details: Some(e.to_string()), }), }; let parsed_at_time = if let Some(at_time_str) = at_time { match chrono::DateTime::parse_from_rfc3339(&at_time_str) { Ok(dt) => Some(dt.with_timezone(&chrono::Utc)), Err(e) => return Ok(CoreToUiResponse::Error { error: "Invalid date format".to_string(), details: Some(e.to_string()), }), } } else { None }; let get_cmd = GetCommand { ucxl_uri, version, at_time: parsed_at_time, }; let result = { let executor = match state.command_executor.lock() { Ok(exec) => exec.clone(), Err(e) => return Ok(CoreToUiResponse::Error { error: "Failed to acquire executor lock".to_string(), details: Some(e.to_string()), }), }; executor.execute(UCXLCommand::Get(get_cmd)).await }; match result { Ok(response) => Ok(CoreToUiResponse::UCXLResponse(response)), Err(e) => Ok(CoreToUiResponse::Error { error: e.to_string(), details: None, }), } } UiToCoreCommand::ExecuteUCXLPost { uri, markdown_content, author, title } => { let ucxl_uri = match UCXLUri::new(&uri) { Ok(uri) => uri, Err(e) => return Ok(CoreToUiResponse::Error { error: "Invalid UCXL URI".to_string(), details: Some(e.to_string()), }), }; let doc_id = ucxl_uri.path.clone(); let markdown_context = MarkdownContext::new(doc_id, markdown_content, author, title); let post_cmd = PostCommand { ucxl_uri, markdown_context, }; let result = { let executor = match state.command_executor.lock() { Ok(exec) => exec.clone(), Err(e) => return Ok(CoreToUiResponse::Error { error: "Failed to acquire executor lock".to_string(), details: Some(e.to_string()), }), }; executor.execute(UCXLCommand::Post(post_cmd)).await }; match result { Ok(response) => Ok(CoreToUiResponse::UCXLResponse(response)), Err(e) => Ok(CoreToUiResponse::Error { error: e.to_string(), details: None, }), } } UiToCoreCommand::SearchEnvelopes { query } => { let search_query = SearchQuery { text: query.text, tags: query.tags, author: query.author, content_type: query.content_type, date_range: None, // TODO: Add date range support in UI limit: query.limit, offset: query.offset, }; let result = { let store = match state.store.lock() { Ok(store) => store.clone(), Err(e) => return Ok(CoreToUiResponse::Error { error: "Failed to acquire store lock".to_string(), details: Some(e.to_string()), }), }; store.search(&search_query).await }; match result { Ok(envelopes) => Ok(CoreToUiResponse::EnvelopeList(envelopes)), Err(e) => Ok(CoreToUiResponse::Error { error: e.to_string(), details: None, }), } } UiToCoreCommand::GetStoreStats => { let stats = { let store = match state.store.lock() { Ok(store) => store, Err(e) => return Ok(CoreToUiResponse::Error { error: "Failed to acquire store lock".to_string(), details: Some(e.to_string()), }), }; store.get_stats() }; Ok(CoreToUiResponse::StoreStats(stats)) } UiToCoreCommand::InitializeDHT => { match state.initialize_dht().await { Ok(()) => Ok(CoreToUiResponse::Success { message: "DHT network initialized successfully".to_string(), data: None, }), Err(e) => Ok(CoreToUiResponse::Error { error: "Failed to initialize DHT".to_string(), details: Some(e), }), } } UiToCoreCommand::GetNetworkStatus => { let gateway_clone = { let gateway_opt = match state.bzzz_gateway.lock() { Ok(gateway) => gateway, Err(e) => return Ok(CoreToUiResponse::Error { error: "Failed to acquire gateway lock".to_string(), details: Some(e.to_string()), }), }; gateway_opt.clone() }; let network_status = if let Some(gateway) = gateway_clone { gateway.get_network_status().await } else { return Ok(CoreToUiResponse::Error { error: "DHT network not initialized".to_string(), details: Some("Call InitializeDHT first".to_string()), }); }; Ok(CoreToUiResponse::NetworkStatus(network_status)) } UiToCoreCommand::GetBZZZStats => { let gateway_clone = { let gateway_opt = match state.bzzz_gateway.lock() { Ok(gateway) => gateway, Err(e) => return Ok(CoreToUiResponse::Error { error: "Failed to acquire gateway lock".to_string(), details: Some(e.to_string()), }), }; gateway_opt.clone() }; let bzzz_stats = if let Some(gateway) = gateway_clone { gateway.get_gateway_stats() } else { return Ok(create_error_response( UCXLErrorCode::ServiceUnavailable, "/bzzz/stats", None )); }; Ok(CoreToUiResponse::BZZZStats(bzzz_stats)) } UiToCoreCommand::StoreToDHT { envelope } => { let ucxl_uri = match UCXLUri::new(&envelope.ucxl_uri) { Ok(uri) => uri, Err(_) => return Ok(create_uri_error(&envelope.ucxl_uri, "/dht/store")), }; let metadata = EnvelopeMetadata { author: envelope.author, title: envelope.title, tags: envelope.tags, source: Some("ucxl-browser".to_string()), context_data: HashMap::new(), }; let new_envelope = match Envelope::new(ucxl_uri, envelope.content, envelope.content_type, metadata) { Ok(env) => env, Err(e) => return Ok(CoreToUiResponse::Error { error: "Failed to create envelope".to_string(), details: Some(e.to_string()), }), }; let gateway_clone = { let gateway_opt = match state.bzzz_gateway.lock() { Ok(gateway) => gateway, Err(e) => return Ok(CoreToUiResponse::Error { error: "Failed to acquire gateway lock".to_string(), details: Some(e.to_string()), }), }; gateway_opt.clone() }; let envelope_id = if let Some(gateway) = gateway_clone { match gateway.store_context(&new_envelope).await { Ok(id) => id, Err(e) => return Ok(CoreToUiResponse::Error { error: "Failed to store to DHT".to_string(), details: Some(e.to_string()), }), } } else { return Ok(CoreToUiResponse::Error { error: "DHT network not initialized".to_string(), details: Some("Call InitializeDHT first".to_string()), }); }; Ok(CoreToUiResponse::Success { message: "Content stored to DHT successfully".to_string(), data: Some(serde_json::json!({ "envelope_id": envelope_id })), }) } UiToCoreCommand::RetrieveFromDHT { envelope_id } => { let gateway_clone = { let gateway_opt = match state.bzzz_gateway.lock() { Ok(gateway) => gateway, Err(e) => return Ok(CoreToUiResponse::Error { error: "Failed to acquire gateway lock".to_string(), details: Some(e.to_string()), }), }; gateway_opt.clone() }; let envelope = if let Some(gateway) = gateway_clone { match gateway.retrieve_context(&envelope_id).await { Ok(Some(env)) => env, Ok(None) => return Ok(CoreToUiResponse::Error { error: "Envelope not found in DHT".to_string(), details: Some(envelope_id), }), Err(e) => return Ok(CoreToUiResponse::Error { error: "Failed to retrieve from DHT".to_string(), details: Some(e.to_string()), }), } } else { return Ok(CoreToUiResponse::Error { error: "DHT network not initialized".to_string(), details: Some("Call InitializeDHT first".to_string()), }); }; Ok(CoreToUiResponse::Envelope(envelope)) } UiToCoreCommand::GetPeerList => { // Mock peer list for now let peers = vec![ BZZZPeer { peer_id: "bzzz-peer-1".to_string(), ip_address: "192.168.1.100".to_string(), port: 8080, last_seen: chrono::Utc::now(), capabilities: PeerCapabilities { supports_ucxl: true, supports_dht: true, supports_temporal: true, storage_capacity: 1_000_000_000, api_version: "v2.0".to_string(), }, health_score: 0.95, latency_ms: Some(15), }, BZZZPeer { peer_id: "bzzz-peer-2".to_string(), ip_address: "192.168.1.101".to_string(), port: 8080, last_seen: chrono::Utc::now(), capabilities: PeerCapabilities { supports_ucxl: true, supports_dht: true, supports_temporal: false, storage_capacity: 500_000_000, api_version: "v2.0".to_string(), }, health_score: 0.88, latency_ms: Some(22), }, ]; Ok(CoreToUiResponse::PeerList(peers)) } // TODO: Implement remaining commands _ => Ok(CoreToUiResponse::Error { error: "Command not implemented yet".to_string(), details: Some(format!("{:?}", command)), }), } }