mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-26 10:21:52 +00:00
256 lines
7.5 KiB
JavaScript
256 lines
7.5 KiB
JavaScript
import Deno from "/deno_global.js";
|
|
import * as mainModule from "/embassy.js";
|
|
|
|
function requireParam(param) {
|
|
throw new Error(`Missing required parameter ${param}`);
|
|
}
|
|
|
|
/**
|
|
* This is using the simplified json pointer spec, using no escapes and arrays
|
|
* @param {object} obj
|
|
* @param {string} pointer
|
|
* @returns
|
|
*/
|
|
function jsonPointerValue(obj, pointer) {
|
|
const paths = pointer.substring(1).split("/");
|
|
for (const path of paths) {
|
|
if (obj == null) {
|
|
return null;
|
|
}
|
|
obj = (obj || {})[path];
|
|
}
|
|
return obj;
|
|
}
|
|
|
|
function maybeDate(value) {
|
|
if (!value) return value;
|
|
return new Date(value);
|
|
}
|
|
const writeFile = (
|
|
{
|
|
path = requireParam("path"),
|
|
volumeId = requireParam("volumeId"),
|
|
toWrite = requireParam("toWrite"),
|
|
} = requireParam("options"),
|
|
) => Deno.core.opAsync("write_file", volumeId, path, toWrite);
|
|
|
|
const readFile = (
|
|
{ volumeId = requireParam("volumeId"), path = requireParam("path") } = requireParam("options"),
|
|
) => Deno.core.opAsync("read_file", volumeId, path);
|
|
|
|
|
|
|
|
const runDaemon = (
|
|
{ command = requireParam("command"), args = [] } = requireParam("options"),
|
|
) => {
|
|
let id = Deno.core.opAsync("start_command", command, args, "inherit", null);
|
|
let processId = id.then(x => x.processId)
|
|
let waitPromise = null;
|
|
return {
|
|
processId,
|
|
async wait() {
|
|
waitPromise = waitPromise || Deno.core.opAsync("wait_command", await processId)
|
|
return waitPromise
|
|
},
|
|
async term(signal = 15) {
|
|
return Deno.core.opAsync("send_signal", await processId, 15)
|
|
}
|
|
}
|
|
};
|
|
const runCommand = async (
|
|
{ command = requireParam("command"), args = [], timeoutMillis = 30000 } = requireParam("options"),
|
|
) => {
|
|
let id = Deno.core.opAsync("start_command", command, args, "collect", timeoutMillis);
|
|
let pid = id.then(x => x.processId)
|
|
return Deno.core.opAsync("wait_command", await pid)
|
|
};
|
|
const signalGroup = async (
|
|
{ gid = requireParam("gid"), signal = requireParam("signal") } = requireParam("gid and signal")
|
|
) => {
|
|
return Deno.core.opAsync("signal_group", gid, signal);
|
|
};
|
|
const sleep = (timeMs = requireParam("timeMs"),
|
|
) => Deno.core.opAsync("sleep", timeMs);
|
|
|
|
const rename = (
|
|
{
|
|
srcVolume = requireParam("srcVolume"),
|
|
dstVolume = requirePapram("dstVolume"),
|
|
srcPath = requireParam("srcPath"),
|
|
dstPath = requireParam("dstPath"),
|
|
} = requireParam("options"),
|
|
) => Deno.core.opAsync("rename", srcVolume, srcPath, dstVolume, dstPath);
|
|
const metadata = async (
|
|
{ volumeId = requireParam("volumeId"), path = requireParam("path") } = requireParam("options"),
|
|
) => {
|
|
const data = await Deno.core.opAsync("metadata", volumeId, path);
|
|
return {
|
|
...data,
|
|
modified: maybeDate(data.modified),
|
|
created: maybeDate(data.created),
|
|
accessed: maybeDate(data.accessed),
|
|
};
|
|
};
|
|
const removeFile = (
|
|
{ volumeId = requireParam("volumeId"), path = requireParam("path") } = requireParam("options"),
|
|
) => Deno.core.opAsync("remove_file", volumeId, path);
|
|
const isSandboxed = () => Deno.core.opSync("is_sandboxed");
|
|
|
|
const writeJsonFile = (
|
|
{
|
|
volumeId = requireParam("volumeId"),
|
|
path = requireParam("path"),
|
|
toWrite = requireParam("toWrite"),
|
|
} = requireParam("options"),
|
|
) =>
|
|
writeFile({
|
|
volumeId,
|
|
path,
|
|
toWrite: JSON.stringify(toWrite),
|
|
});
|
|
|
|
const chown = async (
|
|
{
|
|
volumeId = requireParam("volumeId"),
|
|
path = requireParam("path"),
|
|
uid = requireParam("uid"),
|
|
} = requireParam("options"),
|
|
) => {
|
|
return await Deno.core.opAsync("chown", volumeId, path, uid);
|
|
};
|
|
|
|
const chmod = async (
|
|
{
|
|
volumeId = requireParam("volumeId"),
|
|
path = requireParam("path"),
|
|
mode = requireParam("mode"),
|
|
} = requireParam("options"),
|
|
) => {
|
|
return await Deno.core.opAsync("chmod", volumeId, path, mode);
|
|
};
|
|
const readJsonFile = async (
|
|
{ volumeId = requireParam("volumeId"), path = requireParam("path") } = requireParam("options"),
|
|
) => JSON.parse(await readFile({ volumeId, path }));
|
|
const createDir = (
|
|
{ volumeId = requireParam("volumeId"), path = requireParam("path") } = requireParam("options"),
|
|
) => Deno.core.opAsync("create_dir", volumeId, path);
|
|
|
|
const readDir = (
|
|
{ volumeId = requireParam("volumeId"), path = requireParam("path") } = requireParam("options"),
|
|
) => Deno.core.opAsync("read_dir", volumeId, path);
|
|
const removeDir = (
|
|
{ volumeId = requireParam("volumeId"), path = requireParam("path") } = requireParam("options"),
|
|
) => Deno.core.opAsync("remove_dir", volumeId, path);
|
|
const trace = (whatToTrace = requireParam('whatToTrace')) => Deno.core.opAsync("log_trace", whatToTrace);
|
|
const warn = (whatToTrace = requireParam('whatToTrace')) => Deno.core.opAsync("log_warn", whatToTrace);
|
|
const error = (whatToTrace = requireParam('whatToTrace')) => Deno.core.opAsync("log_error", whatToTrace);
|
|
const debug = (whatToTrace = requireParam('whatToTrace')) => Deno.core.opAsync("log_debug", whatToTrace);
|
|
const info = (whatToTrace = requireParam('whatToTrace')) => Deno.core.opAsync("log_info", whatToTrace);
|
|
const fetch = async (url = requireParam ('url'), options = null) => {
|
|
const { body, ...response } = await Deno.core.opAsync("fetch", url, options);
|
|
const textValue = Promise.resolve(body);
|
|
return {
|
|
...response,
|
|
text() {
|
|
return textValue;
|
|
},
|
|
json() {
|
|
return textValue.then((x) => JSON.parse(x));
|
|
},
|
|
};
|
|
};
|
|
|
|
const runRsync = (
|
|
{
|
|
srcVolume = requireParam("srcVolume"),
|
|
dstVolume = requireParam("dstVolume"),
|
|
srcPath = requireParam("srcPath"),
|
|
dstPath = requireParam("dstPath"),
|
|
options = requireParam("options"),
|
|
} = requireParam("options"),
|
|
) => {
|
|
let id = Deno.core.opAsync("rsync", srcVolume, srcPath, dstVolume, dstPath, options);
|
|
let waitPromise = null;
|
|
return {
|
|
async id() {
|
|
return id
|
|
},
|
|
async wait() {
|
|
waitPromise = waitPromise || Deno.core.opAsync("rsync_wait", await id)
|
|
return waitPromise
|
|
},
|
|
async progress() {
|
|
return Deno.core.opAsync("rsync_progress", await id)
|
|
}
|
|
}
|
|
};
|
|
|
|
const diskUsage = async ({
|
|
volumeId = requireParam("volumeId"),
|
|
path = requireParam("path"),
|
|
} = { volumeId: null, path: null }) => {
|
|
const [used, total] = await Deno.core.opAsync("disk_usage", volumeId, path);
|
|
return { used, total }
|
|
}
|
|
|
|
const callbackMapping = {}
|
|
const registerCallback = (fn) => {
|
|
const uuid = generateUuid(); // TODO
|
|
callbackMapping[uuid] = fn;
|
|
return uuid
|
|
}
|
|
const runCallback = (uuid, data) => callbackMapping[uuid](data)
|
|
|
|
const getServiceConfig = async (serviceId, configPath, onChange) => {
|
|
await Deno.core.opAsync("get_service_config", serviceId, configPath, registerCallback(onChange))
|
|
}
|
|
|
|
const currentFunction = Deno.core.opSync("current_function");
|
|
const input = Deno.core.opSync("get_input");
|
|
const variable_args = Deno.core.opSync("get_variable_args");
|
|
const setState = (x) => Deno.core.opSync("set_value", x);
|
|
const effects = {
|
|
chmod,
|
|
chown,
|
|
writeFile,
|
|
readFile,
|
|
writeJsonFile,
|
|
readJsonFile,
|
|
error,
|
|
warn,
|
|
debug,
|
|
trace,
|
|
info,
|
|
isSandboxed,
|
|
fetch,
|
|
removeFile,
|
|
createDir,
|
|
removeDir,
|
|
metadata,
|
|
rename,
|
|
runCommand,
|
|
sleep,
|
|
runDaemon,
|
|
signalGroup,
|
|
runRsync,
|
|
readDir,
|
|
diskUsage,
|
|
getServiceConfig,
|
|
};
|
|
|
|
const defaults = {
|
|
"handleSignal": (effects, { gid, signal }) => {
|
|
return effects.signalGroup({ gid, signal })
|
|
}
|
|
}
|
|
|
|
const runFunction = jsonPointerValue(mainModule, currentFunction) || jsonPointerValue(defaults, currentFunction);
|
|
(async () => {
|
|
if (typeof runFunction !== "function") {
|
|
error(`Expecting ${currentFunction} to be a function`);
|
|
throw new Error(`Expecting ${currentFunction} to be a function`);
|
|
}
|
|
const answer = await runFunction(effects, input, ...variable_args);
|
|
setState(answer);
|
|
})();
|