mirror of
https://github.com/Ylianst/MeshAgent
synced 2026-02-11 14:03:43 +00:00
Added MacOS support
This commit is contained in:
@@ -187,9 +187,9 @@ function serviceHost(serviceName)
|
||||
console.log(e);
|
||||
process.exit();
|
||||
}
|
||||
if (process.platform == 'win32')
|
||||
if (process.platform == 'win32' || process.platform == 'darwin')
|
||||
{
|
||||
// Only do this on Windows, becuase Linux is async... It'll complete later
|
||||
// Only do this on Windows/MacOS, becuase Linux is async... It'll complete later
|
||||
console.log(this._ServiceOptions.name + ' installed');
|
||||
process.exit();
|
||||
}
|
||||
@@ -207,9 +207,9 @@ function serviceHost(serviceName)
|
||||
console.log(e);
|
||||
process.exit();
|
||||
}
|
||||
if (process.platform == 'win32')
|
||||
if (process.platform == 'win32' || process.platform == 'darwin')
|
||||
{
|
||||
// Only do this on Windows, becuase Linux is async... It'll complete later
|
||||
// Only do this on Windows/MacOS, becuase Linux is async... It'll complete later
|
||||
console.log(this._ServiceOptions.name + ' uninstalled');
|
||||
process.exit();
|
||||
}
|
||||
@@ -251,138 +251,141 @@ function serviceHost(serviceName)
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
var moduleName = this._ServiceOptions ? this._ServiceOptions.name : process.execPath.substring(1 + process.execPath.lastIndexOf('/'));
|
||||
|
||||
for (var i = 0; i < process.argv.length; ++i)
|
||||
else if (process.platform == 'linux')
|
||||
{
|
||||
switch(process.argv[i])
|
||||
{
|
||||
case 'start':
|
||||
case '-d':
|
||||
var child = require('child_process').execFile(process.execPath, [moduleName], { type: require('child_process').SpawnTypes.DETACHED });
|
||||
var pstream = null;
|
||||
try
|
||||
{
|
||||
pstream = require('fs').createWriteStream('/var/run/' + moduleName + '.pid', { flags: 'w' });
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
}
|
||||
if (pstream == null)
|
||||
{
|
||||
pstream = require('fs').createWriteStream('.' + moduleName + '.pid', { flags: 'w' });
|
||||
}
|
||||
pstream.end(child.pid.toString());
|
||||
var moduleName = this._ServiceOptions ? this._ServiceOptions.name : process.execPath.substring(1 + process.execPath.lastIndexOf('/'));
|
||||
|
||||
console.log(moduleName + ' started!');
|
||||
process.exit();
|
||||
break;
|
||||
case 'stop':
|
||||
case '-s':
|
||||
var pid = null;
|
||||
try
|
||||
{
|
||||
pid = parseInt(require('fs').readFileSync('/var/run/' + moduleName + '.pid', { flags: 'r' }));
|
||||
require('fs').unlinkSync('/var/run/' + moduleName + '.pid');
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
}
|
||||
if(pid == null)
|
||||
{
|
||||
try
|
||||
{
|
||||
pid = parseInt(require('fs').readFileSync('.' + moduleName + '.pid', { flags: 'r' }));
|
||||
require('fs').unlinkSync('.' + moduleName + '.pid');
|
||||
for (var i = 0; i < process.argv.length; ++i) {
|
||||
switch (process.argv[i]) {
|
||||
case 'start':
|
||||
case '-d':
|
||||
var child = require('child_process').execFile(process.execPath, [moduleName], { type: require('child_process').SpawnTypes.DETACHED });
|
||||
var pstream = null;
|
||||
try {
|
||||
pstream = require('fs').createWriteStream('/var/run/' + moduleName + '.pid', { flags: 'w' });
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
catch (e) {
|
||||
}
|
||||
}
|
||||
if (pstream == null) {
|
||||
pstream = require('fs').createWriteStream('.' + moduleName + '.pid', { flags: 'w' });
|
||||
}
|
||||
pstream.end(child.pid.toString());
|
||||
|
||||
if(pid)
|
||||
{
|
||||
process.kill(pid);
|
||||
console.log(moduleName + ' stopped');
|
||||
console.log(moduleName + ' started!');
|
||||
process.exit();
|
||||
break;
|
||||
case 'stop':
|
||||
case '-s':
|
||||
var pid = null;
|
||||
try {
|
||||
pid = parseInt(require('fs').readFileSync('/var/run/' + moduleName + '.pid', { flags: 'r' }));
|
||||
require('fs').unlinkSync('/var/run/' + moduleName + '.pid');
|
||||
}
|
||||
catch (e) {
|
||||
}
|
||||
if (pid == null) {
|
||||
try {
|
||||
pid = parseInt(require('fs').readFileSync('.' + moduleName + '.pid', { flags: 'r' }));
|
||||
require('fs').unlinkSync('.' + moduleName + '.pid');
|
||||
}
|
||||
catch (e) {
|
||||
}
|
||||
}
|
||||
|
||||
if (pid) {
|
||||
process.kill(pid);
|
||||
console.log(moduleName + ' stopped');
|
||||
}
|
||||
else {
|
||||
console.log(moduleName + ' not running');
|
||||
}
|
||||
process.exit();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (serviceOperation == 0) {
|
||||
// This is non-windows, so we need to check how this binary was started to determine if this was a service start
|
||||
|
||||
// Start by checking if we were started with start/stop
|
||||
var pid = null;
|
||||
try {
|
||||
pid = parseInt(require('fs').readFileSync('/var/run/' + moduleName + '.pid', { flags: 'r' }));
|
||||
}
|
||||
catch (e) {
|
||||
}
|
||||
if (pid == null) {
|
||||
try {
|
||||
pid = parseInt(require('fs').readFileSync('.' + moduleName + '.pid', { flags: 'r' }));
|
||||
}
|
||||
else
|
||||
{
|
||||
console.log(moduleName + ' not running');
|
||||
catch (e) {
|
||||
}
|
||||
process.exit();
|
||||
break;
|
||||
}
|
||||
|
||||
if (pid != null && pid == process.pid) {
|
||||
this.emit('serviceStart');
|
||||
}
|
||||
else {
|
||||
// Now we need to check if we were started with systemd
|
||||
if (require('process-manager').getProcessInfo(1).Name == 'systemd') {
|
||||
this._checkpid = require('child_process').execFile('/bin/sh', ['sh'], { type: require('child_process').SpawnTypes.TERM });
|
||||
this._checkpid.result = '';
|
||||
this._checkpid.parent = this;
|
||||
this._checkpid.on('exit', function onCheckPIDExit() {
|
||||
var lines = this.result.split('\r\n');
|
||||
for (i in lines) {
|
||||
if (lines[i].startsWith(' Main PID:')) {
|
||||
var tokens = lines[i].split(' ');
|
||||
if (parseInt(tokens[3]) == process.pid) {
|
||||
this.parent.emit('serviceStart');
|
||||
}
|
||||
else {
|
||||
this.parent.emit('normalStart');
|
||||
}
|
||||
delete this.parent._checkpid;
|
||||
return;
|
||||
}
|
||||
}
|
||||
this.parent.emit('normalStart');
|
||||
delete this.parent._checkpid;
|
||||
});
|
||||
this._checkpid.stdout.on('data', function (chunk) { this.parent.result += chunk.toString(); });
|
||||
this._checkpid.stdin.write("systemctl status " + moduleName + " | grep 'Main PID:'\n");
|
||||
this._checkpid.stdin.write('exit\n');
|
||||
}
|
||||
else {
|
||||
// This isn't even a systemd platform, so this couldn't have been a service start
|
||||
this.emit('normalStart');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(serviceOperation == 0)
|
||||
else if(process.platform == 'darwin')
|
||||
{
|
||||
// This is non-windows, so we need to check how this binary was started to determine if this was a service start
|
||||
// First let's fetch all the PIDs of running services
|
||||
var child = require('child_process').execFile('/bin/sh', ['sh']);
|
||||
child.stdout.str = '';
|
||||
child.stdout.on('data', function (chunk) { this.str += chunk.toString(); });
|
||||
child.stdin.write('launchctl list\nexit\n');
|
||||
child.waitExit();
|
||||
|
||||
// Start by checking if we were started with start/stop
|
||||
var pid = null;
|
||||
try
|
||||
var lines = child.stdout.str.split('\n');
|
||||
var tokens, i;
|
||||
var p = {};
|
||||
for (i = 1; i < lines.length; ++i)
|
||||
{
|
||||
pid = parseInt(require('fs').readFileSync('/var/run/' + moduleName + '.pid', { flags: 'r' }));
|
||||
tokens = lines[i].split('\t');
|
||||
if (tokens[0] && tokens[0] != '-') { p[tokens[0]] = tokens[0]; }
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
}
|
||||
if (pid == null)
|
||||
{
|
||||
try
|
||||
{
|
||||
pid = parseInt(require('fs').readFileSync('.' + moduleName + '.pid', { flags: 'r' }));
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
if (pid != null && pid == process.pid)
|
||||
|
||||
if(p[process.pid.toString()])
|
||||
{
|
||||
// We are a service!
|
||||
this.emit('serviceStart');
|
||||
}
|
||||
else
|
||||
{
|
||||
// Now we need to check if we were started with systemd
|
||||
if (require('process-manager').getProcessInfo(1).Name == 'systemd')
|
||||
{
|
||||
this._checkpid = require('child_process').execFile('/bin/sh', ['sh'], { type: require('child_process').SpawnTypes.TERM });
|
||||
this._checkpid.result = '';
|
||||
this._checkpid.parent = this;
|
||||
this._checkpid.on('exit', function onCheckPIDExit()
|
||||
{
|
||||
var lines = this.result.split('\r\n');
|
||||
for (i in lines)
|
||||
{
|
||||
if(lines[i].startsWith(' Main PID:'))
|
||||
{
|
||||
var tokens = lines[i].split(' ');
|
||||
if (parseInt(tokens[3]) == process.pid)
|
||||
{
|
||||
this.parent.emit('serviceStart');
|
||||
}
|
||||
else
|
||||
{
|
||||
this.parent.emit('normalStart');
|
||||
}
|
||||
delete this.parent._checkpid;
|
||||
return;
|
||||
}
|
||||
}
|
||||
this.parent.emit('normalStart');
|
||||
delete this.parent._checkpid;
|
||||
});
|
||||
this._checkpid.stdout.on('data', function (chunk) { this.parent.result += chunk.toString(); });
|
||||
this._checkpid.stdin.write("systemctl status " + moduleName + " | grep 'Main PID:'\n");
|
||||
this._checkpid.stdin.write('exit\n');
|
||||
}
|
||||
else
|
||||
{
|
||||
// This isn't even a systemd platform, so this couldn't have been a service start
|
||||
this.emit('normalStart');
|
||||
}
|
||||
this.emit('normalStart');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -214,6 +214,13 @@ function serviceManager()
|
||||
throw ('could not find service: ' + name);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this.isAdmin = function isAdmin()
|
||||
{
|
||||
return (require('user-sessions').isRoot());
|
||||
}
|
||||
}
|
||||
this.installService = function installService(options)
|
||||
{
|
||||
if (process.platform == 'win32')
|
||||
@@ -273,6 +280,8 @@ function serviceManager()
|
||||
}
|
||||
if(process.platform == 'linux')
|
||||
{
|
||||
if (!this.isAdmin()) { throw ('Installing as Service, requires root'); }
|
||||
|
||||
switch (this.getServiceType())
|
||||
{
|
||||
case 'init':
|
||||
@@ -311,14 +320,70 @@ function serviceManager()
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(process.platform == 'darwin')
|
||||
{
|
||||
if (!this.isAdmin()) { throw ('Installing as Service, requires root'); }
|
||||
|
||||
// Mac OS
|
||||
var stdoutpath = (options.stdout ? ('<key>StandardOutPath</key>\n<string>' + options.stdout + '</string>') : '');
|
||||
var autoStart = (options.startType == 'AUTO_START' ? '<true/>' : '<false/>');
|
||||
var params = ' <key>ProgramArguments</key>\n';
|
||||
params += ' <array>\n';
|
||||
params += (' <string>/usr/local/mesh_services/' + options.name + '/' + options.name + '</string>\n');
|
||||
if(options.parameters)
|
||||
{
|
||||
for(var itm in options.parameters)
|
||||
{
|
||||
params += (' <string>' + options.parameters[itm] + '</string>\n');
|
||||
}
|
||||
}
|
||||
params += ' </array>\n';
|
||||
|
||||
var plist = '<?xml version="1.0" encoding="UTF-8"?>\n';
|
||||
plist += '<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">\n';
|
||||
plist += '<plist version="1.0">\n';
|
||||
plist += ' <dict>\n';
|
||||
plist += ' <key>Label</key>\n';
|
||||
plist += (' <string>' + options.name + '</string>\n');
|
||||
plist += (params + '\n');
|
||||
plist += ' <key>WorkingDirectory</key>\n';
|
||||
plist += (' <string>/usr/local/mesh_services/' + options.name + '</string>\n');
|
||||
plist += (stdoutpath + '\n');
|
||||
plist += ' <key>RunAtLoad</key>\n';
|
||||
plist += (autoStart + '\n');
|
||||
plist += ' </dict>\n';
|
||||
plist += '</plist>';
|
||||
|
||||
if (!require('fs').existsSync('/usr/local/mesh_services')) { require('fs').mkdirSync('/usr/local/mesh_services'); }
|
||||
if (!require('fs').existsSync('/Library/LaunchDaemons/' + options.name + '.plist'))
|
||||
{
|
||||
if (!require('fs').existsSync('/usr/local/mesh_services/' + options.name)) { require('fs').mkdirSync('/usr/local/mesh_services/' + options.name); }
|
||||
if (options.binary)
|
||||
{
|
||||
require('fs').writeFileSync('/usr/local/mesh_services/' + options.name + '/' + options.name, options.binary);
|
||||
}
|
||||
else
|
||||
{
|
||||
require('fs').copyFileSync(options.servicePath, '/usr/local/mesh_services/' + options.name + '/' + options.name);
|
||||
}
|
||||
require('fs').writeFileSync('/Library/LaunchDaemons/' + options.name + '.plist', plist);
|
||||
var m = require('fs').statSync('/usr/local/mesh_services/' + options.name + '/' + options.name).mode;
|
||||
m |= (require('fs').CHMOD_MODES.S_IXUSR | require('fs').CHMOD_MODES.S_IXGRP);
|
||||
require('fs').chmodSync('/usr/local/mesh_services/' + options.name + '/' + options.name, m);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw ('Service: ' + options.name + ' already exists');
|
||||
}
|
||||
}
|
||||
}
|
||||
this.uninstallService = function uninstallService(name)
|
||||
{
|
||||
if (!this.isAdmin()) { throw ('Uninstalling a service, requires admin'); }
|
||||
|
||||
if (typeof (name) == 'object') { name = name.name; }
|
||||
if (process.platform == 'win32')
|
||||
{
|
||||
if (!this.isAdmin()) { throw ('Uninstalling a service, requires admin'); }
|
||||
|
||||
var service = this.getService(name);
|
||||
if (service.status.state == undefined || service.status.state == 'STOPPED')
|
||||
{
|
||||
@@ -388,6 +453,39 @@ function serviceManager()
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if(process.platform == 'darwin')
|
||||
{
|
||||
if (require('fs').existsSync('/Library/LaunchDaemons/' + name + '.plist'))
|
||||
{
|
||||
var child = require('child_process').execFile('/bin/sh', ['sh']);
|
||||
child.stdout.on('data', function (chunk) { });
|
||||
child.stdin.write('launchctl stop ' + name + '\n');
|
||||
child.stdin.write('launchctl unload /Library/LaunchDaemons/' + name + '.plist\n');
|
||||
child.stdin.write('exit\n');
|
||||
child.waitExit();
|
||||
|
||||
try
|
||||
{
|
||||
require('fs').unlinkSync('/usr/local/mesh_services/' + name + '/' + name);
|
||||
require('fs').unlinkSync('/Library/LaunchDaemons/' + name + '.plist');
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
throw ('Error uninstalling service: ' + name + ' => ' + e);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
require('fs').rmdirSync('/usr/local/mesh_services/' + name);
|
||||
}
|
||||
catch(e)
|
||||
{}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw ('Service: ' + name + ' does not exist');
|
||||
}
|
||||
}
|
||||
}
|
||||
if(process.platform == 'linux')
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user