54 lines
2.3 KiB
JavaScript
54 lines
2.3 KiB
JavaScript
import { connect } from 'node:net';
|
|
import { BusError, PROJECT_SAVE_VERB, PROJECT_SAVE_REQUEST_MAX } from './broker.mjs';
|
|
export class Client {
|
|
constructor({ path, cap, human, tester, user, console: owner, timeout = 5000 }) {
|
|
this.path = path;
|
|
this.cap = cap;
|
|
this.human = human;
|
|
this.tester = tester;
|
|
this.user = user;
|
|
this.console = owner;
|
|
this.timeout = timeout;
|
|
}
|
|
call(verb, args = {}) {
|
|
const request =
|
|
JSON.stringify({
|
|
...(this.human ? { human: this.human } : this.tester ? { tester: this.tester } : this.user ? { user: this.user } : this.console ? { console: this.console } : { cap: this.cap }),
|
|
verb,
|
|
args,
|
|
}) + '\n';
|
|
if (Buffer.byteLength(request) > ([PROJECT_SAVE_VERB, 'library.file.save'].includes(verb) ? PROJECT_SAVE_REQUEST_MAX : 65536))
|
|
return Promise.reject(new BusError('request-too-large'));
|
|
return new Promise((resolve, reject) => {
|
|
const socket = connect(this.path);
|
|
let input = Buffer.alloc(0),
|
|
settled = false;
|
|
const end = (error, value) => {
|
|
if (settled) return;
|
|
settled = true;
|
|
socket.destroy();
|
|
error ? reject(error) : resolve(value);
|
|
};
|
|
socket.setTimeout(['processing.halt', 'processing.resume'].includes(verb) ? Math.max(this.timeout, 20000) : this.timeout, () => end(new BusError('outcome-unknown')));
|
|
socket.on('connect', () => socket.write(request));
|
|
socket.on('error', () => end(new BusError('outcome-unknown')));
|
|
socket.on('end', () => end(new BusError('outcome-unknown')));
|
|
socket.on('data', (b) => {
|
|
input = Buffer.concat([input, b]);
|
|
if (input.length > 4 * 1024 * 1024) return end(new BusError('response-too-large'));
|
|
if (!input.includes(10)) return;
|
|
try {
|
|
const r = JSON.parse(input.toString('utf8'));
|
|
if (r.ok === true) end(null, r.result);
|
|
else if (r.ok === false && typeof r.error === 'string' && /^[a-z-]{1,64}$/.test(r.error))
|
|
// Preserve a bounded reason when an explicitly scoped refusal has one.
|
|
end(new BusError(r.error, typeof r.reason === 'string' ? r.reason.slice(0, 300) : undefined));
|
|
else end(new BusError('invalid-response'));
|
|
} catch {
|
|
end(new BusError('invalid-response'));
|
|
}
|
|
});
|
|
});
|
|
}
|
|
}
|