UNPKG

@remote.it/core

Version:

Core remote.it JavasScript/TypeScript library

388 lines 16.4 kB
"use strict"; var __extends = (this && this.__extends) || (function () { var extendStatics = function (d, b) { extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; return extendStatics(d, b); }; return function (d, b) { extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); var __values = (this && this.__values) || function(o) { var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0; if (m) return m.call(o); if (o && typeof o.length === "number") return { next: function () { if (o && i >= o.length) o = void 0; return { value: o && o[i++], done: !o }; } }; throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined."); }; var __read = (this && this.__read) || function (o, n) { var m = typeof Symbol === "function" && o[Symbol.iterator]; if (!m) return o; var i = m.call(o), r, ar = [], e; try { while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); } catch (error) { e = { error: error }; } finally { try { if (r && !r.done && (m = i["return"])) m.call(i); } finally { if (e) throw e.error; } } return ar; }; var __spread = (this && this.__spread) || function () { for (var ar = [], i = 0; i < arguments.length; i++) ar = ar.concat(__read(arguments[i])); return ar; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); var debug_1 = __importDefault(require("debug")); var events_1 = require("events"); var d = debug_1.default('remoteit:ProcessManager'); var ProcessManager = /** @class */ (function (_super) { __extends(ProcessManager, _super); function ProcessManager() { var _this = _super !== null && _super.apply(this, arguments) || this; _this.processes = []; return _this; } ProcessManager.prototype.add = function (config) { this.emit('adding', config.uid); d('adding process', config); var process = this.newProcess(config); this.processes.push({ config: config, process: process, }); this.emit('added', config.uid); return process; }; /** * Start a new Service process and add it to the pool of existing * services. This will also watch the service process and keep it * running. */ ProcessManager.prototype.start = function (config) { this.emit('starting', config.uid); d('starting process:', config); // Find or create the service if missing. var existing = this.processes.find(function (p) { return p.config.uid === config.uid; }); var process = existing ? existing.process : this.add(config); // TODO: watch for events/changes and do things process.on('started', function () { return d('started process'); }); process.on('message', function (message) { return d('message', message); }); process.on('error', function (error) { return d('error', error); }); process.on('closed', function (code) { return d('closed', code); }); process.execute(); this.emit('started', config.uid); }; ProcessManager.prototype.restart = function (config) { var _this = this; var service = this.processes.find(function (p) { return p.config.uid === config.uid; }); if (!service) return; this.emit('restarting', config.uid); // Update the config in case it changed. this.processes[this.processes.indexOf(service)].config = config; // Once the process is closed, start a new one service.process.on('closed', function () { d('process closed'); service.process = _this.newProcess(config); _this.emit('restarted', config.uid); }); // Kill the process so we can start a fresh one service.process.kill(); }; ProcessManager.prototype.stop = function (uid) { var _this = this; this.emit('stopping', uid); var service = this.processes.find(function (p) { return p.config.uid === uid; }); if (!service) return; // Kill the running process service.process.kill(); service.process.on('closed', function () { // Remove from the list of proceesses _this.processes.splice(_this.processes.indexOf(service), 1); _this.emit('stopped', uid); }); }; ProcessManager.prototype.stopAll = function () { var _this = this; this.processes.map(function (p) { return _this.stop(p.config.uid); }); }; ProcessManager.prototype.update = function (latest) { var e_1, _a; var _this = this; if (latest === void 0) { latest = []; } latest = Array.isArray(latest) ? latest : [latest]; var prev = this.processes.map(function (p) { return p.config; }); var hadServices = prev && prev.length; var hasServices = latest && latest.length; // No services to stop and none to add if (!hadServices && !hasServices) return; // Had service(s) but now has none, stop all past services if (hadServices && !hasServices && prev) { this.stopAll(); } // Had no services before but now has them, so add all. if (!hadServices && hasServices && latest) { try { for (var latest_1 = __values(latest), latest_1_1 = latest_1.next(); !latest_1_1.done; latest_1_1 = latest_1.next()) { var service = latest_1_1.value; this.start(service); } } catch (e_1_1) { e_1 = { error: e_1_1 }; } finally { try { if (latest_1_1 && !latest_1_1.done && (_a = latest_1.return)) _a.call(latest_1); } finally { if (e_1) throw e_1.error; } } } if (hadServices && hasServices) { var current = latest; var previous = prev; var unchanged = this.filterUnchanged(current, previous); unchanged.map(function (s) { return _this.emit('unchanged', s.uid); }); var updated = this.filterUpdated(current, previous); updated.map(function (s) { return _this.restart(s); }); var added = this.filterAdded(current, previous); added.map(function (s) { return _this.start(s); }); var removed = this.filterRemoved(current, previous); removed.map(function (s) { return _this.stop(s.uid); }); } }; /** * Returns processes that have not changed since the previous configuration. */ ProcessManager.prototype.filterUnchanged = function (current, previous) { var _this = this; return current.reduce(function (matched, curr) { var matches = previous.filter(function (prev) { return _this.findUnchanged(prev, curr); }); if (matches.length) matched.push(curr); return matched; }, []); }; /** * Returns processes that were changed from the previous configuration * and need to be restarted. */ ProcessManager.prototype.filterUpdated = function (current, previous) { var others = __spread(this.filterUnchanged(current, previous), this.filterAdded(current, previous), this.filterRemoved(current, previous)); return current.reduce(function (matched, curr) { var match = others.find(function (o) { return curr.uid === o.uid; }); if (!match) matched.push(curr); return matched; }, []); }; /** * Returns processes that were not present in the previous configuration * so they can be started. */ ProcessManager.prototype.filterAdded = function (current, previous) { return current.reduce(function (matched, curr) { var matches = previous.filter(function (prev) { return curr.uid === prev.uid; }); if (!matches.length) matched.push(curr); return matched; }, []); }; /** * Returns processes that have been removed since the last configuration and * need to be stopped. */ ProcessManager.prototype.filterRemoved = function (current, previous) { return previous.reduce(function (matched, curr) { var matches = current.filter(function (prev) { return curr.uid === prev.uid; }); if (!matches.length) matched.push(curr); return matched; }, []); }; return ProcessManager; }(events_1.EventEmitter)); exports.ProcessManager = ProcessManager; // import { readFileSync } from 'fs' // import JSONFile from './JSONFile' // import { TargetConfig, InitiatorConfig, UserConfig } from './ConfigFile' // import { EventEmitter } from 'events' // export interface ConfigFile { // target?: TargetConfig | {} // initiators?: InitiatorConfig[] | [] // user?: UserConfig | {} // } // const emptyContent = { // target: {}, // initiators: [], // user: {}, // } // export default interface ProcessManager { // on(msg: 'target/added', cb: (target: TargetConfig) => void): this // on(msg: 'target/removed', cb: (target: TargetConfig) => void): this // on(msg: 'target/updated', cb: (target: TargetConfig) => void): this // on(msg: 'initiator/added', cb: (initiator: InitiatorConfig) => void): this // on(msg: 'initiator/removed', cb: (initiator: InitiatorConfig) => void): this // on(msg: 'initiator/updated', cb: (initiator: InitiatorConfig) => void): this // on(msg: 'initiator/unchanged', cb: (initiator: InitiatorConfig) => void): this // // on(msg: 'service/added', cb: () => void): this // // on(msg: 'service/removed', cb: () => void): this // // on(msg: 'service/updated', cb: () => void): this // emit(msg: 'target/added', target: TargetConfig): boolean // emit(msg: 'target/removed', target: TargetConfig): boolean // emit(msg: 'target/updated', target: TargetConfig): boolean // emit(msg: 'initiator/added', initiator: InitiatorConfig): boolean // emit(msg: 'initiator/removed', initiator: InitiatorConfig): boolean // emit(msg: 'initiator/updated', initiator: InitiatorConfig): boolean // emit(msg: 'initiator/unchanged', initiator: InitiatorConfig): boolean // // emit(msg: 'service/added', service: ServiceConfig): boolean // // emit(msg: 'service/removed', initiator: ServiceConfig): boolean // // emit(msg: 'service/updated', initiator: ServiceConfig): boolean // } // export default class ProcessManager extends EventEmitter { // private config: ConfigFile // private configFile: JSONFile<ConfigFile> // constructor(public configPath: string) { // super() // this.configFile = new JSONFile(configPath) // if (!this.configFile.exists) this.configFile.write(emptyContent) // this.config = this.configFile.read() // this.runProceesses(this.config, this.config) // } // update() { // const prev = this.config // const latest = this.configFile.read() // this.runProceesses(prev, latest) // this.config = latest // } // private runProceesses(prev: ConfigFile, latest: ConfigFile) { // this.runInitiators(prev, latest) // this.runTarget(prev, latest) // } // // TODO: Maybe abstract these away into their own InitiatorManager class then // // have ProcessManger handle any class that is a "Manager" class // private runInitiators(prev: ConfigFile, latest: ConfigFile) { // const hadInitiators = prev && prev.initiators && prev.initiators.length // const hasInitiators = // latest && latest.initiators && latest.initiators.length // // No initiators to stop and none to add // if (!hadInitiators && !hasInitiators) return // // Had initiator(s) but now has none, stop all past initiators // if (hadInitiators && !hasInitiators && prev.initiators) { // for (const initiator of prev.initiators) { // this.emit('initiator/removed', initiator) // } // } // // Had no initiators before but now has them, so add all. // if (!hadInitiators && hasInitiators && latest.initiators) { // for (const initiator of latest.initiators) { // this.emit('initiator/added', initiator) // } // } // if ( // hadInitiators && // hasInitiators && // prev.initiators && // latest.initiators // ) { // const current = latest.initiators // const previous = prev.initiators // const unchanged = this.filterUnchanged<InitiatorConfig>(current, previous) // unchanged.map(i => this.emit('initiator/unchanged', i)) // const updated = this.filterUpdated<InitiatorConfig>(current, previous) // updated.map(i => this.emit('initiator/updated', i)) // const added = this.filterAdded<InitiatorConfig>(current, previous) // added.map(i => this.emit('initiator/added', i)) // const removed = this.filterRemoved<InitiatorConfig>(current, previous) // removed.map(i => this.emit('initiator/removed', i)) // } // } // /** // * Returns processes that have not changed since the previous configuration. // */ // private filterUnchanged<T>( // current: InitiatorConfig[], // previous: InitiatorConfig[] // ): InitiatorConfig[] { // return current.reduce((matched: InitiatorConfig[], i: InitiatorConfig) => { // const matches = previous.filter( // p => i.uid === p.uid && i.hostname === p.hostname && i.port === p.port // ) // if (matches.length) matched.push(i) // return matched // }, []) // } // /** // * Returns processes that were changed from the previous configuration // * and need to be restarted. // */ // private filterUpdated<T>( // current: InitiatorConfig[], // previous: InitiatorConfig[] // ): InitiatorConfig[] { // const others = [ // ...this.filterUnchanged(current, previous), // ...this.filterAdded(current, previous), // ...this.filterRemoved(current, previous), // ] // return current.reduce((matched: InitiatorConfig[], i: InitiatorConfig) => { // const match = others.find(o => i.uid === o.uid) // if (!match) matched.push(i) // return matched // }, []) // } // /** // * Returns processes that were not present in the previous configuration // * so they can be started. // */ // private filterAdded<T>( // current: InitiatorConfig[], // previous: InitiatorConfig[] // ): InitiatorConfig[] { // return current.reduce((matched: InitiatorConfig[], i: InitiatorConfig) => { // const matches = previous.filter(p => i.uid === p.uid) // if (!matches.length) matched.push(i) // return matched // }, []) // } // /** // * Returns processes that have been removed since the last configuration and // * need to be stopped. // */ // private filterRemoved<T>( // current: InitiatorConfig[], // previous: InitiatorConfig[] // ): InitiatorConfig[] { // return previous.reduce((matched: InitiatorConfig[], i: InitiatorConfig) => { // const matches = current.filter(p => i.uid === p.uid) // if (!matches.length) matched.push(i) // return matched // }, []) // } // // TODO: Maybe abstract these away into their own InitiatorManager class then // // have ProcessManger handle any class that is a "Manager" class // private runTarget(prev: ConfigFile, latest: ConfigFile) { // // TODO: if target added, add // // TODO: if target removed, remove // // TODO: if target updated, update // // TODO: if services added, add // // TODO: if services removed, remove // // TODO: if services updated, update // } // } //# sourceMappingURL=ProcessManager.js.map