refactor: Add SessionManager and Session classes to electron
This commit is contained in:
5 files changed
+157
-49
No files matched your search
@@ -1,46 +1,12 @@
|
||||
const path = require('path');
|
||||
const { spawnAsyncJSONPromise, spawnSync } = require('./spawn-promise');
|
||||
const origin = require('./origin.js');
|
||||
const { spawnSync } = require('./spawn-promise');
|
||||
|
||||
const cliPath = async () => path.resolve(__dirname, '..', 'cli', 'boundary');
|
||||
|
||||
/**
|
||||
* Super paranoid shell quote/escape and validation. Input must be base62.
|
||||
* @param {string} str
|
||||
*/
|
||||
const escapeAndValidateBase62 = (str) => {
|
||||
const candidate = str.toString();
|
||||
if (candidate.match(/^[A-Za-z0-9_]*$/)) return candidate;
|
||||
throw new Error(`
|
||||
Could not invoke command:
|
||||
input contained unsafe characters.
|
||||
`);
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
// Check boundary cli existence
|
||||
exists: () => Boolean(cliPath()),
|
||||
|
||||
// Initiate connection and return output
|
||||
connect: (target_id, token, host_id) => {
|
||||
const addr = origin.origin;
|
||||
const sanitized = {
|
||||
target_id: escapeAndValidateBase62(target_id),
|
||||
token: escapeAndValidateBase62(token),
|
||||
};
|
||||
if (host_id) sanitized.host_id = escapeAndValidateBase62(host_id);
|
||||
const command = [
|
||||
'connect',
|
||||
`-target-id=${sanitized.target_id}`,
|
||||
`-token=${sanitized.token}`,
|
||||
`-addr=${addr}`,
|
||||
'-format=json',
|
||||
];
|
||||
|
||||
if (host_id) command.push(`-host-id=${sanitized.host_id}`);
|
||||
return spawnAsyncJSONPromise(command);
|
||||
},
|
||||
|
||||
// Returns JSON-formatted version information from the CLI
|
||||
version: () => {
|
||||
const command = ['-v'];
|
||||
|
||||
@@ -3,7 +3,7 @@ const isDev = require('electron-is-dev');
|
||||
const handle = require('./ipc-handler');
|
||||
const boundaryCli = require('./boundary-cli');
|
||||
const origin = require('./origin');
|
||||
const spawnSession = require('./spawn-session');
|
||||
const sessionManager = require('./session/manager');
|
||||
|
||||
/**
|
||||
* Returns the current runtime origin, which is used by the main thread to
|
||||
@@ -57,12 +57,13 @@ handle('cliExists', () => boundaryCli.exists());
|
||||
* Establishes a boundary session and returns session details.
|
||||
*/
|
||||
handle('connect', ({ target_id, token, host_id }) =>
|
||||
boundaryCli.connect(target_id, token, host_id)
|
||||
sessionManager.start(origin.origin, target_id, token, host_id)
|
||||
);
|
||||
|
||||
/**
|
||||
* Cancel an established boundary session spawned process.
|
||||
*/
|
||||
handle('cancel', ({ session_id }) => {
|
||||
spawnSession.cancelSession(session_id);
|
||||
});
|
||||
handle('cancel', ({ session_id }) =>
|
||||
// spawnSession.cancelSession(session_id);
|
||||
sessionManager.stop(session_id)
|
||||
);
|
||||
@@ -0,0 +1,99 @@
|
||||
const { spawnAsyncJSONPromise } = require('../spawn-promise');
|
||||
|
||||
// FIXME create structure 'util' folder for spawn-promise
|
||||
|
||||
/**
|
||||
* Super paranoid shell quote/escape and validation. Input must be base62.
|
||||
* @param {string} str
|
||||
*/
|
||||
const escapeAndValidateBase62 = (str) => {
|
||||
const candidate = str.toString();
|
||||
if (candidate.match(/^[A-Za-z0-9_]*$/)) return candidate;
|
||||
throw new Error(`
|
||||
Could not invoke command:
|
||||
input contained unsafe characters.
|
||||
`);
|
||||
};
|
||||
|
||||
class Session {
|
||||
#id;
|
||||
#pid;
|
||||
#addr;
|
||||
#token;
|
||||
#hostId;
|
||||
#targetId;
|
||||
#proxyDetails;
|
||||
|
||||
/**
|
||||
* Initialize a session to a controller address
|
||||
* using target details.
|
||||
* @param {string} addr
|
||||
* @param {string} targetId
|
||||
* @param {string} token
|
||||
* @param {string} hostId
|
||||
*/
|
||||
constructor(addr, targetId, token, hostId) {
|
||||
this.#addr = addr;
|
||||
this.#targetId = targetId;
|
||||
this.#token = token;
|
||||
this.#hostId = hostId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {boolean}
|
||||
*/
|
||||
get isActive() {
|
||||
return Boolean(this.#pid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns session proxy details.
|
||||
* Only available after successful start of a session.
|
||||
* @return {object}
|
||||
*/
|
||||
get proxyDetails() {
|
||||
return this.#proxyDetails;
|
||||
}
|
||||
|
||||
// Spawn process
|
||||
// Track spawned process this.pid = pid;
|
||||
/**
|
||||
* Using cli, initialize a session to a target.
|
||||
* Tracks local proxy details if successful.
|
||||
*/
|
||||
start() {
|
||||
const command = this.cliCommand();
|
||||
return spawnAsyncJSONPromise(command).then((spawnedSession) => {
|
||||
this.#id = this.#proxyDetails.session_id;
|
||||
this.#pid = spawnedSession.childProcess.pid;
|
||||
this.#proxyDetails = spawnedSession.response;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate cli command for session.
|
||||
* @returns {[]}
|
||||
*/
|
||||
cliCommand() {
|
||||
const sanitized = {
|
||||
target_id: escapeAndValidateBase62(this.#targetId),
|
||||
token: escapeAndValidateBase62(this.#token),
|
||||
};
|
||||
|
||||
const command = [
|
||||
'connect',
|
||||
`-target-id=${sanitized.target_id}`,
|
||||
`-token=${sanitized.token}`,
|
||||
`-addr=${this.#addr}`,
|
||||
'-format=json',
|
||||
];
|
||||
|
||||
if (this.#hostId) {
|
||||
sanitized.host_id = escapeAndValidateBase62(this.#hostId);
|
||||
command.push(`-host-id=${sanitized.host_id}`);
|
||||
}
|
||||
return command;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Session;
|
||||
@@ -0,0 +1,39 @@
|
||||
const Session = require('./index.js');
|
||||
|
||||
class SessionManager {
|
||||
#sessions;
|
||||
|
||||
constructor() {
|
||||
this.#sessions = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Start a session and track it.
|
||||
* Returns session proxy details if successfully started.
|
||||
* Only successfully started sessions will be tracked.
|
||||
* @param {string} addr
|
||||
* @param {string} target_id
|
||||
* @param {string} token
|
||||
* @param {string} host_id
|
||||
*/
|
||||
start(addr, target_id, token, host_id) {
|
||||
const session = new Session(addr, target_id, token, host_id);
|
||||
return session.start().then(() => {
|
||||
this.#sessions.push(session);
|
||||
return session.proxyDetails;
|
||||
});
|
||||
}
|
||||
|
||||
stopById() {
|
||||
}
|
||||
|
||||
stopAll() {
|
||||
}
|
||||
|
||||
get sessions() {
|
||||
return this.#sessions;
|
||||
}
|
||||
}
|
||||
|
||||
const sessionManager = new SessionManager();
|
||||
module.exports = sessionManager;
|
||||
@@ -47,25 +47,28 @@ module.exports = {
|
||||
outputStream += data.toString();
|
||||
const jsonData = jsonify(outputStream);
|
||||
if (jsonData) {
|
||||
if (jsonData.termination_reason) {
|
||||
spawnSession.cancelProcess(childProcess.pid);
|
||||
} else {
|
||||
// Track only successfully launched child processes
|
||||
spawnSession.add({ childProcess, data: jsonData });
|
||||
}
|
||||
outputStream = '';
|
||||
resolve(jsonData);
|
||||
// if (jsonData.termination_reason) {
|
||||
// spawnSession.cancelProcess(childProcess.pid);
|
||||
// } else {
|
||||
// // Track only successfully launched child processes
|
||||
// spawnSession.add({ childProcess, data: jsonData });
|
||||
// }
|
||||
// FIXME
|
||||
// outputStream = '';
|
||||
resolve({ childProcess, response: jsonData });
|
||||
}
|
||||
});
|
||||
|
||||
// @todo Cancel spawned session childprocess on error? Does it get automatically cancelled?
|
||||
// @todo on error - should childprocess be closed?
|
||||
// Test on connection limit errors especially
|
||||
childProcess.stderr.on('data', (data) => {
|
||||
errorStream += data.toString();
|
||||
const jsonData = jsonify(errorStream);
|
||||
if (jsonData) {
|
||||
const error = jsonData.api_error || jsonData.error;
|
||||
errorStream = '';
|
||||
// FIXME
|
||||
// errorStream = '';
|
||||
reject(new Error(error.message));
|
||||
}
|
||||
});
|
||||
|
||||
Reference in new issue
Block a user