diff --git a/src/cli/transport.rs b/src/cli/transport.rs index 6afa6e6..7865bbb 100644 --- a/src/cli/transport.rs +++ b/src/cli/transport.rs @@ -126,8 +126,8 @@ fn send_unix(req: Request) -> Result { let sock_path = config::sock_path(); let mut stream = UnixStream::connect(&sock_path) .context("连接 daemon socket 失败")?; - stream.set_read_timeout(Some(Duration::from_secs(30))).ok(); - stream.set_write_timeout(Some(Duration::from_secs(30))).ok(); + stream.set_read_timeout(Some(Duration::from_secs(120))).ok(); + stream.set_write_timeout(Some(Duration::from_secs(120))).ok(); let req_str = serde_json::to_string(&req)? + "\n"; stream.write_all(req_str.as_bytes())?; diff --git a/src/daemon/mod.rs b/src/daemon/mod.rs index 3058a99..2c24e87 100644 --- a/src/daemon/mod.rs +++ b/src/daemon/mod.rs @@ -55,6 +55,7 @@ async fn async_run() -> Result<()> { .filter(|k| { let k = k.replace('\\', "/"); k.contains("message/message_") && k.ends_with(".db") + && !k.contains("_fts") && !k.contains("_resource") }) .cloned() .collect(); @@ -143,7 +144,9 @@ async fn run_watcher( let rows = stmt.query_map([], |row| { Ok(( row.get::<_, String>(0)?, - row.get::<_, Vec>(1).unwrap_or_default(), + row.get::<_, Vec>(1) + .or_else(|_| row.get::<_, String>(1).map(|s| s.into_bytes())) + .unwrap_or_default(), row.get::<_, i64>(2)?, row.get::<_, i64>(3).unwrap_or(0), row.get::<_, String>(4).unwrap_or_default(), diff --git a/src/daemon/query.rs b/src/daemon/query.rs index e8706f6..612b5b1 100644 --- a/src/daemon/query.rs +++ b/src/daemon/query.rs @@ -81,7 +81,7 @@ pub async fn q_sessions(db: &DbCache, names: &Names, limit: usize) -> Result(0)?, row.get::<_, i64>(1).unwrap_or(0), - row.get::<_, Vec>(2).unwrap_or_default(), + get_content_bytes(row, 2), row.get::<_, i64>(3).unwrap_or(0), row.get::<_, i64>(4).unwrap_or(0), row.get::<_, String>(5).unwrap_or_default(), @@ -433,7 +433,7 @@ fn query_messages( row.get::<_, i64>(1)?, row.get::<_, i64>(2)?, row.get::<_, i64>(3)?, - row.get::<_, Vec>(4).unwrap_or_default(), + get_content_bytes(row, 4), row.get::<_, i64>(5).unwrap_or(0), )) })? @@ -497,7 +497,7 @@ fn search_in_table( row.get::<_, i64>(1)?, row.get::<_, i64>(2)?, row.get::<_, i64>(3)?, - row.get::<_, Vec>(4).unwrap_or_default(), + get_content_bytes(row, 4), row.get::<_, i64>(5).unwrap_or(0), )) })? @@ -561,6 +561,17 @@ fn sender_label( String::new() } +/// 读取消息内容列(兼容 TEXT 和 BLOB 两种存储类型) +/// +/// SQLite 中 message_content 在未压缩时为 TEXT,zstd 压缩后为 BLOB。 +/// rusqlite 的 Vec FromSql 只接受 BLOB,读 TEXT 会静默返回空。 +fn get_content_bytes(row: &rusqlite::Row<'_>, idx: usize) -> Vec { + // 先尝试 BLOB,再 fallback 到 TEXT→bytes + row.get::<_, Vec>(idx) + .or_else(|_| row.get::<_, String>(idx).map(|s| s.into_bytes())) + .unwrap_or_default() +} + fn decompress_message(data: &[u8], ct: i64) -> String { if ct == 4 && !data.is_empty() { // zstd 压缩