sqlite: synchronize enable() internally
TL is stupid and doesn't wait for message{Provider,Storage} to settle before it starts using the store. While this should be fixed globally, we can hack around the problem by pushing everything onto the call stack and hope that we'll eventually finish the setup before we blow the stack.
This commit is contained in:
parent
deeea274da
commit
2d4143b779
@ -38,17 +38,30 @@ const schema = [
|
|||||||
"CREATE INDEX IF NOT EXISTS time ON messages (time)",
|
"CREATE INDEX IF NOT EXISTS time ON messages (time)",
|
||||||
];
|
];
|
||||||
|
|
||||||
|
class Deferred {
|
||||||
|
resolve!: () => void;
|
||||||
|
promise: Promise<void>;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.promise = new Promise((resolve) => {
|
||||||
|
this.resolve = resolve;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class SqliteMessageStorage implements ISqliteMessageStorage {
|
class SqliteMessageStorage implements ISqliteMessageStorage {
|
||||||
client: Client;
|
client: Client;
|
||||||
isEnabled: boolean;
|
isEnabled: boolean;
|
||||||
database!: Database;
|
database!: Database;
|
||||||
|
initDone: Deferred;
|
||||||
|
|
||||||
constructor(client: Client) {
|
constructor(client: Client) {
|
||||||
this.client = client;
|
this.client = client;
|
||||||
this.isEnabled = false;
|
this.isEnabled = false;
|
||||||
|
this.initDone = new Deferred();
|
||||||
}
|
}
|
||||||
|
|
||||||
async enable() {
|
async _enable() {
|
||||||
const logsPath = Config.getUserLogsPath();
|
const logsPath = Config.getUserLogsPath();
|
||||||
const sqlitePath = path.join(logsPath, `${this.client.name}.sqlite3`);
|
const sqlitePath = path.join(logsPath, `${this.client.name}.sqlite3`);
|
||||||
|
|
||||||
@ -70,6 +83,14 @@ class SqliteMessageStorage implements ISqliteMessageStorage {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async enable() {
|
||||||
|
try {
|
||||||
|
await this._enable();
|
||||||
|
} finally {
|
||||||
|
this.initDone.resolve(); // unblock the instance methods
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async run_migrations() {
|
async run_migrations() {
|
||||||
for (const stmt of schema) {
|
for (const stmt of schema) {
|
||||||
await this.serialize_run(stmt, []);
|
await this.serialize_run(stmt, []);
|
||||||
@ -127,6 +148,8 @@ class SqliteMessageStorage implements ISqliteMessageStorage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async index(network: Network, channel: Chan, msg: Msg) {
|
async index(network: Network, channel: Chan, msg: Msg) {
|
||||||
|
await this.initDone.promise;
|
||||||
|
|
||||||
if (!this.isEnabled) {
|
if (!this.isEnabled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -155,6 +178,8 @@ class SqliteMessageStorage implements ISqliteMessageStorage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async deleteChannel(network: Network, channel: Channel) {
|
async deleteChannel(network: Network, channel: Channel) {
|
||||||
|
await this.initDone.promise;
|
||||||
|
|
||||||
if (!this.isEnabled) {
|
if (!this.isEnabled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -172,6 +197,8 @@ class SqliteMessageStorage implements ISqliteMessageStorage {
|
|||||||
* @param channel Channel - Channel object for which to load messages for
|
* @param channel Channel - Channel object for which to load messages for
|
||||||
*/
|
*/
|
||||||
async getMessages(network: Network, channel: Channel): Promise<Message[]> {
|
async getMessages(network: Network, channel: Channel): Promise<Message[]> {
|
||||||
|
await this.initDone.promise;
|
||||||
|
|
||||||
if (!this.isEnabled || Config.values.maxHistory === 0) {
|
if (!this.isEnabled || Config.values.maxHistory === 0) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
@ -199,6 +226,8 @@ class SqliteMessageStorage implements ISqliteMessageStorage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async search(query: SearchQuery): Promise<SearchResponse> {
|
async search(query: SearchQuery): Promise<SearchResponse> {
|
||||||
|
await this.initDone.promise;
|
||||||
|
|
||||||
if (!this.isEnabled) {
|
if (!this.isEnabled) {
|
||||||
// this should never be hit as messageProvider is checked in client.search()
|
// this should never be hit as messageProvider is checked in client.search()
|
||||||
throw new Error(
|
throw new Error(
|
||||||
|
@ -37,11 +37,6 @@ describe("SQLite Message Storage", function () {
|
|||||||
fs.rmdir(path.join(Config.getHomePath(), "logs"), done);
|
fs.rmdir(path.join(Config.getHomePath(), "logs"), done);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should resolve an empty array when disabled", async function () {
|
|
||||||
const messages = await store.getMessages(null as any, null as any);
|
|
||||||
expect(messages).to.be.empty;
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should create database file", async function () {
|
it("should create database file", async function () {
|
||||||
expect(store.isEnabled).to.be.false;
|
expect(store.isEnabled).to.be.false;
|
||||||
expect(fs.existsSync(expectedPath)).to.be.false;
|
expect(fs.existsSync(expectedPath)).to.be.false;
|
||||||
@ -50,6 +45,13 @@ describe("SQLite Message Storage", function () {
|
|||||||
expect(store.isEnabled).to.be.true;
|
expect(store.isEnabled).to.be.true;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should resolve an empty array when disabled", async function () {
|
||||||
|
store.isEnabled = false;
|
||||||
|
const messages = await store.getMessages(null as any, null as any);
|
||||||
|
expect(messages).to.be.empty;
|
||||||
|
store.isEnabled = true;
|
||||||
|
});
|
||||||
|
|
||||||
it("should create tables", function (done) {
|
it("should create tables", function (done) {
|
||||||
store.database.all(
|
store.database.all(
|
||||||
"SELECT name, tbl_name, sql FROM sqlite_master WHERE type = 'table'",
|
"SELECT name, tbl_name, sql FROM sqlite_master WHERE type = 'table'",
|
||||||
|
Loading…
Reference in New Issue
Block a user