mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-08-05 19:21:35 -07:00
99 lines
2.6 KiB
TypeScript
99 lines
2.6 KiB
TypeScript
import crypto from 'node:crypto';
|
|
import os from 'node:os';
|
|
import path from 'node:path';
|
|
|
|
export const SUBMINER_APP_CONTROL_SOCKET_ENV = 'SUBMINER_APP_CONTROL_SOCKET';
|
|
|
|
export interface AppControlSocketPathOptions {
|
|
configDir?: string;
|
|
env?: NodeJS.ProcessEnv;
|
|
platform?: NodeJS.Platform;
|
|
tmpDir?: string;
|
|
}
|
|
|
|
export interface AppControlRequest {
|
|
argv: string[];
|
|
}
|
|
|
|
export interface AppControlResponse {
|
|
ok: boolean;
|
|
error?: string;
|
|
}
|
|
|
|
function getUserKey(): string {
|
|
if (typeof process.getuid === 'function') {
|
|
return String(process.getuid());
|
|
}
|
|
try {
|
|
const user = os.userInfo();
|
|
if (typeof user.uid === 'number') {
|
|
return String(user.uid);
|
|
}
|
|
if (user.username) {
|
|
return user.username.replace(/[^\w.-]/g, '_');
|
|
}
|
|
} catch {
|
|
// Fall back below.
|
|
}
|
|
return 'user';
|
|
}
|
|
|
|
export function getAppControlSocketPath(options: AppControlSocketPathOptions = {}): string {
|
|
const env = options.env ?? process.env;
|
|
const override = env[SUBMINER_APP_CONTROL_SOCKET_ENV]?.trim();
|
|
if (override) return override;
|
|
|
|
const platform = options.platform ?? process.platform;
|
|
const identity = options.configDir?.trim() || 'default';
|
|
const digest = crypto.createHash('sha256').update(identity).digest('hex').slice(0, 16);
|
|
|
|
if (platform === 'win32') {
|
|
return `\\\\.\\pipe\\subminer-control-${digest}`;
|
|
}
|
|
|
|
return path.join(
|
|
options.tmpDir ?? os.tmpdir(),
|
|
`subminer-control-${getUserKey()}-${digest}.sock`,
|
|
);
|
|
}
|
|
|
|
export function encodeAppControlRequest(argv: string[]): string {
|
|
return `${JSON.stringify({ argv })}\n`;
|
|
}
|
|
|
|
export function encodeAppControlResponse(response: AppControlResponse): string {
|
|
return `${JSON.stringify(response)}\n`;
|
|
}
|
|
|
|
function normalizeArgv(value: unknown): string[] | null {
|
|
if (!Array.isArray(value) || value.length > 128) return null;
|
|
const argv: string[] = [];
|
|
for (const entry of value) {
|
|
if (typeof entry !== 'string' || entry.length > 8192) {
|
|
return null;
|
|
}
|
|
argv.push(entry);
|
|
}
|
|
return argv;
|
|
}
|
|
|
|
export function parseAppControlRequestLine(line: string): AppControlRequest {
|
|
const payload = JSON.parse(line) as { argv?: unknown };
|
|
const argv = normalizeArgv(payload.argv);
|
|
if (!argv) {
|
|
throw new Error('Invalid app-control argv payload');
|
|
}
|
|
return { argv };
|
|
}
|
|
|
|
export function parseAppControlResponseLine(line: string): AppControlResponse {
|
|
const payload = JSON.parse(line) as { ok?: unknown; error?: unknown };
|
|
if (payload.ok === true) {
|
|
return { ok: true };
|
|
}
|
|
return {
|
|
ok: false,
|
|
error: typeof payload.error === 'string' ? payload.error : 'App control command failed',
|
|
};
|
|
}
|