fix: 优化数据库启动与设置页响应性能

(cherry picked from commit f6614548b0e742bc703b2a5aaa5060720985ed27)
This commit is contained in:
电摇小子
2026-08-03 10:04:19 +08:00
committed by Wxw-Gu
parent 90bf1aed90
commit ee7dc11e92
14 changed files with 202 additions and 94 deletions
+5 -1
View File
@@ -486,6 +486,7 @@ app.whenReady().then(async () => {
if (dbInitInFlight) return dbInitInFlight
dbInitInFlight = (async () => {
const startedAt = Date.now()
try {
if (wcdbBootstrapPromise) await wcdbBootstrapPromise
const trimmedKey = String(key || '').trim()
@@ -511,7 +512,7 @@ app.whenReady().then(async () => {
}
chat.setChatDb(nextWechatDb)
const wcdb4Client = nextWechatDb.getWcdb4Client()
const sessions = await wcdb4Client.getSessionsAsync()
const sessions = await wcdb4Client.getSessionsAsync({ hydrateDisplayNames: false })
configureRecallProtection(wcdb4Client, resolvedRoot, settings.recallProtectionEnabled)
voiceService = new VoiceService(wcdb4Client)
stickerService = new StickerService(wcdb4Client)
@@ -530,6 +531,9 @@ app.whenReady().then(async () => {
.catch((error) => console.warn('[WCDB4] message cursor warmup failed:', error))
}
imageDecryptService = null
console.log(
`[WCDB4] db:init ready sessions=${sessions.length} monitoring=${monitoring} cost=${Date.now() - startedAt}ms`
)
return { success: true, monitoring }
} catch (error) {
console.error('Failed to init DB:', error)
+1 -1
View File
@@ -174,7 +174,7 @@ export function listContacts(filter?: string): FormattedContact[] {
export async function listContactsAsync(filter?: string): Promise<FormattedContact[]> {
if (!dbRef) return []
await dbRef.getWcdb4Client().getSessionsAsync()
await dbRef.getWcdb4Client().getSessionsAsync({ hydrateDisplayNames: false })
return listContacts(filter)
}
+53 -16
View File
@@ -32,6 +32,10 @@ export interface Wcdb4MessageQueryOptions {
limit?: number
}
export interface Wcdb4SessionQueryOptions {
hydrateDisplayNames?: boolean
}
type Wcdb4MessageStore = {
tableName: string
dbPath: string
@@ -242,6 +246,8 @@ export class Wcdb4Client {
private cachedSessions: Wcdb4Session[] | null = null
private cachedChatTables: { name: string; db_number: string }[] | null = null
private sessionsInFlight: Promise<Wcdb4Session[]> | null = null
private sessionDisplayNamesInFlight: Promise<void> | null = null
private sessionDisplayNamesHydrated = false
private sessionCacheGeneration = 0
private wcdbShutdown: (() => number) | null = null
@@ -558,6 +564,7 @@ export class Wcdb4Client {
this.handle = null
this.cachedSessions = null
this.sessionDisplayNamesHydrated = false
this.displayNameCache.clear()
this.avatarCache.clear()
this.groupNicknameCache.clear()
@@ -722,13 +729,22 @@ export class Wcdb4Client {
...session,
nickname: this.displayNameCache.get(session.username) || session.nickname || session.username
}))
this.sessionDisplayNamesHydrated = true
return this.cachedSessions
}
async getSessionsAsync(): Promise<Wcdb4Session[]> {
if (this.cachedSessions) return this.cachedSessions
if (this.sessionsInFlight) return this.sessionsInFlight
async getSessionsAsync(options: Wcdb4SessionQueryOptions = {}): Promise<Wcdb4Session[]> {
const hydrateDisplayNames = options.hydrateDisplayNames !== false
if (this.cachedSessions) {
if (hydrateDisplayNames) await this.ensureSessionDisplayNamesAsync()
return this.cachedSessions
}
if (this.sessionsInFlight) {
await this.sessionsInFlight
if (hydrateDisplayNames) await this.ensureSessionDisplayNamesAsync()
return this.cachedSessions || []
}
if (!this.wcdbGetSessions) return []
const generation = this.sessionCacheGeneration
@@ -739,25 +755,17 @@ export class Wcdb4Client {
const sessions = (Array.isArray(rows) ? rows : [])
.map((row) => this.normalizeSession(row))
.filter((session) => session.username)
await this.hydrateDisplayNamesAsync(
sessions
.filter((session) => this.shouldHydrateSessionDisplayName(session))
.map((session) => session.username)
)
const hydrated = sessions.map((session) => ({
...session,
nickname:
this.displayNameCache.get(session.username) || session.nickname || session.username
}))
if (generation === this.sessionCacheGeneration) this.cachedSessions = hydrated
return hydrated
if (generation === this.sessionCacheGeneration) this.cachedSessions = sessions
return sessions
})()
this.sessionsInFlight = request
try {
return await request
await request
} finally {
if (this.sessionsInFlight === request) this.sessionsInFlight = null
}
if (hydrateDisplayNames) await this.ensureSessionDisplayNamesAsync()
return this.cachedSessions || []
}
invalidateSessionCache(): void {
@@ -765,6 +773,7 @@ export class Wcdb4Client {
this.cachedSessions = null
this.cachedChatTables = null
this.sessionsInFlight = null
this.sessionDisplayNamesHydrated = false
}
getChatTables(): { name: string; db_number: string }[] {
@@ -2214,6 +2223,34 @@ export class Wcdb4Client {
}
}
private async ensureSessionDisplayNamesAsync(): Promise<void> {
if (this.sessionDisplayNamesHydrated || !this.cachedSessions) return
if (this.sessionDisplayNamesInFlight) return this.sessionDisplayNamesInFlight
const generation = this.sessionCacheGeneration
const sessions = this.cachedSessions
const request = (async (): Promise<void> => {
await this.hydrateDisplayNamesAsync(
sessions
.filter((session) => this.shouldHydrateSessionDisplayName(session))
.map((session) => session.username)
)
if (generation !== this.sessionCacheGeneration || this.cachedSessions !== sessions) return
this.cachedSessions = sessions.map((session) => ({
...session,
nickname:
this.displayNameCache.get(session.username) || session.nickname || session.username
}))
this.sessionDisplayNamesHydrated = true
})()
this.sessionDisplayNamesInFlight = request
try {
await request
} finally {
if (this.sessionDisplayNamesInFlight === request) this.sessionDisplayNamesInFlight = null
}
}
private hydrateAvatarUrls(usernames: string[]): void {
const missing = this.uniq(usernames).filter((username) => !this.avatarCache.has(username))
if (missing.length === 0) return