1
0
mirror of https://github.com/Ylianst/MeshAgent synced 2025-12-10 13:23:41 +00:00
Files
MeshAgent/microscript/ILibDuktape_ProcessPipe.c
2017-10-12 14:28:03 -07:00

257 lines
9.7 KiB
C

#include "duktape.h"
#if defined(WINSOCK2)
#include <winsock2.h>
#include <ws2tcpip.h>
#endif
#include "microstack/ILibParsers.h"
#include "microstack/ILibProcessPipe.h"
#include "ILibDuktape_ProcessPipe.h"
#include "ILibDuktape_Helpers.h"
#include "ILibDuktape_DuplexStream.h"
#include "ILibDuktapeModSearch.h"
#define ILibDuktape_ProcessPipe_Process_ErrorStreamPtr "\xFF_ErrorStreamPtr"
#define ILibDuktape_ProcessPipe_Process_ErrorStreamPtrNative "\xFF_ErrorStreamPtrNative"
#define ILibDuktape_ProcessPipe_Process_PTR "\xFFProcessPtr"
ILibTransport_DoneState ILibDuktape_ProcessPipe_Process_JSOnWrite(ILibDuktape_DuplexStream *stream, char *buffer, int bufferLen, void *user)
{
// Called when JavaScript has written bytes to this object
ILibProcessPipe_Process mProcess = (ILibProcessPipe_Process)user;
return(ILibProcessPipe_Process_WriteStdIn(mProcess, buffer, bufferLen, ILibTransport_MemoryOwnership_USER));
}
void ILibDuktape_ProcessPipe_Process_JSOnEnd(ILibDuktape_DuplexStream *stream, void *user)
{
// Called when JavaScript has specified that it will no longer write data
ILibProcessPipe_Process mProcess = (ILibProcessPipe_Process)user;
if (mProcess != NULL)
{
ILibProcessPipe_Process_KillEx(mProcess);
duk_push_heapptr(stream->readableStream->ctx, stream->ParentObject); // [process]
duk_del_prop_string(stream->readableStream->ctx, -1, ILibDuktape_ProcessPipe_Process_PTR);
duk_pop(stream->readableStream->ctx);
ILibProcessPipe_Process_UpdateUserObject(mProcess, NULL);
stream->user = NULL;
}
}
void ILibDuktape_ProcessPipe_Process_JSPause(ILibDuktape_DuplexStream *sender, void *user)
{
// Called when either JavaScript called Pause, or JavaScript has not attached a reader yet
ILibProcessPipe_Process mProcess = (ILibProcessPipe_Process)user;
ILibProcessPipe_Pipe_Pause(ILibProcessPipe_Process_GetStdOut(mProcess));
}
void ILibDuktape_ProcessPipe_Process_JSResume(ILibDuktape_DuplexStream *sender, void *user)
{
// Called when JavaScript called Resume
ILibProcessPipe_Process mProcess = (ILibProcessPipe_Process)user;
ILibProcessPipe_Pipe_Resume(ILibProcessPipe_Process_GetStdOut(mProcess));
}
void ILibDuktape_ProcessPipe_Process_OnExit(ILibProcessPipe_Process sender, int exitCode, void* user)
{
if (user == NULL) { return; }
// Called when process has exited
ILibDuktape_DuplexStream* stream = (ILibDuktape_DuplexStream*)user;
ILibProcessPipe_Process_UpdateUserObject(sender, NULL);
ILibDuktape_DuplexStream_WriteEnd(stream);
duk_push_heapptr(stream->readableStream->ctx, stream->ParentObject); // [process]
duk_del_prop_string(stream->readableStream->ctx, -1, ILibDuktape_ProcessPipe_Process_PTR);
duk_pop(stream->readableStream->ctx);
}
void ILibDuktape_ProcessPipe_Process_OnStdOut(ILibProcessPipe_Process sender, char *buffer, int bufferLen, int* bytesConsumed, void* user)
{
if (user == NULL) { return; }
// Called when process has written data
ILibDuktape_DuplexStream* ds = (ILibDuktape_DuplexStream*)user;
ILibDuktape_DuplexStream_WriteData(ds, buffer, bufferLen);
*bytesConsumed = bufferLen;
}
void ILibDuktape_ProcessPipe_Process_OnStdErr(ILibProcessPipe_Process sender, char *buffer, int bufferLen, int* bytesConsumed, void* user)
{
if (user == NULL) { return; }
// Called when process has written error data
ILibDuktape_DuplexStream* ds = (ILibDuktape_DuplexStream*)user;
ILibDuktape_readableStream *rs;
duk_push_heapptr(ds->readableStream->ctx, ds->ParentObject); // [process]
duk_get_prop_string(ds->readableStream->ctx, -1, ILibDuktape_ProcessPipe_Process_ErrorStreamPtrNative); // [process][error]
rs = (ILibDuktape_readableStream*)duk_get_pointer(ds->readableStream->ctx, -1);
ILibDuktape_readableStream_WriteData(rs, buffer, bufferLen);
*bytesConsumed = bufferLen;
}
void ILibDuktape_ProcessPipe_Process_OnSendOK(ILibProcessPipe_Process sender, void* user)
{
if (user == NULL) { return; }
//ToDo: Finish this
}
duk_ret_t ILibDuktape_ProcessPipe_Process_Finalizer(duk_context *ctx)
{
ILibProcessPipe_Process mProcess;
duk_dup(ctx, 0);
duk_get_prop_string(ctx, -1, ILibDuktape_ProcessPipe_Process_PTR);
mProcess = (ILibProcessPipe_Process)duk_get_pointer(ctx, -1);
if (mProcess != NULL)
{
ILibProcessPipe_Process_UpdateUserObject(mProcess, NULL);
ILibProcessPipe_Process_KillEx(mProcess);
}
if (duk_has_prop_string(ctx, 0, ILibDuktape_DuplexStream_bufferPtr))
{
duk_get_prop_string(ctx, 0, ILibDuktape_DuplexStream_bufferPtr);
memset(Duktape_GetBuffer(ctx, -1, NULL), 0, sizeof(ILibDuktape_DuplexStream));
}
return 0;
}
void ILibDuktape_ProcessPipe_ErrorStream_Pause(struct ILibDuktape_readableStream *sender, void *user)
{
ILibProcessPipe_Process mProcess = (ILibProcessPipe_Process)user;
ILibProcessPipe_Pipe_Pause(ILibProcessPipe_Process_GetStdErr(mProcess));
}
void ILibDuktape_ProcessPipe_ErrorStream_Resume(struct ILibDuktape_readableStream *sender, void *user)
{
ILibProcessPipe_Process mProcess = (ILibProcessPipe_Process)user;
ILibProcessPipe_Pipe_Resume(ILibProcessPipe_Process_GetStdErr(mProcess));
}
duk_ret_t ILibDuktape_ProcessPipe_ErrorStream_Getter(duk_context *ctx)
{
duk_push_this(ctx);
duk_get_prop_string(ctx, -1, ILibDuktape_ProcessPipe_Process_ErrorStreamPtr);
return 1;
}
duk_ret_t ILibDuktape_ProcessPipe_CreateProcess(duk_context *ctx)
{
ILibProcessPipe_Manager pipeManager;
ILibProcessPipe_Process mProcess;
ILibDuktape_DuplexStream* ds;
ILibDuktape_readableStream *rs;
duk_size_t targetLen;
int nargs = duk_get_top(ctx);
char *target;
char **params = NULL;
int i, x;
ILibProcessPipe_SpawnTypes asUser = ILibProcessPipe_SpawnTypes_DEFAULT;
if (nargs < 1) { duk_push_string(ctx, "ProcessPipe.CreateProcess: Invalid number of args"); duk_throw(ctx); return(DUK_RET_ERROR); }
// Parse Parameters
target = (char*)duk_get_lstring(ctx, 0, &targetLen);
#ifdef WIN32
if (target[0] == '%')
{
size_t evsize;
int pctx = ILibString_IndexOf(target + 1, (int)targetLen - 1, "%", 1);
if (pctx > 0)
{
memcpy_s(ILibScratchPad, sizeof(ILibScratchPad), target + 1, pctx);
ILibScratchPad[pctx] = 0;
getenv_s(&evsize, ILibScratchPad2, sizeof(ILibScratchPad2), ILibScratchPad);
if (evsize > 0)
{
strncpy_s(ILibScratchPad2 + evsize - 1, sizeof(ILibScratchPad2) - evsize, target + pctx + 2, targetLen - pctx - 2);
target = ILibScratchPad2;
}
}
}
#endif
if (nargs > 1)
{
x = 0;
params = (char**)ILibMemory_Allocate((nargs * sizeof(char*)), 0, NULL, NULL);
for (i = 1; i < nargs; ++i)
{
if (duk_is_number(ctx, i))
{
asUser = (ILibProcessPipe_SpawnTypes)duk_require_int(ctx, i);
}
else
{
params[x++] = (char*)duk_require_string(ctx, i);
}
}
params[x] = NULL;
}
duk_push_this(ctx); // [manager]
duk_get_prop_string(ctx, -1, "\xFFPipeManager"); // [manager][pipeManager]
pipeManager = (ILibProcessPipe_Manager)duk_get_pointer(ctx, -1);
mProcess = ILibProcessPipe_Manager_SpawnProcessEx(pipeManager, target, params, asUser);
if (params != NULL) { free(params); }
if (mProcess != NULL)
{
duk_push_object(ctx); // [manager][pipeManager][retVal]
duk_push_pointer(ctx, mProcess); // [manager][pipeManager][retVal][process]
duk_put_prop_string(ctx, -2, ILibDuktape_ProcessPipe_Process_PTR); // [manager][pipeManager][retVal]
ILibDuktape_CreateReadonlyProperty_int(ctx, "pid", ILibProcessPipe_Process_GetPID(mProcess));
ds = ILibDuktape_DuplexStream_Init(ctx, ILibDuktape_ProcessPipe_Process_JSOnWrite,
ILibDuktape_ProcessPipe_Process_JSOnEnd, ILibDuktape_ProcessPipe_Process_JSPause,
ILibDuktape_ProcessPipe_Process_JSResume, mProcess);
ILibDuktape_CreateFinalizer(ctx, ILibDuktape_ProcessPipe_Process_Finalizer);
ILibProcessPipe_Process_AddHandlers(mProcess, 4096, ILibDuktape_ProcessPipe_Process_OnExit,
ILibDuktape_ProcessPipe_Process_OnStdOut, ILibDuktape_ProcessPipe_Process_OnStdErr,
ILibDuktape_ProcessPipe_Process_OnSendOK, ds);
duk_push_object(ctx); // [manager][pipeManager][retVal][error]
ILibDuktape_CreateEventWithGetterEx(ctx, "parent", duk_get_heapptr(ctx, -2));
rs = ILibDuktape_ReadableStream_Init(ctx, ILibDuktape_ProcessPipe_ErrorStream_Pause, ILibDuktape_ProcessPipe_ErrorStream_Resume, mProcess);
duk_put_prop_string(ctx, -2, ILibDuktape_ProcessPipe_Process_ErrorStreamPtr); // [manager][pipeManager][retVal]
ILibDuktape_CreateEventWithGetter(ctx, "error", ILibDuktape_ProcessPipe_ErrorStream_Getter);
duk_push_pointer(ctx, rs); // [manager][pipeManager][retVal][ptr]
duk_put_prop_string(ctx, -2, ILibDuktape_ProcessPipe_Process_ErrorStreamPtrNative); // [manager][pipeManager][retVal]
}
else
{
duk_push_null(ctx);
}
return 1;
}
duk_ret_t ILibDuktape_ProcessPipe_Finalizer(duk_context *ctx)
{
ILibProcessPipe_Manager *pipeManager;
duk_dup(ctx, 0); // [obj]
duk_get_prop_string(ctx, -1, "\xFFPipeManager"); // [obj][manager]
pipeManager = (ILibProcessPipe_Manager)duk_get_pointer(ctx, -1);
ILibChain_SafeRemove(((ILibChain_Link*)pipeManager)->ParentChain, pipeManager);
return 0;
}
void ILibDuktape_ProcessPipe_PUSH(duk_context *ctx, void *chain)
{
ILibProcessPipe_Manager pipeManager = ILibProcessPipe_Manager_Create(chain);
duk_push_object(ctx); // [obj]
duk_push_pointer(ctx, pipeManager); // [obj][pipeManager]
duk_put_prop_string(ctx, -2, "\xFFPipeManager"); // [obj]
ILibDuktape_CreateInstanceMethod(ctx, "CreateProcess", ILibDuktape_ProcessPipe_CreateProcess, DUK_VARARGS);
ILibDuktape_CreateFinalizer(ctx, ILibDuktape_ProcessPipe_Finalizer);
Duktape_CreateEnum(ctx, "ILibProcessPipe_SpawnTypes", (char*[]) { "DEFAULT", "USER", "WINLOGON", "TERM" }, (int[]) { 0, 1, 2, 3 }, 4);
}
void ILibDuktape_ProcessPipe_Init(duk_context * ctx, void * chain)
{
ILibDuktape_ModSearch_AddHandler(ctx, "ILibProcessPipe", ILibDuktape_ProcessPipe_PUSH);
}