openclaw / src /plugin-state /plugin-state.worker.ts
SaylorTwift's picture
SaylorTwift HF Staff
Add files using upload-large-folder tool
76289e7 verified
Raw
History Blame Contribute Delete
6.54 kB
import { err, ok } from "@openclaw/normalization-core/result";
import type { SqliteWorkerCommand } from "../infra/sqlite-worker-contract.js";
import { captureOpenClawStateDatabaseReadAdmission } from "../state/openclaw-state-db-cache.js";
import type {
OpenClawStateDatabase,
OpenClawStateDatabaseOptions,
} from "../state/openclaw-state-db-contract.js";
import { runOpenClawStateWriteTransaction } from "../state/openclaw-state-db.js";
import {
compareAndApplyPluginStateEntry,
observePluginStateEntry,
} from "./plugin-state-store.comparison.js";
import { registerPluginStateSequencedJournalEntryInDatabase } from "./plugin-state-store.journal.js";
import {
countLivePluginStateNamespaceEntries,
deletePluginStateEntry,
lookupPluginStateEntry,
registerPluginStateEntry,
} from "./plugin-state-store.kernel.js";
import {
clearPluginStateNamespace,
consumePluginStateEntry,
deletePluginStateEntryIfEqual,
registerPluginStateEntryIfAbsent,
} from "./plugin-state-store.mutations.js";
import {
listPluginStateEntries,
listPluginStateEntriesInKeyRange,
lookupPluginStateEntries,
} from "./plugin-state-store.reads.js";
import {
withPluginStateDatabaseReadOnly,
wrapPluginStateError,
} from "./plugin-state-store.sqlite.js";
import {
type PluginStateWorkerOperations,
pluginStateWorkerOperations,
} from "./plugin-state-worker-contract.js";
import { capturePluginStateWorkerFailure } from "./plugin-state-worker-errors.js";
export function executePluginStateCommand(
command: SqliteWorkerCommand<PluginStateWorkerOperations>,
options: OpenClawStateDatabaseOptions & { path: string },
openDatabase: () => OpenClawStateDatabase,
hasRetainedDatabase: boolean,
): PluginStateWorkerOperations[keyof PluginStateWorkerOperations]["output"] {
const description = pluginStateWorkerOperations[command.type];
if (
command.type === "pluginState.lookup" ||
command.type === "pluginState.lookupMany" ||
command.type === "pluginState.entries" ||
command.type === "pluginState.entriesInKeyRange" ||
command.type === "pluginState.count"
) {
try {
switch (command.type) {
case "pluginState.lookup":
return ok(
withPluginStateDatabaseReadOnly(
"lookup",
(store) => lookupPluginStateEntry(store, command.input),
options,
),
);
case "pluginState.lookupMany": {
const rows =
withPluginStateDatabaseReadOnly(
"lookup",
(store) => lookupPluginStateEntries(store, command.input),
options,
) ?? command.input.keys.map(() => ok(undefined));
return ok(
rows.map((row) => (row.ok ? row : err(capturePluginStateWorkerFailure(row.error)))),
);
}
case "pluginState.entriesInKeyRange":
return ok(
withPluginStateDatabaseReadOnly(
"entries",
(store) => listPluginStateEntriesInKeyRange(store, command.input),
options,
) ?? [],
);
case "pluginState.entries":
return ok(
withPluginStateDatabaseReadOnly(
"entries",
(store) => listPluginStateEntries(store, command.input),
options,
) ?? [],
);
case "pluginState.count":
return ok(
withPluginStateDatabaseReadOnly(
"count",
({ db }) =>
countLivePluginStateNamespaceEntries(db, {
...command.input,
now: Date.now(),
}),
options,
) ?? 0,
);
}
} catch (error) {
return err(
capturePluginStateWorkerFailure(
wrapPluginStateError(
error,
description.operation,
description.code,
description.message,
options.path,
),
),
);
}
}
let database: OpenClawStateDatabase;
try {
database = openDatabase();
} catch (error) {
return err(
capturePluginStateWorkerFailure(
wrapPluginStateError(
error,
description.operation,
hasRetainedDatabase ? description.code : "PLUGIN_STATE_OPEN_FAILED",
hasRetainedDatabase ? description.message : "Failed to open the plugin state database.",
options.path,
),
),
);
}
try {
return ok(
runOpenClawStateWriteTransaction(
(store) => {
switch (command.type) {
case "pluginState.appendJournal":
return registerPluginStateSequencedJournalEntryInDatabase(store, command.input);
case "pluginState.observe":
return observePluginStateEntry(
store,
command.input,
captureOpenClawStateDatabaseReadAdmission(store.path).identity.key,
);
case "pluginState.compareUpdate":
case "pluginState.compareDelete":
return compareAndApplyPluginStateEntry(
store,
command.input,
captureOpenClawStateDatabaseReadAdmission(store.path).identity.key,
);
case "pluginState.register":
return registerPluginStateEntry(store, command.input, command.input.maxPluginEntries);
case "pluginState.registerIfAbsent":
return registerPluginStateEntryIfAbsent(
store,
command.input,
command.input.maxPluginEntries,
);
case "pluginState.deleteIfEqual":
return deletePluginStateEntryIfEqual(store, command.input);
case "pluginState.consume":
return consumePluginStateEntry(store, command.input);
case "pluginState.delete":
return deletePluginStateEntry(store.db, command.input) > 0;
case "pluginState.clear":
return clearPluginStateNamespace(store.db, command.input);
default:
throw new Error("Plugin-state read command entered its write path");
}
},
{ ...options, database },
),
);
} catch (error) {
return err(
capturePluginStateWorkerFailure(
wrapPluginStateError(
error,
description.operation,
description.code,
description.message,
options.path,
),
),
);
}
}