feat: 新增聊天消息关键词搜索功能

- wcdbCore: 绑定 wcdb_search_messages DLL 函数,添加 searchMessages 方法
- wcdbWorker: 添加 searchMessages case
- wcdbService: 添加 searchMessages 代理方法
- chatService: 添加 searchMessages,结果解析为 Message 对象
- main: 注册 chat:searchMessages IPC handler
This commit is contained in:
hicccc77
2026-03-15 19:08:52 +08:00
parent 5deacf45cb
commit 2f25fd1239
5 changed files with 63 additions and 0 deletions

View File

@@ -1563,6 +1563,10 @@ function registerIpcHandlers() {
return chatService.getMessageById(sessionId, localId)
})
ipcMain.handle('chat:searchMessages', async (_, keyword: string, sessionId?: string, limit?: number, offset?: number, beginTimestamp?: number, endTimestamp?: number) => {
return chatService.searchMessages(keyword, sessionId, limit, offset, beginTimestamp, endTimestamp)
})
ipcMain.handle('chat:execQuery', async (_, kind: string, path: string | null, sql: string) => {
return chatService.execQuery(kind, path, sql)
})

View File

@@ -6580,6 +6580,20 @@ class ChatService {
}
}
async searchMessages(keyword: string, sessionId?: string, limit?: number, offset?: number, beginTimestamp?: number, endTimestamp?: number): Promise<{ success: boolean; messages?: Message[]; error?: string }> {
try {
const result = await wcdbService.searchMessages(keyword, sessionId, limit, offset, beginTimestamp, endTimestamp)
if (!result.success || !result.messages) {
return { success: false, error: result.error || '搜索失败' }
}
const messages = result.messages.map((row: any) => this.parseMessage(row)).filter(Boolean) as Message[]
return { success: true, messages }
} catch (e) {
console.error('ChatService: searchMessages 失败:', e)
return { success: false, error: String(e) }
}
}
private parseMessage(row: any): Message {
const rawContent = this.decodeMessageContent(
this.getRowField(row, [

View File

@@ -106,6 +106,7 @@ export class WcdbCore {
private wcdbGetEmoticonCdnUrl: any = null
private wcdbGetDbStatus: any = null
private wcdbGetVoiceData: any = null
private wcdbSearchMessages: any = null
private wcdbGetSnsTimeline: any = null
private wcdbGetSnsAnnualStats: any = null
private wcdbInstallSnsBlockDeleteTrigger: any = null
@@ -817,6 +818,13 @@ export class WcdbCore {
this.wcdbGetVoiceData = null
}
// wcdb_status wcdb_search_messages(wcdb_handle handle, const char* session_id, const char* keyword, int32_t limit, int32_t offset, int32_t begin_timestamp, int32_t end_timestamp, char** out_json)
try {
this.wcdbSearchMessages = this.lib.func('int32 wcdb_search_messages(int64 handle, const char* sessionId, const char* keyword, int32 limit, int32 offset, int32 beginTimestamp, int32 endTimestamp, _Out_ void** outJson)')
} catch {
this.wcdbSearchMessages = null
}
// wcdb_status wcdb_get_sns_timeline(wcdb_handle handle, int32_t limit, int32_t offset, const char* username, const char* keyword, int32_t start_time, int32_t end_time, char** out_json)
try {
this.wcdbGetSnsTimeline = this.lib.func('int32 wcdb_get_sns_timeline(int64 handle, int32 limit, int32 offset, const char* username, const char* keyword, int32 startTime, int32 endTime, _Out_ void** outJson)')
@@ -2279,6 +2287,36 @@ export class WcdbCore {
})
}
async searchMessages(keyword: string, sessionId?: string, limit?: number, offset?: number, beginTimestamp?: number, endTimestamp?: number): Promise<{ success: boolean; messages?: any[]; error?: string }> {
if (!this.ensureReady()) return { success: false, error: 'WCDB 未连接' }
if (!this.wcdbSearchMessages) return { success: false, error: '当前 DLL 版本不支持搜索消息' }
try {
const handle = this.handle
await new Promise(resolve => setImmediate(resolve))
if (handle === null || this.handle !== handle) return { success: false, error: '连接已断开' }
const outPtr = [null as any]
const result = this.wcdbSearchMessages(
handle,
sessionId || '',
keyword,
limit || 50,
offset || 0,
beginTimestamp || 0,
endTimestamp || 0,
outPtr
)
if (result !== 0 || !outPtr[0]) {
return { success: false, error: `搜索消息失败: ${result}` }
}
const jsonStr = this.decodeJsonPtr(outPtr[0])
if (!jsonStr) return { success: false, error: '解析搜索结果失败' }
const messages = JSON.parse(jsonStr)
return { success: true, messages }
} catch (e) {
return { success: false, error: String(e) }
}
}
async getSnsTimeline(limit: number, offset: number, usernames?: string[], keyword?: string, startTime?: number, endTime?: number): Promise<{ success: boolean; timeline?: any[]; error?: string }> {
if (!this.ensureReady()) return { success: false, error: 'WCDB 未连接' }
if (!this.wcdbGetSnsTimeline) return { success: false, error: '当前 DLL 版本不支持获取朋友圈' }

View File

@@ -406,6 +406,10 @@ export class WcdbService {
return this.callWorker('getMessageById', { sessionId, localId })
}
async searchMessages(keyword: string, sessionId?: string, limit?: number, offset?: number, beginTimestamp?: number, endTimestamp?: number): Promise<{ success: boolean; messages?: any[]; error?: string }> {
return this.callWorker('searchMessages', { keyword, sessionId, limit, offset, beginTimestamp, endTimestamp })
}
/**
* 获取语音数据
*/

View File

@@ -140,6 +140,9 @@ if (parentPort) {
case 'getMessageById':
result = await core.getMessageById(payload.sessionId, payload.localId)
break
case 'searchMessages':
result = await core.searchMessages(payload.keyword, payload.sessionId, payload.limit, payload.offset, payload.beginTimestamp, payload.endTimestamp)
break
case 'getVoiceData':
result = await core.getVoiceData(payload.sessionId, payload.createTime, payload.candidates, payload.localId, payload.svrId)
if (!result.success) {