初始化web服务功能

This commit is contained in:
xintaofei
2026-03-25 14:26:26 +08:00
parent ae70f17d2e
commit ac09d3db9e
99 changed files with 3253 additions and 304 deletions

View File

@@ -3,7 +3,7 @@ use std::fs;
use std::path::{Path, PathBuf};
use serde::{Deserialize, Serialize};
use tauri::{Emitter, State};
use tauri::State;
use crate::acp::binary_cache;
use crate::acp::error::AcpError;
@@ -32,7 +32,8 @@ fn emit_acp_agents_updated(
reason: &'static str,
agent_type: Option<AgentType>,
) {
let _ = app.emit(
crate::web::event_bridge::emit_event(
app,
ACP_AGENTS_UPDATED_EVENT,
AcpAgentsUpdatedEventPayload { reason, agent_type },
);

View File

@@ -459,6 +459,60 @@ fn compute_stats(all_conversations: &[ConversationSummary]) -> AgentStats {
}
}
// ── Public helpers for the embedded web server ──
pub async fn list_conversations_for_web(
agent_type: Option<AgentType>,
search: Option<String>,
sort_by: Option<String>,
folder_path: Option<String>,
) -> Result<Vec<ConversationSummary>, AppCommandError> {
tokio::task::spawn_blocking(move || list_conversations_sync(agent_type, search, sort_by, folder_path))
.await
.map_err(|e| {
AppCommandError::task_execution_failed("Failed to list conversations")
.with_detail(e.to_string())
})
}
pub async fn list_folders_for_web() -> Result<Vec<FolderInfo>, AppCommandError> {
tokio::task::spawn_blocking(move || {
let all = list_conversations_sync(None, None, None, None);
compute_folders(&all)
})
.await
.map_err(|e| {
AppCommandError::task_execution_failed("Failed to list folders").with_detail(e.to_string())
})
}
pub async fn get_stats_for_web() -> Result<AgentStats, AppCommandError> {
tokio::task::spawn_blocking(move || {
let all = list_conversations_sync(None, None, None, None);
compute_stats(&all)
})
.await
.map_err(|e| {
AppCommandError::task_execution_failed("Failed to compute stats")
.with_detail(e.to_string())
})
}
pub async fn get_sidebar_data_for_web() -> Result<SidebarData, AppCommandError> {
tokio::task::spawn_blocking(move || {
let all = list_conversations_sync(None, None, None, None);
SidebarData {
folders: compute_folders(&all),
stats: compute_stats(&all),
}
})
.await
.map_err(|e| {
AppCommandError::task_execution_failed("Failed to build sidebar data")
.with_detail(e.to_string())
})
}
fn parse_error_to_app_error(error: ParseError) -> AppCommandError {
match error {
ParseError::ConversationNotFound(id) => {

View File

@@ -10,7 +10,7 @@ use std::time::{Duration, Instant, UNIX_EPOCH};
use base64::Engine as _;
use notify::{EventKind, RecommendedWatcher, RecursiveMode, Watcher};
use serde::Serialize;
use tauri::Emitter;
use tokio::sync::Semaphore;
use walkdir::WalkDir;
@@ -985,7 +985,8 @@ pub async fn git_push(
.strip_prefix("push-")
.and_then(|value| value.parse::<i32>().ok())
{
let _ = app.emit(
crate::web::event_bridge::emit_event(
&app,
"folder://git-push-succeeded",
GitPushSucceededEvent {
folder_id,
@@ -1552,7 +1553,8 @@ pub async fn git_commit(
.strip_prefix("commit-")
.and_then(|value| value.parse::<i32>().ok())
{
let _ = app.emit(
crate::web::event_bridge::emit_event(
&app,
"folder://git-commit-succeeded",
GitCommitSucceededEvent {
folder_id,
@@ -2384,7 +2386,7 @@ impl WatchEventBatch {
full_reload: self.overflowed,
};
let _ = app.emit("folder://file-tree-changed", payload);
crate::web::event_bridge::emit_event(app, "folder://file-tree-changed", payload);
}
}

View File

@@ -1,5 +1,5 @@
use sea_orm::DatabaseConnection;
use tauri::{Emitter, State};
use tauri::State;
use crate::app_error::AppCommandError;
use crate::db::service::app_metadata_service;
@@ -130,7 +130,7 @@ pub async fn update_system_language_settings(
.await
.map_err(AppCommandError::from)?;
let _ = app.emit(LANGUAGE_SETTINGS_UPDATED_EVENT, &settings);
crate::web::event_bridge::emit_event(&app, LANGUAGE_SETTINGS_UPDATED_EVENT, settings.clone());
Ok(settings)
}

View File

@@ -1,7 +1,7 @@
use std::collections::{HashMap, HashSet};
use std::sync::Mutex;
use tauri::{AppHandle, Emitter, Manager, WebviewUrl, WebviewWindowBuilder};
use tauri::{AppHandle, Manager, WebviewUrl, WebviewWindowBuilder};
use crate::app_error::AppCommandError;
use crate::db::AppDatabase;
@@ -534,7 +534,8 @@ pub async fn cleanup_dangling_merge(app: &AppHandle, merge_window_label: &str) {
.output()
.await;
let _ = app.emit(
crate::web::event_bridge::emit_event(
app,
"folder://merge-aborted",
serde_json::json!({ "folder_id": folder_id }),
);