Files
crosslang/src/runtime_methods/process.cpp

296 lines
10 KiB
C++

#include "CrossLang.hpp"
namespace Tesses::CrossLang {
class ProcessObject : public TNativeObject {
public:
ProcessObject() {
arguments = nullptr;
environment = nullptr;
}
ProcessObject(GCList &ls) {
arguments = TList::Create(ls);
environment = TList::Create(ls);
process.includeThisEnv = true;
process.redirectStdIn = false;
process.redirectStdOut = false;
process.redirectStdErr = false;
}
TList *arguments;
TList *environment;
Tesses::Framework::Platform::Process process;
std::string TypeName() { return "Process"; }
void Mark() {
if (this->marked)
return;
this->marked = true;
if (arguments != nullptr)
arguments->Mark();
if (environment != nullptr)
environment->Mark();
}
TObject CallMethod(GCList &ls, std::string key, std::vector<TObject> args) {
if (key == "setFileName" && GetArgument(args, 0, process.name)) {
return process.name;
}
if (key == "getFileName") {
return process.name;
}
if (key == "setRedirectStandardInput" &&
GetArgument(args, 0, process.redirectStdIn)) {
return process.redirectStdIn;
}
if (key == "getRedirectStandardInput") {
return process.redirectStdIn;
}
if (key == "setRedirectStandardOutput" &&
GetArgument(args, 0, process.redirectStdOut)) {
return process.redirectStdOut;
}
if (key == "getRedirectStandardOutput") {
return process.redirectStdOut;
}
if (key == "setRedirectStandardError" &&
GetArgument(args, 0, process.redirectStdErr)) {
return process.redirectStdErr;
}
if (key == "getRedirectStandardError") {
return process.redirectStdErr;
}
if (key == "setWorkingDirectory" &&
GetArgument(args, 0, process.workingDirectory)) {
return process.workingDirectory;
}
if (key == "getWorkingDirectory") {
return process.workingDirectory;
}
if (key == "setInheritParentEnvironment" &&
GetArgument(args, 0, process.includeThisEnv)) {
return process.includeThisEnv;
}
if (key == "getInheritParentEnvironment") {
return process.includeThisEnv;
}
if (key == "getArguments") {
if (arguments == nullptr)
return nullptr;
return arguments;
}
if (key == "setArguments") {
if (GetArgumentHeap(args, 0, arguments)) {
return arguments;
}
}
if (key == "getEnvironment") {
if (environment == nullptr)
return nullptr;
return environment;
}
if (key == "getEnvironment") {
if (GetArgumentHeap(args, 0, environment)) {
return environment;
}
}
if (key == "Start") {
this->process.args.push_back(process.name);
if (arguments != nullptr) {
for (int64_t i = 0; i < arguments->Count(); i++) {
TObject argVal = arguments->Get(i);
std::string argValStr;
if (GetObject(argVal, argValStr))
this->process.args.push_back(argValStr);
}
}
if (environment != nullptr) {
for (int64_t i = 0; i < environment->Count(); i++) {
TObject arg = environment->Get(i);
std::string argstr;
if (GetObject(arg, argstr)) {
auto kvp =
Tesses::Framework::Http::HttpUtils::SplitString(
argstr, "=", 2);
if (kvp.size() == 2) {
process.env.push_back(
std::pair<std::string, std::string>(kvp[0],
kvp[1]));
} else if (kvp.size() == 1) {
process.env.push_back(
std::pair<std::string, std::string>(kvp[0],
""));
}
}
}
}
return process.Start();
}
if (key == "Join" || key == "WaitForExit") {
return (int64_t)process.WaitForExit();
}
if (key == "getHasExited") {
return process.HasExited();
}
if (key == "Terminate") {
process.Kill(SIGTERM);
}
if (key == "CloseStdInNow") {
process.CloseStdInNow();
}
int64_t k;
if (key == "Kill" && GetArgument(args, 0, k)) {
process.Kill((int)k);
}
if (key == "getStandardInput") {
return process.GetStdinStream();
}
if (key == "getStandardOutput") {
return process.GetStdoutStream();
}
if (key == "getStandardError") {
return process.GetStderrStream();
}
return Undefined();
}
};
static TObject Process_Start(GCList &ls, std::vector<TObject> args,
TRootEnvironment *env) {
// Process.Start({
// FileName = "git",
// Arguments =
// ["clone","https://gitea.site.tesses.net/tesses50/crosslang.git"],
// Environment = [],
// InheritParentEnvironment=true
// })
TDictionary *dict;
if (GetArgumentHeap(args, 0, dict)) {
auto process = TNativeObject::Create<ProcessObject>(ls);
auto name = dict->GetValue("FileName");
auto inh = dict->GetValue("InheritParentEnvironment");
auto rStdIn = dict->GetValue("RedirectStandardInput");
auto rStdOut = dict->GetValue("RedirectStandardOutput");
auto rStdErr = dict->GetValue("RedirectStandardError");
auto workingDirectory = dict->GetValue("WorkingDirectory");
process->process.includeThisEnv = true;
process->process.redirectStdIn = false;
process->process.redirectStdOut = false;
process->process.redirectStdErr = false;
GetObject(inh, process->process.includeThisEnv);
GetObject(rStdIn, process->process.redirectStdIn);
GetObject(rStdOut, process->process.redirectStdOut);
GetObject(rStdErr, process->process.redirectStdErr);
GetObject(name, process->process.name);
Tesses::Framework::Filesystem::VFSPath wdPath;
if (env->permissions.localfs) {
process->process.workingDirectory =
env->permissions.localfs->GetWorking().ToString();
}
if (GetObject(workingDirectory, wdPath)) {
process->process.workingDirectory =
wdPath.MakeAbsolute().ToString();
}
GetObject(workingDirectory, process->process.workingDirectory);
process->process.args.push_back(process->process.name);
auto argumentsO = dict->GetValue("Arguments");
TList *arguments;
if (GetObjectHeap(argumentsO, arguments)) {
for (int64_t i = 0; i < arguments->Count(); i++) {
TObject arg = arguments->Get(i);
std::string argstr;
if (GetObject(arg, argstr)) {
process->process.args.push_back(argstr);
}
}
}
argumentsO = dict->GetValue("Environment");
if (GetObjectHeap(argumentsO, arguments)) {
for (int64_t i = 0; i < arguments->Count(); i++) {
TObject arg = arguments->Get(i);
std::string argstr;
if (GetObject(arg, argstr)) {
auto kvp = Tesses::Framework::Http::HttpUtils::SplitString(
argstr, "=", 2);
if (kvp.size() == 2) {
process->process.env.push_back(
std::pair<std::string, std::string>(kvp[0],
kvp[1]));
} else if (kvp.size() == 1) {
process->process.env.push_back(
std::pair<std::string, std::string>(kvp[0], ""));
}
}
}
}
if (process->process.Start()) {
return process;
}
}
return nullptr;
}
void TStd::RegisterProcess(std::shared_ptr<GC> gc, TRootEnvironment *env) {
env->permissions.canRegisterProcess = true;
GCList ls(gc);
TDictionary *dict = TDictionary::Create(ls);
gc->BarrierBegin();
auto processStart = TExternalMethod::Create(
ls, "Start a process", {"process_object"},
[env](GCList &ls, std::vector<TObject> args) -> TObject {
return Process_Start(ls, args, env);
});
processStart->watch.push_back(env);
dict->SetValue("Start", processStart);
env->SetVariable("Process", dict);
auto process = env->EnsureDictionary(gc, "New");
auto newProcess = TExternalMethod::Create(
ls, "Create process", {},
[env](GCList &ls, std::vector<TObject> args) -> TObject {
auto obj = TNativeObject::Create<ProcessObject>(ls, ls);
if (env->permissions.localfs) {
obj->process.workingDirectory =
env->permissions.localfs->GetWorking().ToString();
}
return obj;
});
newProcess->watch.push_back(env);
process->SetValue("Process", newProcess);
// process->DeclareFunction(gc, "Process", "Create process",{},New_Process);
process->DeclareFunction(
gc, "CGIServer", "Create a CGI Server", {"path"},
[](GCList &ls, std::vector<TObject> args) -> TObject {
Tesses::Framework::Filesystem::VFSPath path;
if (GetArgumentAsPath(args, 0, path)) {
return std::make_shared<Tesses::Framework::Http::CGIServer>(
path);
}
return Undefined();
});
process->DeclareFunction(
gc, "ShellFileOrUrl", "Launch file or url in shell", {"urlOrFilename"},
[](GCList &ls, std::vector<TObject> args) -> TObject {
std::string fileOrUrl;
if (GetArgument(args, 0, fileOrUrl))
Tesses::Framework::Platform::ShellFileOrUrl(fileOrUrl);
return Undefined();
});
gc->BarrierEnd();
}
} // namespace Tesses::CrossLang