mirror of
https://github.com/Termix-SSH/Termix.git
synced 2026-10-29 06:35:24 +00:00
fix: finish 2.9.0 plugin moves and get every check green
This commit is contained in:
1 parent
8c1e02af89
commit
6489b62ece
335 files changed
+29878
-17749
No files matched your search
@@ -9,6 +9,12 @@ import type { PluginContext, PluginSshHost } from "@termix/plugin-sdk/backend";
|
||||
import { getErrorMessage } from "./error-message.js";
|
||||
import { setPluginSsh, pluginSsh } from "./ssh.js";
|
||||
import { setPluginCtx } from "./plugin-ctx.js";
|
||||
import {
|
||||
flushTransferProfiles,
|
||||
setTransferProfileStore,
|
||||
} from "./transfer-tuning.js";
|
||||
|
||||
const TRANSFER_PROFILES_KEY = "transfer-profiles";
|
||||
import { AuthManager } from "../../../../src/backend/utils/auth-manager.js";
|
||||
import { logger } from "../../../../src/backend/utils/logger.js";
|
||||
import {
|
||||
@@ -113,6 +119,14 @@ export async function activate(ctx: PluginContext) {
|
||||
setPluginCtx(ctx);
|
||||
ctx.disposables.add(() => setPluginSsh(null));
|
||||
ctx.disposables.add(() => setPluginCtx(null));
|
||||
setTransferProfileStore({
|
||||
read: () => ctx.kv.get(TRANSFER_PROFILES_KEY),
|
||||
write: (value) => ctx.kv.set(TRANSFER_PROFILES_KEY, value),
|
||||
});
|
||||
ctx.disposables.add(async () => {
|
||||
await flushTransferProfiles();
|
||||
setTransferProfileStore(null);
|
||||
});
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
// ctx.db.define hands back an untyped table object; typed at this module's
|
||||
@@ -605,7 +619,11 @@ export async function activate(ctx: PluginContext) {
|
||||
};
|
||||
resolvedTerminalConfig = resolvedHost.terminalConfig as unknown as
|
||||
Record<string, unknown> | undefined;
|
||||
resolvedScpLegacy = resolvedHost.scpLegacy ?? false;
|
||||
resolvedScpLegacy =
|
||||
(await ctx.settings.getHost<boolean>(
|
||||
Number(resolvedHost.id),
|
||||
"scpLegacy",
|
||||
)) === true;
|
||||
if (resolvedHost.useSocks5) {
|
||||
resolvedUseSocks5 = resolvedHost.useSocks5;
|
||||
resolvedSocks5Host = resolvedHost.socks5Host;
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
// TODO(file-manager): move this to ctx.kv, see FINISH-LIST.md
|
||||
import { createHash } from "node:crypto";
|
||||
import { promises as fs } from "node:fs";
|
||||
import path from "node:path";
|
||||
|
||||
export interface TransferPerformanceProfile {
|
||||
throughputBps: number;
|
||||
@@ -32,15 +29,32 @@ const MB = 1024 * 1024;
|
||||
const PROFILE_TTL_MS = 7 * 24 * 60 * 60 * 1000;
|
||||
const MAX_PROFILES = 128;
|
||||
const STORE_VERSION = 1;
|
||||
const STORE_FILENAME = "adaptive-transfer-profiles.json";
|
||||
const profiles = new Map<string, TransferPerformanceProfile>();
|
||||
const directRoutes = new Map<string, DirectRouteProfile>();
|
||||
let loadedPath: string | undefined;
|
||||
|
||||
/** Where the learned profiles live: ctx.kv, set on activate. */
|
||||
export interface TransferProfileStore {
|
||||
read: () => Promise<unknown>;
|
||||
write: (value: PersistedProfiles) => Promise<void>;
|
||||
}
|
||||
|
||||
let store: TransferProfileStore | null = null;
|
||||
let loadedStore: TransferProfileStore | null = null;
|
||||
let loadPromise: Promise<void> | undefined;
|
||||
|
||||
export function setTransferProfileStore(
|
||||
next: TransferProfileStore | null,
|
||||
): void {
|
||||
store = next;
|
||||
loadedStore = null;
|
||||
loadPromise = undefined;
|
||||
profiles.clear();
|
||||
directRoutes.clear();
|
||||
}
|
||||
let persistTimer: ReturnType<typeof setTimeout> | undefined;
|
||||
let persistPromise = Promise.resolve();
|
||||
|
||||
interface PersistedProfiles {
|
||||
export interface PersistedProfiles {
|
||||
version: typeof STORE_VERSION;
|
||||
profiles: Record<string, TransferPerformanceProfile>;
|
||||
directRoutes: Record<string, DirectRouteProfile>;
|
||||
@@ -68,12 +82,6 @@ function validDirectRoute(value: unknown): value is DirectRouteProfile {
|
||||
);
|
||||
}
|
||||
|
||||
function storePath(): string {
|
||||
const dataDir =
|
||||
process.env.DATA_DIR || path.join(process.cwd(), "db", "data");
|
||||
return path.join(dataDir, STORE_FILENAME);
|
||||
}
|
||||
|
||||
function profileId(key: string): string {
|
||||
return createHash("sha256").update(key).digest("hex");
|
||||
}
|
||||
@@ -117,22 +125,15 @@ function trimProfiles(now = Date.now()): void {
|
||||
|
||||
async function persistProfiles(): Promise<void> {
|
||||
trimProfiles();
|
||||
const target = storePath();
|
||||
const temporary = `${target}.${process.pid}.tmp`;
|
||||
const payload: PersistedProfiles = {
|
||||
version: STORE_VERSION,
|
||||
profiles: Object.fromEntries(profiles),
|
||||
directRoutes: Object.fromEntries(directRoutes),
|
||||
};
|
||||
if (!store) return;
|
||||
try {
|
||||
await fs.mkdir(path.dirname(target), { recursive: true });
|
||||
await fs.writeFile(temporary, JSON.stringify(payload), {
|
||||
encoding: "utf8",
|
||||
mode: 0o600,
|
||||
await store.write({
|
||||
version: STORE_VERSION,
|
||||
profiles: Object.fromEntries(profiles),
|
||||
directRoutes: Object.fromEntries(directRoutes),
|
||||
});
|
||||
await fs.rename(temporary, target);
|
||||
} catch {
|
||||
await fs.rm(temporary, { force: true }).catch(() => {});
|
||||
// Learning data is a nicety; a failed write must not affect transfers.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,16 +147,16 @@ function queuePersist(): void {
|
||||
}
|
||||
|
||||
export async function initializeTransferProfiles(): Promise<void> {
|
||||
const target = storePath();
|
||||
if (loadedPath === target) return loadPromise;
|
||||
loadedPath = target;
|
||||
if (loadPromise && loadedStore === store) return loadPromise;
|
||||
loadedStore = store;
|
||||
const current = store;
|
||||
loadPromise = (async () => {
|
||||
profiles.clear();
|
||||
directRoutes.clear();
|
||||
if (!current) return;
|
||||
try {
|
||||
const parsed = JSON.parse(
|
||||
await fs.readFile(target, "utf8"),
|
||||
) as Partial<PersistedProfiles>;
|
||||
const parsed = ((await current.read()) ??
|
||||
{}) as Partial<PersistedProfiles>;
|
||||
if (parsed.version !== STORE_VERSION || !parsed.profiles) return;
|
||||
for (const [key, profile] of Object.entries(parsed.profiles)) {
|
||||
if (/^[a-f0-9]{64}$/.test(key) && validProfile(profile)) {
|
||||
@@ -381,7 +382,7 @@ export function getRecentDirectRouteDecision(
|
||||
export function clearTransferProfiles(): void {
|
||||
if (persistTimer) clearTimeout(persistTimer);
|
||||
persistTimer = undefined;
|
||||
loadedPath = undefined;
|
||||
loadedStore = null;
|
||||
loadPromise = undefined;
|
||||
profiles.clear();
|
||||
directRoutes.clear();
|
||||
|
||||
Reference in new issue
Block a user