@remote.it/core
Version:
Core remote.it JavasScript/TypeScript library
388 lines • 16.4 kB
JavaScript
"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