refactor db
This commit is contained in:
@@ -43,166 +43,172 @@ import path from "path";
|
|||||||
import url from "url";
|
import url from "url";
|
||||||
import { i18n } from "@main/i18n";
|
import { i18n } from "@main/i18n";
|
||||||
import { UserSettingKeyEnum } from "@/types/enums";
|
import { UserSettingKeyEnum } from "@/types/enums";
|
||||||
|
import log from "@main/logger";
|
||||||
|
|
||||||
const __filename = url.fileURLToPath(import.meta.url);
|
const __filename = url.fileURLToPath(import.meta.url);
|
||||||
const __dirname = path.dirname(__filename);
|
const __dirname = path.dirname(__filename);
|
||||||
|
const logger = log.scope("DB");
|
||||||
|
|
||||||
const db = {
|
const db = {
|
||||||
connection: null as Sequelize | null,
|
connection: null as Sequelize | null,
|
||||||
connect: async () => {},
|
connect: async () => {},
|
||||||
disconnect: async () => {},
|
disconnect: async () => {},
|
||||||
registerIpcHandlers: () => {},
|
registerIpcHandlers: () => {},
|
||||||
|
isConnecting: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handlers = [
|
||||||
|
audiosHandler,
|
||||||
|
cacheObjectsHandler,
|
||||||
|
chatAgentsHandler,
|
||||||
|
chatMembersHandler,
|
||||||
|
chatMessagesHandler,
|
||||||
|
chatsHandler,
|
||||||
|
conversationsHandler,
|
||||||
|
messagesHandler,
|
||||||
|
notesHandler,
|
||||||
|
pronunciationAssessmentsHandler,
|
||||||
|
recordingsHandler,
|
||||||
|
segmentsHandler,
|
||||||
|
speechesHandler,
|
||||||
|
transcriptionsHandler,
|
||||||
|
userSettingsHandler,
|
||||||
|
videosHandler,
|
||||||
|
];
|
||||||
|
|
||||||
db.connect = async () => {
|
db.connect = async () => {
|
||||||
if (db.connection) {
|
// Use a lock to prevent concurrent connections
|
||||||
return;
|
if (db.isConnecting) {
|
||||||
}
|
throw new Error("Database connection is already in progress");
|
||||||
const dbPath = settings.dbPath();
|
|
||||||
if (!dbPath) {
|
|
||||||
throw new Error("Db path is not ready");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const sequelize = new Sequelize({
|
db.isConnecting = true;
|
||||||
dialect: "sqlite",
|
|
||||||
storage: dbPath,
|
|
||||||
models: [
|
|
||||||
Audio,
|
|
||||||
CacheObject,
|
|
||||||
Chat,
|
|
||||||
ChatAgent,
|
|
||||||
ChatMember,
|
|
||||||
ChatMessage,
|
|
||||||
Conversation,
|
|
||||||
Message,
|
|
||||||
Note,
|
|
||||||
PronunciationAssessment,
|
|
||||||
Recording,
|
|
||||||
Segment,
|
|
||||||
Speech,
|
|
||||||
Transcription,
|
|
||||||
UserSetting,
|
|
||||||
Video,
|
|
||||||
],
|
|
||||||
});
|
|
||||||
|
|
||||||
db.connection = sequelize;
|
try {
|
||||||
|
if (db.connection) {
|
||||||
const migrationResolver: Resolver<unknown> = ({
|
return;
|
||||||
name,
|
}
|
||||||
path: filepath,
|
const dbPath = settings.dbPath();
|
||||||
context,
|
if (!dbPath) {
|
||||||
}) => {
|
throw new Error("Db path is not ready");
|
||||||
if (!filepath) {
|
|
||||||
throw new Error(
|
|
||||||
`Can't use default resolver for non-filesystem migrations`
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const loadModule: () => Promise<RunnableMigration<unknown>> = async () => {
|
const sequelize = new Sequelize({
|
||||||
if (os.platform() === "win32") {
|
dialect: "sqlite",
|
||||||
return import(`file://${filepath}`) as Promise<
|
storage: dbPath,
|
||||||
RunnableMigration<unknown>
|
models: [
|
||||||
>;
|
Audio,
|
||||||
} else {
|
CacheObject,
|
||||||
return import(filepath) as Promise<RunnableMigration<unknown>>;
|
Chat,
|
||||||
}
|
ChatAgent,
|
||||||
};
|
ChatMember,
|
||||||
|
ChatMessage,
|
||||||
|
Conversation,
|
||||||
|
Message,
|
||||||
|
Note,
|
||||||
|
PronunciationAssessment,
|
||||||
|
Recording,
|
||||||
|
Segment,
|
||||||
|
Speech,
|
||||||
|
Transcription,
|
||||||
|
UserSetting,
|
||||||
|
Video,
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
const getModule = async () => {
|
const migrationResolver: Resolver<unknown> = ({
|
||||||
return await loadModule();
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
name,
|
name,
|
||||||
path: filepath,
|
path: filepath,
|
||||||
up: async () => (await getModule()).up({ path: filepath, name, context }),
|
context,
|
||||||
down: async () =>
|
}) => {
|
||||||
(await getModule()).down?.({ path: filepath, name, context }),
|
if (!filepath) {
|
||||||
};
|
throw new Error(
|
||||||
};
|
`Can't use default resolver for non-filesystem migrations`
|
||||||
|
);
|
||||||
const umzug = new Umzug({
|
|
||||||
migrations: {
|
|
||||||
glob: ["migrations/*.js", { cwd: __dirname }],
|
|
||||||
resolve: migrationResolver,
|
|
||||||
},
|
|
||||||
context: sequelize.getQueryInterface(),
|
|
||||||
storage: new SequelizeStorage({ sequelize }),
|
|
||||||
logger: console,
|
|
||||||
});
|
|
||||||
|
|
||||||
// migrate up to the latest state
|
|
||||||
await umzug.up();
|
|
||||||
|
|
||||||
await sequelize.query("PRAGMA foreign_keys = false;");
|
|
||||||
await sequelize.sync();
|
|
||||||
await sequelize.authenticate();
|
|
||||||
|
|
||||||
// kill the zombie transcribe processes
|
|
||||||
Transcription.findAll({
|
|
||||||
where: {
|
|
||||||
state: "processing",
|
|
||||||
},
|
|
||||||
}).then((transcriptions) => {
|
|
||||||
transcriptions.forEach((transcription) => {
|
|
||||||
if (transcription.result) {
|
|
||||||
transcription.update({ state: "finished" });
|
|
||||||
} else {
|
|
||||||
transcription.update({ state: "pending" });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const loadModule: () => Promise<
|
||||||
|
RunnableMigration<unknown>
|
||||||
|
> = async () => {
|
||||||
|
if (os.platform() === "win32") {
|
||||||
|
return import(`file://${filepath}`) as Promise<
|
||||||
|
RunnableMigration<unknown>
|
||||||
|
>;
|
||||||
|
} else {
|
||||||
|
return import(filepath) as Promise<RunnableMigration<unknown>>;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const getModule = async () => {
|
||||||
|
return await loadModule();
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
name,
|
||||||
|
path: filepath,
|
||||||
|
up: async () =>
|
||||||
|
(await getModule()).up({ path: filepath, name, context }),
|
||||||
|
down: async () =>
|
||||||
|
(await getModule()).down?.({ path: filepath, name, context }),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const umzug = new Umzug({
|
||||||
|
migrations: {
|
||||||
|
glob: ["migrations/*.js", { cwd: __dirname }],
|
||||||
|
resolve: migrationResolver,
|
||||||
|
},
|
||||||
|
context: sequelize.getQueryInterface(),
|
||||||
|
storage: new SequelizeStorage({ sequelize }),
|
||||||
|
logger: logger,
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
// migrate settings
|
try {
|
||||||
await UserSetting.migrateFromSettings();
|
// migrate up to the latest state
|
||||||
|
await umzug.up();
|
||||||
|
|
||||||
// initialize i18n
|
await sequelize.query("PRAGMA foreign_keys = false;");
|
||||||
const language = (await UserSetting.get(
|
await sequelize.sync();
|
||||||
UserSettingKeyEnum.LANGUAGE
|
await sequelize.authenticate();
|
||||||
)) as string;
|
} catch (err) {
|
||||||
i18n(language);
|
logger.error(err);
|
||||||
|
await sequelize.close();
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
|
||||||
// vacuum the database
|
// migrate settings
|
||||||
await sequelize.query("VACUUM");
|
await UserSetting.migrateFromSettings();
|
||||||
|
|
||||||
// register handlers
|
// initialize i18n
|
||||||
audiosHandler.register();
|
const language = (await UserSetting.get(
|
||||||
cacheObjectsHandler.register();
|
UserSettingKeyEnum.LANGUAGE
|
||||||
chatAgentsHandler.register();
|
)) as string;
|
||||||
chatMembersHandler.register();
|
i18n(language);
|
||||||
chatMessagesHandler.register();
|
|
||||||
chatsHandler.register();
|
// vacuum the database
|
||||||
conversationsHandler.register();
|
await sequelize.query("VACUUM");
|
||||||
messagesHandler.register();
|
|
||||||
notesHandler.register();
|
// register handlers
|
||||||
pronunciationAssessmentsHandler.register();
|
|
||||||
recordingsHandler.register();
|
for (const handler of handlers) {
|
||||||
segmentsHandler.register();
|
handler.register();
|
||||||
speechesHandler.register();
|
}
|
||||||
transcriptionsHandler.register();
|
|
||||||
userSettingsHandler.register();
|
db.connection = sequelize;
|
||||||
videosHandler.register();
|
logger.info("Database connection established");
|
||||||
|
} catch (err) {
|
||||||
|
logger.error(err);
|
||||||
|
throw err;
|
||||||
|
} finally {
|
||||||
|
db.isConnecting = false;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
db.disconnect = async () => {
|
db.disconnect = async () => {
|
||||||
// unregister handlers
|
// unregister handlers
|
||||||
audiosHandler.unregister();
|
for (const handler of handlers) {
|
||||||
cacheObjectsHandler.unregister();
|
handler.unregister();
|
||||||
chatAgentsHandler.unregister();
|
}
|
||||||
chatMembersHandler.unregister();
|
|
||||||
chatMessagesHandler.unregister();
|
|
||||||
chatsHandler.unregister();
|
|
||||||
conversationsHandler.unregister();
|
|
||||||
messagesHandler.unregister();
|
|
||||||
notesHandler.unregister();
|
|
||||||
pronunciationAssessmentsHandler.unregister();
|
|
||||||
recordingsHandler.unregister();
|
|
||||||
segmentsHandler.unregister();
|
|
||||||
speechesHandler.unregister();
|
|
||||||
transcriptionsHandler.unregister();
|
|
||||||
userSettingsHandler.unregister();
|
|
||||||
videosHandler.unregister();
|
|
||||||
|
|
||||||
await db.connection?.close();
|
await db.connection?.close();
|
||||||
db.connection = null;
|
db.connection = null;
|
||||||
|
|||||||
Reference in New Issue
Block a user