mirror of
https://github.com/Ylianst/MeshAgent
synced 2026-02-28 02:13:33 +00:00
1. Updated waitExit() for windows to support a timeout
2. Updated ProcessPipe for Windows, to disable inheritance on detach 3. Updated service-manager to support restart on self for windows
This commit is contained in:
@@ -168,6 +168,7 @@ duk_ret_t ILibDuktape_ChildProcess_waitExit(duk_context *ctx)
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
DWORD result;
|
||||
HANDLE eptr = CreateEventA(NULL, TRUE, FALSE, NULL);
|
||||
duk_push_pointer(ctx, (void*)eptr);
|
||||
#else
|
||||
@@ -176,8 +177,9 @@ duk_ret_t ILibDuktape_ChildProcess_waitExit(duk_context *ctx)
|
||||
duk_put_prop_string(ctx, -2, "\xFF_WaitExit"); // [spawnedProcess]
|
||||
|
||||
#ifdef WIN32
|
||||
while (WaitForSingleObjectEx(eptr, INFINITE, TRUE) != WAIT_OBJECT_0);
|
||||
while ((result=WaitForSingleObjectEx(eptr, duk_is_number(ctx, 0) ? duk_require_int(ctx, 0) : INFINITE, TRUE)) != WAIT_OBJECT_0 && result != WAIT_TIMEOUT);
|
||||
CloseHandle(eptr);
|
||||
if (result == WAIT_TIMEOUT) { return(ILibDuktape_Error(ctx, "timeout")); }
|
||||
#else
|
||||
void *mods[] = { ILibGetBaseTimer(Duktape_GetChain(ctx)), Duktape_GetPointerProperty(ctx, -1, ILibDuktape_ChildProcess_Manager) };
|
||||
ILibChain_Continue(chain, (ILibChain_Link**)mods, 2, -1);
|
||||
@@ -214,7 +216,7 @@ ILibDuktape_ChildProcess_SubProcess* ILibDuktape_ChildProcess_SpawnedProcess_PUS
|
||||
ILibDuktape_EventEmitter_CreateEventEx(emitter, "error");
|
||||
ILibDuktape_EventEmitter_PrependOnce(ctx, -1, "~", ILibDuktape_ChildProcess_SpawnedProcess_Finalizer);
|
||||
ILibDuktape_CreateInstanceMethod(ctx, "kill", ILibDuktape_ChildProcess_Kill, 0);
|
||||
ILibDuktape_CreateInstanceMethod(ctx, "waitExit", ILibDuktape_ChildProcess_waitExit, 0);
|
||||
ILibDuktape_CreateInstanceMethod(ctx, "waitExit", ILibDuktape_ChildProcess_waitExit, DUK_VARARGS);
|
||||
|
||||
if (ILibProcessPipe_Process_IsDetached(mProcess) == 0)
|
||||
{
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -860,7 +860,7 @@ ILibProcessPipe_Process ILibProcessPipe_Manager_SpawnProcessEx4(ILibProcessPipe_
|
||||
info.dwFlags |= STARTF_USESTDHANDLES;
|
||||
}
|
||||
|
||||
if ((spawnType == ILibProcessPipe_SpawnTypes_DEFAULT && !CreateProcessA(target, parms, NULL, NULL, TRUE, CREATE_NO_WINDOW | (needSetSid !=0? (DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP) : 0x00), envvars, NULL, &info, &processInfo)) ||
|
||||
if (((spawnType == ILibProcessPipe_SpawnTypes_DEFAULT || spawnType == ILibProcessPipe_SpawnTypes_DETACHED) && !CreateProcessA(target, parms, NULL, NULL, spawnType == ILibProcessPipe_SpawnTypes_DETACHED ? FALSE: TRUE, CREATE_NO_WINDOW | (needSetSid !=0? (DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP) : 0x00), envvars, NULL, &info, &processInfo)) ||
|
||||
(spawnType != ILibProcessPipe_SpawnTypes_DEFAULT && !CreateProcessAsUserA(userToken, target, parms, NULL, NULL, TRUE, CREATE_NO_WINDOW | (needSetSid != 0 ? (DETACHED_PROCESS| CREATE_NEW_PROCESS_GROUP) : 0x00), envvars, NULL, &info, &processInfo)))
|
||||
{
|
||||
if (spawnType != ILibProcessPipe_SpawnTypes_DETACHED)
|
||||
|
||||
@@ -13,6 +13,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
var promise = require('promise');
|
||||
|
||||
|
||||
function extractFileName(filePath)
|
||||
@@ -558,15 +559,35 @@ function serviceManager()
|
||||
var handle = this.proxy.OpenSCManagerA(0x00, 0x00, 0x0001 | 0x0004 | 0x0020 | 0x0010);
|
||||
if (handle.Val == 0) { throw ('could not open ServiceManager'); }
|
||||
var h = this.proxy.OpenServiceA(handle, serviceName, 0x0001 | 0x0004 | 0x0020 | 0x0010 | 0x00010000);
|
||||
if (h.Val != 0) {
|
||||
var success = this.proxy.QueryServiceStatusEx(h, 0, 0, 0, bytesNeeded);
|
||||
var status = this.GM.CreateVariable(bytesNeeded.toBuffer().readUInt32LE());
|
||||
success = this.proxy.QueryServiceStatusEx(h, 0, status, status._size, bytesNeeded);
|
||||
if (success != 0)
|
||||
{
|
||||
var retVal = { _ObjectID: 'service-manager.service' }
|
||||
require('events').EventEmitter.call(retVal);
|
||||
if (h.Val != 0)
|
||||
{
|
||||
var retVal = { _ObjectID: 'service-manager.service' }
|
||||
retVal._scm = handle;
|
||||
retVal._service = h;
|
||||
retVal._GM = this.GM;
|
||||
retVal._proxy = this.proxy;
|
||||
retVal.name = name;
|
||||
|
||||
Object.defineProperty(retVal, 'status',
|
||||
{
|
||||
get: function()
|
||||
{
|
||||
var bytesNeeded = this._GM.CreateVariable(this._GM.PointerSize);
|
||||
this._proxy.QueryServiceStatusEx(this._service, 0, 0, 0, bytesNeeded);
|
||||
var st = this._GM.CreateVariable(bytesNeeded.toBuffer().readUInt32LE());
|
||||
if (this._proxy.QueryServiceStatusEx(this._service, 0, st, st._size, bytesNeeded).Val != 0)
|
||||
{
|
||||
return(parseServiceStatus(st));
|
||||
}
|
||||
else
|
||||
{
|
||||
return ({ state: 'UNKNOWN' });
|
||||
}
|
||||
}
|
||||
});
|
||||
if (retVal.status.state != 'UNKNOWN')
|
||||
{
|
||||
require('events').EventEmitter.call(retVal);
|
||||
retVal.close = function ()
|
||||
{
|
||||
if(this._service && this._scm)
|
||||
@@ -576,15 +597,11 @@ function serviceManager()
|
||||
this._service = this._scm = null;
|
||||
}
|
||||
};
|
||||
|
||||
retVal.on('~', retVal.close);
|
||||
retVal.status = parseServiceStatus(status);
|
||||
retVal._scm = handle;
|
||||
retVal._service = h;
|
||||
retVal._GM = this.GM;
|
||||
retVal._proxy = this.proxy;
|
||||
retVal.name = name;
|
||||
|
||||
retVal.isMe = function isMe()
|
||||
{
|
||||
return (parseInt(this.status.pid) == process.pid);
|
||||
}
|
||||
retVal.appLocation = function ()
|
||||
{
|
||||
var reg = require('win-registry');
|
||||
@@ -594,7 +611,6 @@ function serviceManager()
|
||||
return (ret);
|
||||
};
|
||||
|
||||
|
||||
retVal.appWorkingDirectory = function ()
|
||||
{
|
||||
var tokens = this.appLocation().split('\\');
|
||||
@@ -603,105 +619,107 @@ function serviceManager()
|
||||
};
|
||||
retVal.isRunning = function ()
|
||||
{
|
||||
var bytesNeeded = this._GM.CreateVariable(this._GM.PointerSize);
|
||||
this._proxy.QueryServiceStatusEx(this._service, 0, 0, 0, bytesNeeded);
|
||||
var st = this._GM.CreateVariable(bytesNeeded.toBuffer().readUInt32LE());
|
||||
if(this._proxy.QueryServiceStatusEx(this._service, 0, st, st._size, bytesNeeded).Val != 0)
|
||||
{
|
||||
var state = parseServiceStatus(st);
|
||||
return (state.state == 'RUNNING');
|
||||
}
|
||||
return (false);
|
||||
return (this.status.state == 'RUNNING');
|
||||
};
|
||||
|
||||
retVal._stopEx = function(s, p)
|
||||
{
|
||||
var bytesNeeded = s._GM.CreateVariable(s._GM.PointerSize);
|
||||
s._proxy.QueryServiceStatusEx(s._service, 0, 0, 0, bytesNeeded);
|
||||
var st = s._GM.CreateVariable(bytesNeeded.toBuffer().readUInt32LE());
|
||||
if (s._proxy.QueryServiceStatusEx(s._service, 0, st, st._size, bytesNeeded).Val != 0)
|
||||
var current = s.status.state;
|
||||
switch (current)
|
||||
{
|
||||
var currentState = parseServiceStatus(st).state;
|
||||
switch (currentState)
|
||||
{
|
||||
case 'STOPPED':
|
||||
p._res('STOPPED');
|
||||
break;
|
||||
case 'STOP_PENDING':
|
||||
p._elapsedTime = Date.now() - p._startTime;
|
||||
if (p._elapsedTime < 10000)
|
||||
{
|
||||
p.timer = setTimeout(s._stopEx, p._waitTime, s, p);
|
||||
}
|
||||
else
|
||||
{
|
||||
p._rej('timeout waiting for service to stop');
|
||||
}
|
||||
break;
|
||||
default:
|
||||
p._rej('Unexpected state: ' + currentState);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
p._rej('Error fetching service state');
|
||||
case 'STOPPED':
|
||||
console.log('STOPPED');
|
||||
p._res('STOPPED');
|
||||
break;
|
||||
case 'STOP_PENDING':
|
||||
p._elapsedTime = Date.now() - p._startTime;
|
||||
if (p._elapsedTime < 10000)
|
||||
{
|
||||
p.timer = setTimeout(s._stopEx, p._waitTime, s, p);
|
||||
}
|
||||
else
|
||||
{
|
||||
p._rej('timeout waiting for service to stop');
|
||||
}
|
||||
break;
|
||||
default:
|
||||
console.log(current);
|
||||
p._rej('Unexpected state: ' + current);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
retVal.stop = function ()
|
||||
{
|
||||
var promise = require('promise');
|
||||
var ret = new promise(function (a, r) { this._res = a; this._rej = r; });
|
||||
var bytesNeeded = this._GM.CreateVariable(this._GM.PointerSize);
|
||||
this._proxy.QueryServiceStatusEx(this._service, 0, 0, 0, bytesNeeded);
|
||||
var st = this._GM.CreateVariable(bytesNeeded.toBuffer().readUInt32LE());
|
||||
if (this._proxy.QueryServiceStatusEx(this._service, 0, st, st._size, bytesNeeded).Val != 0)
|
||||
var status = this.status;
|
||||
if(status.state == 'RUNNING')
|
||||
{
|
||||
var status = parseServiceStatus(st);
|
||||
if(status.state == 'RUNNING')
|
||||
// Stop Service
|
||||
var newstate = this._GM.CreateVariable(36);
|
||||
if(this._proxy.ControlService(this._service, 0x00000001, newstate).Val == 0)
|
||||
{
|
||||
// Stop Service
|
||||
var newstate = this._GM.CreateVariable(36);
|
||||
if(this._proxy.ControlService(this._service, 0x00000001, newstate).Val == 0)
|
||||
{
|
||||
ret._rej(this.name + '.stop() failed');
|
||||
}
|
||||
else
|
||||
{
|
||||
// Now we need to setup a timed callback to check the status
|
||||
ret._startTime = Date.now();
|
||||
ret._elapsedTime = 0;
|
||||
ret._waitTime = status.waitHint / 10;
|
||||
if (ret._waitTime < 500) { ret._waitTime = 500; }
|
||||
if (ret._waitTime > 5000) { ret._waitTime = 5000; }
|
||||
ret.timer = setTimeout(this._stopEx, ret._waitTime, this, ret);
|
||||
}
|
||||
ret._rej(this.name + '.stop() failed');
|
||||
}
|
||||
else
|
||||
{
|
||||
ret._rej('cannot call ' + this.name + '.stop(), when current state is: ' + status.state);
|
||||
// Now we need to setup a timed callback to check the status
|
||||
ret._startTime = Date.now();
|
||||
ret._elapsedTime = 0;
|
||||
ret._waitTime = status.waitHint / 10;
|
||||
if (ret._waitTime < 500) { ret._waitTime = 500; }
|
||||
if (ret._waitTime > 5000) { ret._waitTime = 5000; }
|
||||
ret.timer = setTimeout(this._stopEx, ret._waitTime, this, ret);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ret._rej('error determining if ' + this.name + ' is running');
|
||||
ret._rej('cannot call ' + this.name + '.stop(), when current state is: ' + this.status.state);
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
retVal.start = function () {
|
||||
if (this.status.state == 'STOPPED') {
|
||||
retVal.start = function ()
|
||||
{
|
||||
if (this.status.state == 'STOPPED')
|
||||
{
|
||||
var success = this._proxy.StartServiceA(this._service, 0, 0);
|
||||
if (success == 0) {
|
||||
if (success == 0)
|
||||
{
|
||||
throw (this.name + '.start() failed');
|
||||
}
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
throw ('cannot call ' + this.name + '.start(), when current state is: ' + this.status.state);
|
||||
}
|
||||
}
|
||||
retVal.restart = function ()
|
||||
{
|
||||
if (this.isMe())
|
||||
{
|
||||
// In order to restart ourselves on Windows, we must spawn a detached child process, becuase we need to call start, once we are stopped
|
||||
child = require('child_process').execFile(process.execPath, [process.execPath.split('\\').pop(), '-exec "' + "require('service-manager').manager.getService('" + this.name + "').restart().finally(function(){process.exit();});" + '"'], { type: 4, detached: true });
|
||||
}
|
||||
else
|
||||
{
|
||||
var p = this.stop();
|
||||
p.startp = new promise(function (a, r) { this._a = a; this._r = r; });
|
||||
p.service = this;
|
||||
p.then(function ()
|
||||
{
|
||||
try
|
||||
{
|
||||
this.service.start();
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
this.startp._r(e);
|
||||
return;
|
||||
}
|
||||
this.startp._a();
|
||||
});
|
||||
return (p.startp);
|
||||
}
|
||||
}
|
||||
var query_service_configa_DWORD = this.GM.CreateVariable(4);
|
||||
this.proxy.QueryServiceConfigA(h, 0, 0, query_service_configa_DWORD);
|
||||
|
||||
Reference in New Issue
Block a user