104 lines
2.8 KiB
TypeScript
104 lines
2.8 KiB
TypeScript
import { Database } from 'bun:sqlite';
|
|
import fs from 'fs';
|
|
import path from 'path';
|
|
|
|
import { ASSISTANT_NAME, DATA_DIR, STORE_DIR } from '../config.js';
|
|
import { logger } from '../logger.js';
|
|
import type { RegisteredGroup } from '../types.js';
|
|
import { readJsonFile } from '../utils.js';
|
|
import { applyBaseSchema } from './base-schema.js';
|
|
import { applySchemaMigrations } from './schema.js';
|
|
|
|
export interface JsonStateMigrationHooks {
|
|
setRouterState(key: string, value: string): void;
|
|
setSession(groupFolder: string, sessionId: string): void;
|
|
writeLegacyRegisteredGroupAndSyncRoomSettings(
|
|
jid: string,
|
|
group: RegisteredGroup,
|
|
): void;
|
|
}
|
|
|
|
export function initializeDatabaseSchema(database: Database): void {
|
|
applyBaseSchema(database);
|
|
applySchemaMigrations(database, {
|
|
assistantName: ASSISTANT_NAME,
|
|
});
|
|
}
|
|
|
|
export function openPersistentDatabase(): Database {
|
|
const dbPath = path.join(STORE_DIR, 'messages.db');
|
|
fs.mkdirSync(path.dirname(dbPath), { recursive: true });
|
|
|
|
const database = new Database(dbPath);
|
|
database.exec('PRAGMA journal_mode = WAL');
|
|
database.exec('PRAGMA busy_timeout = 5000');
|
|
return database;
|
|
}
|
|
|
|
export function openInMemoryDatabase(): Database {
|
|
return new Database(':memory:');
|
|
}
|
|
|
|
export function openDatabaseFromFile(dbPath: string): Database {
|
|
return new Database(dbPath);
|
|
}
|
|
|
|
export function migrateJsonStateFromFiles(
|
|
hooks: JsonStateMigrationHooks,
|
|
): void {
|
|
const migrateFile = (filename: string) => {
|
|
const filePath = path.join(DATA_DIR, filename);
|
|
const data = readJsonFile(filePath);
|
|
if (data === null) return null;
|
|
try {
|
|
fs.renameSync(filePath, `${filePath}.migrated`);
|
|
} catch {
|
|
/* best effort */
|
|
}
|
|
return data;
|
|
};
|
|
|
|
const routerState = migrateFile('router_state.json') as {
|
|
last_timestamp?: string;
|
|
last_agent_timestamp?: Record<string, string>;
|
|
} | null;
|
|
if (routerState) {
|
|
if (routerState.last_timestamp) {
|
|
hooks.setRouterState('last_timestamp', routerState.last_timestamp);
|
|
}
|
|
if (routerState.last_agent_timestamp) {
|
|
hooks.setRouterState(
|
|
'last_agent_timestamp',
|
|
JSON.stringify(routerState.last_agent_timestamp),
|
|
);
|
|
}
|
|
}
|
|
|
|
const sessions = migrateFile('sessions.json') as Record<
|
|
string,
|
|
string
|
|
> | null;
|
|
if (sessions) {
|
|
for (const [folder, sessionId] of Object.entries(sessions)) {
|
|
hooks.setSession(folder, sessionId);
|
|
}
|
|
}
|
|
|
|
const groups = migrateFile('registered_groups.json') as Record<
|
|
string,
|
|
RegisteredGroup
|
|
> | null;
|
|
if (groups) {
|
|
for (const [jid, group] of Object.entries(groups)) {
|
|
try {
|
|
hooks.writeLegacyRegisteredGroupAndSyncRoomSettings(jid, group);
|
|
} catch (err) {
|
|
logger.warn(
|
|
{ jid, folder: group.folder, err },
|
|
'Skipping migrated registered group with invalid folder',
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|