mirror of
https://github.com/the-draupnir-project/Draupnir.git
synced 2026-08-03 09:19:22 +00:00
Create a fresh safe mode instance when restarting Draupnir.
Specifically, when restart Draupnir fails, and safe mode is already running, we will want to create a fresh safe mode instance that contains the relevant recovery options, from the new cause of failure.
This commit is contained in:
+43
-16
@@ -39,8 +39,9 @@ import {
|
||||
StringUserID,
|
||||
MatrixRoomID,
|
||||
} from "@the-draupnir-project/matrix-basic-types";
|
||||
import { Result, isError } from "@gnuxie/typescript-result";
|
||||
import { Err, Ok, Result, isError } from "@gnuxie/typescript-result";
|
||||
import {
|
||||
DraupnirRestartError,
|
||||
SafeModeToggle,
|
||||
SafeModeToggleOptions,
|
||||
} from "./safemode/SafeModeToggle";
|
||||
@@ -70,6 +71,10 @@ interface BotModeTogle extends SafeModeToggle {
|
||||
startFromScratch(
|
||||
options?: SafeModeToggleOptions
|
||||
): Promise<Result<Draupnir | SafeModeDraupnir>>;
|
||||
maybeRecoverWithSafeMode(
|
||||
error: ResultError,
|
||||
options?: SafeModeToggleOptions
|
||||
): Promise<Result<SafeModeDraupnir>>;
|
||||
}
|
||||
|
||||
export class DraupnirBotModeToggle implements BotModeTogle {
|
||||
@@ -168,12 +173,13 @@ export class DraupnirBotModeToggle implements BotModeTogle {
|
||||
}
|
||||
public async switchToDraupnir(
|
||||
options?: SafeModeToggleOptions
|
||||
): Promise<Result<Draupnir>> {
|
||||
): Promise<Result<Draupnir, DraupnirRestartError | ResultError>> {
|
||||
if (this.draupnir !== null) {
|
||||
return ResultError.Result(
|
||||
`There is a draupnir for ${this.clientUserID} already running`
|
||||
);
|
||||
}
|
||||
this.stopSafeModeDraupnir();
|
||||
const draupnirResult = await this.draupnirFactory.makeDraupnir(
|
||||
this.clientUserID,
|
||||
this.managementRoom,
|
||||
@@ -181,7 +187,18 @@ export class DraupnirBotModeToggle implements BotModeTogle {
|
||||
this
|
||||
);
|
||||
if (isError(draupnirResult)) {
|
||||
return draupnirResult;
|
||||
const safeModeResult = await this.maybeRecoverWithSafeMode(
|
||||
draupnirResult.error,
|
||||
options
|
||||
);
|
||||
if (isError(safeModeResult)) {
|
||||
return safeModeResult;
|
||||
} else {
|
||||
return DraupnirRestartError.Result(
|
||||
"Draupnir failed to start, switching to safe mode.",
|
||||
{ safeModeDraupnir: safeModeResult.ok }
|
||||
);
|
||||
}
|
||||
}
|
||||
this.draupnir = draupnirResult.ok;
|
||||
this.draupnir.start();
|
||||
@@ -203,7 +220,6 @@ export class DraupnirBotModeToggle implements BotModeTogle {
|
||||
}
|
||||
}
|
||||
}
|
||||
this.stopSafeModeDraupnir();
|
||||
return draupnirResult;
|
||||
}
|
||||
public async switchToSafeMode(
|
||||
@@ -239,18 +255,8 @@ export class DraupnirBotModeToggle implements BotModeTogle {
|
||||
): Promise<Result<Draupnir | SafeModeDraupnir>> {
|
||||
const draupnirResult = await this.switchToDraupnir(options ?? {});
|
||||
if (isError(draupnirResult)) {
|
||||
if (this.config.safeMode?.bootIntoOnStartupFailure) {
|
||||
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 ?? {}
|
||||
);
|
||||
if (draupnirResult.error instanceof DraupnirRestartError) {
|
||||
return Ok(draupnirResult.error.safeModeDraupnir);
|
||||
} else {
|
||||
return draupnirResult;
|
||||
}
|
||||
@@ -258,6 +264,27 @@ export class DraupnirBotModeToggle implements BotModeTogle {
|
||||
return draupnirResult;
|
||||
}
|
||||
|
||||
public async maybeRecoverWithSafeMode(
|
||||
error: ResultError,
|
||||
options?: SafeModeToggleOptions | undefined
|
||||
): Promise<Result<SafeModeDraupnir>> {
|
||||
if (this.config.safeMode?.bootIntoOnStartupFailure) {
|
||||
log.error(
|
||||
"Failed to start draupnir, switching to safe mode as configured",
|
||||
error
|
||||
);
|
||||
return await this.switchToSafeMode(
|
||||
{
|
||||
reason: SafeModeReason.InitializationError,
|
||||
error: error,
|
||||
},
|
||||
options ?? {}
|
||||
);
|
||||
} else {
|
||||
return Err(error);
|
||||
}
|
||||
}
|
||||
|
||||
public async encryptionInitialized(): Promise<void> {
|
||||
if (this.draupnir !== null) {
|
||||
try {
|
||||
|
||||
@@ -2,13 +2,29 @@
|
||||
//
|
||||
// SPDX-License-Identifier: AFL-3.0
|
||||
|
||||
import { Result } from "@gnuxie/typescript-result";
|
||||
import { Err, Result, ResultError } from "@gnuxie/typescript-result";
|
||||
import { Draupnir } from "../Draupnir";
|
||||
import { SafeModeDraupnir } from "./DraupnirSafeMode";
|
||||
import { SafeModeCause } from "./SafeModeCause";
|
||||
|
||||
export type SafeModeToggleOptions = { sendStatusOnStart?: boolean };
|
||||
|
||||
export class DraupnirRestartError extends ResultError {
|
||||
constructor(
|
||||
message: string,
|
||||
public readonly safeModeDraupnir: SafeModeDraupnir
|
||||
) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public static Result(
|
||||
message: string,
|
||||
options: { safeModeDraupnir: SafeModeDraupnir }
|
||||
): Result<never> {
|
||||
return Err(new DraupnirRestartError(message, options.safeModeDraupnir));
|
||||
}
|
||||
}
|
||||
|
||||
export interface SafeModeToggle {
|
||||
/**
|
||||
* Switch the bot to Draupnir mode.
|
||||
@@ -17,7 +33,9 @@ export interface SafeModeToggle {
|
||||
* That means that by the command responds with ticks and crosses,
|
||||
* draupnir will be running or we will still be in safe mode.
|
||||
*/
|
||||
switchToDraupnir(options?: SafeModeToggleOptions): Promise<Result<Draupnir>>;
|
||||
switchToDraupnir(
|
||||
options?: SafeModeToggleOptions
|
||||
): Promise<Result<Draupnir, DraupnirRestartError | ResultError>>;
|
||||
switchToSafeMode(
|
||||
cause: SafeModeCause,
|
||||
options?: SafeModeToggleOptions
|
||||
|
||||
Reference in New Issue
Block a user