implement recovery from changed token

use exponential backoff for token retrieval
This commit is contained in:
2025-11-19 21:15:27 +00:00
parent 3de168210c
commit a86f89fefc
4 changed files with 57 additions and 6 deletions

View File

@@ -1,4 +1,5 @@
import type { BodyInit } from "bun";
import { backOff } from "exponential-backoff";
import type z from "zod";
import { encryptPassword } from "@/encryption";
import { logger } from "@/logger";
@@ -30,7 +31,21 @@ export class NanoKVMClient {
return;
}
this.loginAndSetToken();
await this.initAuth();
}
async initAuth() {
logger.info("Initializing auth...");
await backOff(async () => await this.loginAndSetToken(), {
numOfAttempts: 50,
retry: (_, attempt) => {
logger.info(`Retrying for the ${attempt} time`);
return true;
},
startingDelay: 100,
});
}
async fetch(path: string, method?: "POST" | "GET", body?: BodyInit) {
@@ -75,15 +90,19 @@ export class NanoKVMClient {
return;
}
case -2: {
logger.fatal(`Invalid password! Failed to get token.`);
logger.fatal(
`Invalid password! Failed to get token for ${this.options.host}`,
);
return;
throw new Error("Failed to get token!");
}
default: {
logger.fatal(
"Unknown error while getting token.",
(result as z.output<typeof AuthLoginSchema>).msg,
);
throw new Error("Failed to get token!");
}
}
}

View File

@@ -1,4 +1,5 @@
import type z from "zod";
import z from "zod";
import { logger } from "@/logger";
import { NanoKVMClient } from "./nano-kvm-client";
import {
type GpioSchema,
@@ -26,7 +27,20 @@ export class NanoKVMService {
async getInfo(): Promise<z.output<typeof InfoSchema>> {
const data = await (await this.client.fetch("/api/vm/info", "GET")).json();
return InfoSuccess.parse(data).data;
const result = InfoSuccess.safeParse(data);
if (!result.success) {
logger.error(data);
logger.fatal(`Failed getting info: `, z.prettifyError(result.error));
if (data === "unauthorized") {
await this.client.initAuth();
}
throw result.error;
}
return result.data.data;
}
async getGpio(): Promise<z.output<typeof GpioSchema>> {
@@ -34,7 +48,20 @@ export class NanoKVMService {
const data = await response.json();
return GpioSuccess.parse(data).data;
const result = GpioSuccess.safeParse(data);
if (!result.success) {
logger.error(data);
logger.fatal(`Failed getting gpio: `, z.prettifyError(result.error));
if (data === "unauthorized") {
await this.client.initAuth();
}
throw result.error;
}
return result.data.data;
}
async triggerPower(input: z.input<typeof TriggerPowerInput>) {