feat: complete Ancestor quote bot with production-ready Docker support

This commit is contained in:
unfunny
2026-09-13 14:14:38 -04:00
parent f2016da05a
commit fe7351a7dc
1145 changed files with 30890 additions and 97684 deletions

View File

@@ -1,4 +1,18 @@
import _defineProperty from "@babel/runtime/helpers/defineProperty";
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.IndexedDBStore = void 0;
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _memory = require("./memory");
var _indexeddbLocalBackend = require("./indexeddb-local-backend");
var _indexeddbRemoteBackend = require("./indexeddb-remote-backend");
var _user = require("../models/user");
var _event = require("../models/event");
var _logger = require("../logger");
var _typedEventEmitter = require("../models/typed-event-emitter");
/*
Copyright 2017 - 2021 Vector Creations Ltd
@@ -15,12 +29,8 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import { MemoryStore } from "./memory.js";
import { LocalIndexedDBStoreBackend } from "./indexeddb-local-backend.js";
import { RemoteIndexedDBStoreBackend } from "./indexeddb-remote-backend.js";
import { MatrixEvent } from "../models/event.js";
import { logger } from "../logger.js";
import { TypedEventEmitter } from "../models/typed-event-emitter.js";
/* eslint-disable @babel/no-invalid-this */
/**
* This is an internal module. See {@link IndexedDBStore} for the public class.
*/
@@ -32,10 +42,16 @@ import { TypedEventEmitter } from "../models/typed-event-emitter.js";
// response is persisted each time.
const WRITE_DELAY_MS = 1000 * 60 * 5; // once every 5 minutes
export class IndexedDBStore extends MemoryStore {
class IndexedDBStore extends _memory.MemoryStore {
static exists(indexedDB, dbName) {
return LocalIndexedDBStoreBackend.exists(indexedDB, dbName);
return _indexeddbLocalBackend.LocalIndexedDBStoreBackend.exists(indexedDB, dbName);
}
/**
* The backend instance.
* Call through to this API if you need to perform specific indexeddb actions like deleting the database.
*/
/**
* Construct a new Indexed Database store, which extends MemoryStore.
*
@@ -49,10 +65,10 @@ export class IndexedDBStore extends MemoryStore {
* ```
* let opts = { indexedDB: window.indexedDB, localStorage: window.localStorage };
* let store = new IndexedDBStore(opts);
* await store.startup(); // load from indexed db
* let client = sdk.createClient({
* store: store,
* });
* await store.startup(); // load from indexed db, must be called after createClient
* client.startClient();
* client.on("sync", function(state, prevState, data) {
* if (state === "PREPARED") {
@@ -65,16 +81,17 @@ export class IndexedDBStore extends MemoryStore {
*/
constructor(opts) {
super(opts);
_defineProperty(this, "_backend", void 0);
_defineProperty(this, "startedUp", false);
_defineProperty(this, "syncTs", 0);
(0, _defineProperty2.default)(this, "backend", void 0);
(0, _defineProperty2.default)(this, "startedUp", false);
(0, _defineProperty2.default)(this, "syncTs", 0);
// Records the last-modified-time of each user at the last point we saved
// the database, such that we can derive the set if users that have been
// modified since we last saved.
_defineProperty(this, "userModifiedMap", {});
(0, _defineProperty2.default)(this, "userModifiedMap", {});
// user_id : timestamp
_defineProperty(this, "emitter", new TypedEventEmitter());
_defineProperty(this, "onClose", () => {
(0, _defineProperty2.default)(this, "emitter", new _typedEventEmitter.TypedEventEmitter());
(0, _defineProperty2.default)(this, "on", this.emitter.on.bind(this.emitter));
(0, _defineProperty2.default)(this, "onClose", () => {
this.emitter.emit("closed");
});
/**
@@ -82,34 +99,34 @@ export class IndexedDBStore extends MemoryStore {
* client state to where it was at the last save, or null if there
* is no saved sync data.
*/
_defineProperty(this, "getSavedSync", this.degradable(() => {
(0, _defineProperty2.default)(this, "getSavedSync", this.degradable(() => {
return this.backend.getSavedSync();
}, "getSavedSync"));
/** @returns whether or not the database was newly created in this session. */
_defineProperty(this, "isNewlyCreated", this.degradable(() => {
(0, _defineProperty2.default)(this, "isNewlyCreated", this.degradable(() => {
return this.backend.isNewlyCreated();
}, "isNewlyCreated"));
/**
* @returns If there is a saved sync, the nextBatch token
* for this sync, otherwise null.
*/
_defineProperty(this, "getSavedSyncToken", this.degradable(() => {
(0, _defineProperty2.default)(this, "getSavedSyncToken", this.degradable(() => {
return this.backend.getNextBatchToken();
}, "getSavedSyncToken"));
/**
* Delete all data from this store.
* @returns Promise which resolves if the data was deleted from the database.
*/
_defineProperty(this, "deleteAllData", this.degradable(() => {
(0, _defineProperty2.default)(this, "deleteAllData", this.degradable(() => {
super.deleteAllData();
return this.backend.clearDatabase().then(() => {
logger.log("Deleted indexeddb data.");
_logger.logger.log("Deleted indexeddb data.");
}, err => {
logger.error(`Failed to delete indexeddb data: ${err}`);
_logger.logger.error(`Failed to delete indexeddb data: ${err}`);
throw err;
});
}, null));
_defineProperty(this, "reallySave", this.degradable(() => {
}));
(0, _defineProperty2.default)(this, "reallySave", this.degradable(() => {
this.syncTs = Date.now(); // set now to guard against multi-writes
// work out changed users (this doesn't handle deletions but you
@@ -124,8 +141,8 @@ export class IndexedDBStore extends MemoryStore {
this.userModifiedMap[u.userId] = u.getLastModifiedTime();
}
return this.backend.syncToDatabase(userTuples);
}, null));
_defineProperty(this, "setSyncData", this.degradable(syncData => {
}));
(0, _defineProperty2.default)(this, "setSyncData", this.degradable(syncData => {
return this.backend.setSyncData(syncData);
}, "setSyncData"));
/**
@@ -134,7 +151,7 @@ export class IndexedDBStore extends MemoryStore {
* @returns the events, potentially an empty array if OOB loading didn't yield any new members
* @returns in case the members for this room haven't been stored yet
*/
_defineProperty(this, "getOutOfBandMembers", this.degradable(roomId => {
(0, _defineProperty2.default)(this, "getOutOfBandMembers", this.degradable(roomId => {
return this.backend.getOutOfBandMembers(roomId);
}, "getOutOfBandMembers"));
/**
@@ -144,73 +161,48 @@ export class IndexedDBStore extends MemoryStore {
* @param membershipEvents - the membership events to store
* @returns when all members have been stored
*/
_defineProperty(this, "setOutOfBandMembers", this.degradable((roomId, membershipEvents) => {
(0, _defineProperty2.default)(this, "setOutOfBandMembers", this.degradable((roomId, membershipEvents) => {
super.setOutOfBandMembers(roomId, membershipEvents);
return this.backend.setOutOfBandMembers(roomId, membershipEvents);
}, "setOutOfBandMembers"));
_defineProperty(this, "clearOutOfBandMembers", this.degradable(roomId => {
(0, _defineProperty2.default)(this, "clearOutOfBandMembers", this.degradable(roomId => {
super.clearOutOfBandMembers(roomId);
return this.backend.clearOutOfBandMembers(roomId);
}, "clearOutOfBandMembers"));
_defineProperty(this, "getClientOptions", this.degradable(() => {
(0, _defineProperty2.default)(this, "getClientOptions", this.degradable(() => {
return this.backend.getClientOptions();
}, "getClientOptions"));
_defineProperty(this, "storeClientOptions", this.degradable(options => {
(0, _defineProperty2.default)(this, "storeClientOptions", this.degradable(options => {
super.storeClientOptions(options);
return this.backend.storeClientOptions(options);
}, "storeClientOptions"));
this.opts = opts;
if (!opts.indexedDB) {
throw new Error("Missing required option: indexedDB");
}
if (opts.workerFactory) {
this._backend = new RemoteIndexedDBStoreBackend(opts.workerFactory, opts.dbName);
this.backend = new _indexeddbRemoteBackend.RemoteIndexedDBStoreBackend(opts.workerFactory, opts.dbName);
} else {
this._backend = new LocalIndexedDBStoreBackend(opts.indexedDB, opts.dbName);
this.backend = new _indexeddbLocalBackend.LocalIndexedDBStoreBackend(opts.indexedDB, opts.dbName);
}
}
/**
* The backend instance.
* Call through to this API if you need to perform specific indexeddb actions like deleting the database.
*/
get backend() {
return this._backend;
}
/** Re-exports `TypedEventEmitter.on` */
on(event, handler) {
this.emitter.on(event, handler);
}
/**
* @returns Resolved when loaded from indexed db.
*/
startup() {
if (this.startedUp) {
logger.log(`IndexedDBStore.startup: already started`);
_logger.logger.log(`IndexedDBStore.startup: already started`);
return Promise.resolve();
}
logger.log(`IndexedDBStore.startup: connecting to backend`);
return this.backend.connect(this.onClose).catch(e => {
if (this.opts.workerFactory) {
logger.log("Falling back to local indexeddb backend");
this._backend = new LocalIndexedDBStoreBackend(this.opts.indexedDB, this.opts.dbName);
return this.backend.connect(this.onClose);
}
throw e;
}).then(() => {
logger.log(`IndexedDBStore.startup: loading presence events`);
_logger.logger.log(`IndexedDBStore.startup: connecting to backend`);
return this.backend.connect(this.onClose).then(() => {
_logger.logger.log(`IndexedDBStore.startup: loading presence events`);
return this.backend.getUserPresenceEvents();
}).then(userPresenceEvents => {
logger.log(`IndexedDBStore.startup: processing presence events`);
_logger.logger.log(`IndexedDBStore.startup: processing presence events`);
userPresenceEvents.forEach(([userId, rawEvent]) => {
if (!this.createUser) {
throw new Error("`IndexedDBStore.startup` must be called after assigning it to the client, not before!");
}
const u = this.createUser(userId);
const u = new _user.User(userId);
if (rawEvent) {
u.setPresenceEvent(new MatrixEvent(rawEvent));
u.setPresenceEvent(new _event.MatrixEvent(rawEvent));
}
this.userModifiedMap[u.userId] = u.getLastModifiedTime();
this.storeUser(u);
@@ -270,18 +262,18 @@ export class IndexedDBStore extends MemoryStore {
try {
return await func.call(this, ...args);
} catch (e) {
logger.error("IndexedDBStore failure, degrading to MemoryStore", e);
_logger.logger.error("IndexedDBStore failure, degrading to MemoryStore", e);
this.emitter.emit("degraded", e);
try {
// We try to delete IndexedDB after degrading since this store is only a
// cache (the app will still function correctly without the data).
// It's possible that deleting repair IndexedDB for the next app load,
// potentially by making a little more space available.
logger.log("IndexedDBStore trying to delete degraded data");
_logger.logger.log("IndexedDBStore trying to delete degraded data");
await this.backend.clearDatabase();
logger.log("IndexedDBStore delete after degrading succeeded");
_logger.logger.log("IndexedDBStore delete after degrading succeeded");
} catch (e) {
logger.warn("IndexedDBStore delete after degrading failed", e);
_logger.logger.warn("IndexedDBStore delete after degrading failed", e);
}
// Degrade the store from being an instance of `IndexedDBStore` to instead be
// an instance of `MemoryStore` so that future API calls use the memory path
@@ -306,7 +298,7 @@ export class IndexedDBStore extends MemoryStore {
try {
return JSON.parse(serialized);
} catch (e) {
logger.error("Could not parse persisted pending events", e);
_logger.logger.error("Could not parse persisted pending events", e);
}
}
return [];
@@ -328,21 +320,13 @@ export class IndexedDBStore extends MemoryStore {
removeToDeviceBatch(id) {
return this.backend.removeToDeviceBatch(id);
}
async getUserProfile(userId) {
return this.backend.getUserProfile(userId);
}
async storeUserProfiles(userProfiles) {
return this.backend.storeUserProfiles(userProfiles);
}
async removeUserProfiles(userIds) {
return this.backend.removeUserProfiles(userIds);
}
}
/**
* @param roomId - ID of the current room
* @returns Storage key to retrieve pending events
*/
exports.IndexedDBStore = IndexedDBStore;
function pendingEventsKey(roomId) {
return `mx_pending_events_${roomId}`;
}