mirror of
https://github.com/the-draupnir-project/Draupnir.git
synced 2026-05-24 08:15:17 +00:00
Make src/index.ts use the BotModeToggle to manage the bot.
Now we need to change the integration test's makeMjolnir do the same.
This commit is contained in:
+97
-7
@@ -15,6 +15,10 @@ import {
|
||||
RoomStateBackingStore,
|
||||
ClientsInRoomMap,
|
||||
Task,
|
||||
Logger,
|
||||
Ok,
|
||||
ActionException,
|
||||
ActionExceptionKind,
|
||||
} from "matrix-protection-suite";
|
||||
import {
|
||||
BotSDKLogServiceLogger,
|
||||
@@ -43,17 +47,34 @@ import {
|
||||
} from "./safemode/SafeModeToggle";
|
||||
import { SafeModeDraupnir } from "./safemode/DraupnirSafeMode";
|
||||
import { ResultError } from "@gnuxie/typescript-result";
|
||||
import { SafeModeCause } from "./safemode/SafeModeCause";
|
||||
import { SafeModeCause, SafeModeReason } from "./safemode/SafeModeCause";
|
||||
|
||||
setGlobalLoggerProvider(new BotSDKLogServiceLogger());
|
||||
|
||||
const log = new Logger("DraupnirBotMode");
|
||||
|
||||
export function constructWebAPIs(draupnir: Draupnir): WebAPIs {
|
||||
return new WebAPIs(draupnir.reportManager, draupnir.config);
|
||||
}
|
||||
|
||||
export class DraupnirBotModeToggle implements SafeModeToggle {
|
||||
/**
|
||||
* The bot mode toggle allows the entrypoint, either src/index.ts or
|
||||
* manual test scripts, to setup and control Draupnir.
|
||||
* This includes the webAPIS that accompany Draupnir in bot mode.
|
||||
*
|
||||
* The appservice also implements `SafeModeToggle` but has different requirements.
|
||||
* This interface is exlusively used by the entrypoints to draupnir's bot mode.
|
||||
*/
|
||||
interface BotModeTogle extends SafeModeToggle {
|
||||
encryptionInitialized(): Promise<void>;
|
||||
stopEverything(): void;
|
||||
startFromScratch(options?: SafeModeToggleOptions): Promise<Result<void>>;
|
||||
}
|
||||
|
||||
export class DraupnirBotModeToggle implements BotModeTogle {
|
||||
private draupnir: Draupnir | null = null;
|
||||
private safeModeDraupnir: SafeModeDraupnir | null = null;
|
||||
private webAPIs: WebAPIs | null = null;
|
||||
|
||||
private constructor(
|
||||
private readonly clientUserID: StringUserID,
|
||||
@@ -161,13 +182,27 @@ export class DraupnirBotModeToggle implements SafeModeToggle {
|
||||
if (isError(draupnirResult)) {
|
||||
return draupnirResult;
|
||||
}
|
||||
this.safeModeDraupnir?.stop();
|
||||
this.safeModeDraupnir = null;
|
||||
this.draupnir = draupnirResult.ok;
|
||||
void Task(this.draupnir.start());
|
||||
if (options?.sendStatusOnStart) {
|
||||
void Task(this.draupnir.startupComplete());
|
||||
try {
|
||||
this.webAPIs = constructWebAPIs(this.draupnir);
|
||||
await this.webAPIs.start();
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
this.stopDraupnir();
|
||||
log.error("Failed to start webAPIs", e);
|
||||
return ActionException.Result("Failed to start webAPIs", {
|
||||
exceptionKind: ActionExceptionKind.Unknown,
|
||||
exception: e,
|
||||
});
|
||||
} else {
|
||||
throw new TypeError("Someone is throwing garbage.");
|
||||
}
|
||||
}
|
||||
}
|
||||
this.stopSafeModeDraupnir();
|
||||
return draupnirResult;
|
||||
}
|
||||
public async switchToSafeMode(
|
||||
@@ -189,13 +224,68 @@ export class DraupnirBotModeToggle implements SafeModeToggle {
|
||||
if (isError(safeModeResult)) {
|
||||
return safeModeResult;
|
||||
}
|
||||
this.draupnir?.stop();
|
||||
this.draupnir = null;
|
||||
this.stopDraupnir();
|
||||
this.safeModeDraupnir = safeModeResult.ok;
|
||||
this.safeModeDraupnir.start();
|
||||
if (options?.sendStatusOnStart) {
|
||||
this.safeModeDraupnir.sendStartupComplete();
|
||||
this.safeModeDraupnir.startupComplete();
|
||||
}
|
||||
return safeModeResult;
|
||||
}
|
||||
|
||||
public async startFromScratch(
|
||||
options?: SafeModeToggleOptions
|
||||
): Promise<Result<void>> {
|
||||
const draupnirResult = await this.switchToDraupnir(options ?? {});
|
||||
if (isError(draupnirResult)) {
|
||||
if (this.config.safeMode?.bootOnStartupFailure) {
|
||||
log.error(
|
||||
"Failed to start draupnir, switching to safe mode as configured",
|
||||
draupnirResult.error
|
||||
);
|
||||
return (await this.switchToSafeMode(
|
||||
{
|
||||
reason: SafeModeReason.InitializationError,
|
||||
error: draupnirResult.error,
|
||||
},
|
||||
options ?? {}
|
||||
)) as Result<void>;
|
||||
} else {
|
||||
return draupnirResult;
|
||||
}
|
||||
}
|
||||
return Ok(undefined);
|
||||
}
|
||||
|
||||
public async encryptionInitialized(): Promise<void> {
|
||||
if (this.draupnir !== null) {
|
||||
try {
|
||||
this.webAPIs = constructWebAPIs(this.draupnir);
|
||||
await this.webAPIs.start();
|
||||
await this.draupnir.startupComplete();
|
||||
} catch (e) {
|
||||
this.stopEverything();
|
||||
throw e;
|
||||
}
|
||||
} else if (this.safeModeDraupnir !== null) {
|
||||
this.safeModeDraupnir.startupComplete();
|
||||
}
|
||||
}
|
||||
|
||||
private stopDraupnir(): void {
|
||||
this.draupnir?.stop();
|
||||
this.draupnir = null;
|
||||
this.webAPIs?.stop();
|
||||
this.webAPIs = null;
|
||||
}
|
||||
|
||||
private stopSafeModeDraupnir(): void {
|
||||
this.safeModeDraupnir?.stop();
|
||||
this.safeModeDraupnir = null;
|
||||
}
|
||||
|
||||
public stopEverything(): void {
|
||||
this.stopDraupnir();
|
||||
this.stopSafeModeDraupnir();
|
||||
}
|
||||
}
|
||||
|
||||
+9
-16
@@ -9,9 +9,7 @@
|
||||
// </text>
|
||||
|
||||
import * as path from "path";
|
||||
|
||||
import { Healthz } from "./health/healthz";
|
||||
|
||||
import {
|
||||
LogLevel,
|
||||
LogService,
|
||||
@@ -24,11 +22,9 @@ import {
|
||||
import { StoreType } from "@matrix-org/matrix-sdk-crypto-nodejs";
|
||||
import { read as configRead } from "./config";
|
||||
import { initializeSentry, patchMatrixClient } from "./utils";
|
||||
import { DraupnirBotModeToggle, constructWebAPIs } from "./DraupnirBotMode";
|
||||
import { Draupnir } from "./Draupnir";
|
||||
import { DraupnirBotModeToggle } from "./DraupnirBotMode";
|
||||
import { SafeMatrixEmitterWrapper } from "matrix-protection-suite-for-matrix-bot-sdk";
|
||||
import { DefaultEventDecoder, Task } from "matrix-protection-suite";
|
||||
import { WebAPIs } from "./webapis/WebAPIs";
|
||||
import { DefaultEventDecoder } from "matrix-protection-suite";
|
||||
import { SqliteRoomStateBackingStore } from "./backingstore/better-sqlite3/SqliteRoomStateBackingStore";
|
||||
|
||||
void (async function () {
|
||||
@@ -51,8 +47,7 @@ void (async function () {
|
||||
healthz.listen();
|
||||
}
|
||||
|
||||
let bot: Draupnir | null = null;
|
||||
let apis: WebAPIs | null = null;
|
||||
let bot: DraupnirBotModeToggle | null = null;
|
||||
try {
|
||||
const storagePath = path.isAbsolute(config.dataPath)
|
||||
? config.dataPath
|
||||
@@ -101,7 +96,7 @@ void (async function () {
|
||||
eventDecoder
|
||||
)
|
||||
: undefined;
|
||||
const toggle = await DraupnirBotModeToggle.create(
|
||||
bot = await DraupnirBotModeToggle.create(
|
||||
client,
|
||||
new SafeMatrixEmitterWrapper(client, eventDecoder),
|
||||
config,
|
||||
@@ -109,25 +104,23 @@ void (async function () {
|
||||
);
|
||||
|
||||
// We don't want to send the status on start, as we need to initialize e2ee first (using client.start);
|
||||
bot = (await toggle.switchToDraupnir({ sendStatusOnStart: false })).expect(
|
||||
"Failed to initialize Draupnir"
|
||||
(await bot.startFromScratch({ sendStatusOnStart: false })).expect(
|
||||
"Failed to start Draupnir"
|
||||
);
|
||||
apis = constructWebAPIs(bot);
|
||||
} catch (err) {
|
||||
console.error(
|
||||
`Failed to setup mjolnir from the config ${config.dataPath}: ${err}`
|
||||
);
|
||||
bot?.stopEverything();
|
||||
throw err;
|
||||
}
|
||||
try {
|
||||
await config.RUNTIME.client.start();
|
||||
void Task(bot.startupComplete());
|
||||
await apis.start();
|
||||
await bot.encryptionInitialized();
|
||||
healthz.isHealthy = true;
|
||||
} catch (err) {
|
||||
console.error(`Mjolnir failed to start: ${err}`);
|
||||
bot.stop();
|
||||
apis.stop();
|
||||
bot.stopEverything();
|
||||
throw err;
|
||||
}
|
||||
})();
|
||||
|
||||
@@ -101,7 +101,7 @@ export class SafeModeDraupnir implements MatrixAdaptorContext {
|
||||
this.clientRooms.off("timeline", this.timelineEventListener);
|
||||
}
|
||||
|
||||
public sendStartupComplete(): void {
|
||||
public startupComplete(): void {
|
||||
void Task(
|
||||
sendMatrixEventsFromDeadDocument(
|
||||
this.clientPlatform.toRoomMessageSender(),
|
||||
|
||||
Reference in New Issue
Block a user