diff --git a/CMakeLists.txt b/CMakeLists.txt index 7864d5b..de89638 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -170,6 +170,7 @@ src/types/vfsheapobject.cpp src/types/streamheapobject.cpp src/types/class.cpp src/types/classenvironment.cpp +src/types/random.cpp src/vm/filereader.cpp src/vm/gc.cpp src/vm/gclist.cpp diff --git a/Packaging/CPKG/ConsoleOrServer/main.cpp b/Packaging/CPKG/ConsoleOrServer/main.cpp index 1a494d2..62b672b 100644 --- a/Packaging/CPKG/ConsoleOrServer/main.cpp +++ b/Packaging/CPKG/ConsoleOrServer/main.cpp @@ -4,6 +4,8 @@ using namespace Tesses::CrossLang; int main(int argc, char** argv) { TF_InitWithConsole(); + if(argc > 0) + TF_AllowPortable(argv[0]); std::string name = argv[0]; Tesses::Framework::Filesystem::VFSPath exePath=Tesses::Framework::Filesystem::LocalFS->SystemToVFSPath(name); exePath.MakeAbsolute(); diff --git a/Packaging/Linux/build-tars.sh b/Packaging/Linux/build-tars.sh index f25a476..a983575 100644 --- a/Packaging/Linux/build-tars.sh +++ b/Packaging/Linux/build-tars.sh @@ -3,10 +3,10 @@ mkdir build-x86_64-tar cd build-x86_64-tar cmake -S ../../.. -B . -DTESSESFRAMEWORK_ENABLE_SHARED=ON -DTESSESFRAMEWORK_ENABLE_STATIC=OFF -DTESSESFRAMEWORK_FETCHCONTENT=ON make -j`nproc` -make install DESTDIR=./crosslang -mkdir -p crosslang/share/Tesses/CrossLang -cp ../build/jammy/Tesses.CrossLang.ShellPackage-1.0.0.0-prod.crvm crosslang/share/Tesses/CrossLang/Tesses.CrossLang.ShellPackage-1.0.0.0-prod.crvm -tar cvzf ../../../artifacts/crosslang-linux-x86_64.tar.gz crosslang +make install DESTDIR=./crosslang-x86_64 +mkdir -p crosslang-x86_64/share/Tesses/CrossLang +cp ../build/jammy/Tesses.CrossLang.ShellPackage-1.0.0.0-prod.crvm crosslang-x86_64/share/Tesses/CrossLang/Tesses.CrossLang.ShellPackage-1.0.0.0-prod.crvm +tar cvzf ../../../artifacts/crosslang-linux-x86_64.tar.gz crosslang-x86_64 cd .. foreign() { @@ -14,10 +14,10 @@ mkdir build-$1\-tar cd build-$1\-tar cmake -S ../../.. -B . -DTESSESFRAMEWORK_ENABLE_SHARED=ON -DTESSESFRAMEWORK_ENABLE_STATIC=OFF -DTESSESFRAMEWORK_FETCHCONTENT=ON -DCMAKE_TOOLCHAIN_FILE=/opt/toolchains/$1\.cmake make -j`nproc` -make install DESTDIR=./crosslang -mkdir -p crosslang/share/Tesses/CrossLang -cp ../build/jammy/Tesses.CrossLang.ShellPackage-1.0.0.0-prod.crvm crosslang/share/Tesses/CrossLang/Tesses.CrossLang.ShellPackage-1.0.0.0-prod.crvm -tar cvzf ../../../artifacts/crosslang-linux-$1\.tar.gz crosslang +make install DESTDIR=./crosslang-$1 +mkdir -p crosslang-$1\/share/Tesses/CrossLang +cp ../build/jammy/Tesses.CrossLang.ShellPackage-1.0.0.0-prod.crvm crosslang-$1\/share/Tesses/CrossLang/Tesses.CrossLang.ShellPackage-1.0.0.0-prod.crvm +tar cvzf ../../../artifacts/crosslang-linux-$1\.tar.gz crosslang-$1 cd .. } foreign arm64 diff --git a/include/CrossLang.hpp b/include/CrossLang.hpp index b467eb0..ee811b7 100644 --- a/include/CrossLang.hpp +++ b/include/CrossLang.hpp @@ -1687,6 +1687,8 @@ class GC { virtual TObject Call(GCList& ls,std::vector args)=0; TObject CallWithFatalError(GCList& ls, std::vector args); virtual void Mark(); + + Tesses::Framework::Http::ServerRequestHandler ToRouteServerRequestHandler(GC* gc); }; void ThrowFatalError(std::exception& ex); @@ -2045,6 +2047,9 @@ class GC { void CreateHardlink(Tesses::Framework::Filesystem::VFSPath existingFile, Tesses::Framework::Filesystem::VFSPath newName); bool DirectoryExists(Tesses::Framework::Filesystem::VFSPath path); void DeleteFile(Tesses::Framework::Filesystem::VFSPath path); + void Lock(Tesses::Framework::Filesystem::VFSPath path); + void Unlock(Tesses::Framework::Filesystem::VFSPath path); + void DeleteDirectoryRecurse(Tesses::Framework::Filesystem::VFSPath path); Tesses::Framework::Filesystem::VFSPathEnumerator EnumeratePaths(Tesses::Framework::Filesystem::VFSPath path); void MoveFile(Tesses::Framework::Filesystem::VFSPath src, Tesses::Framework::Filesystem::VFSPath dest); @@ -2370,6 +2375,16 @@ class GC { virtual bool Equals(GC* gc, TObject right); virtual ~TNativeObject(); }; + class TRandom : public TNativeObject + { + public: + Tesses::Framework::Random random; + TRandom(); + TRandom(uint64_t seed); + std::string TypeName(); + TObject CallMethod(GCList& ls,std::string name, std::vector args); + + }; class TNative : public THeapObject { std::atomic destroyed; @@ -2387,7 +2402,7 @@ class GC { ~TNative(); }; - + class ThreadHandle : public THeapObject { public: @@ -2604,4 +2619,6 @@ class GC { std::string VFSPathToSystem(Tesses::Framework::Filesystem::VFSPath path); Tesses::Framework::Filesystem::VFSPath SystemToVFSPath(std::string path); }; + + }; diff --git a/src/crosslang.cpp b/src/crosslang.cpp index 79882e4..89daaa5 100644 --- a/src/crosslang.cpp +++ b/src/crosslang.cpp @@ -49,6 +49,8 @@ bool Download(Tesses::Framework::Filesystem::VFSPath filename,std::shared_ptr 0) + TF_AllowPortable(argv[0]); diff --git a/src/crosslanginterperter.cpp b/src/crosslanginterperter.cpp index a8aeb7d..85eb52c 100644 --- a/src/crosslanginterperter.cpp +++ b/src/crosslanginterperter.cpp @@ -9,6 +9,8 @@ using namespace Tesses::Framework::Filesystem; int main(int argc, char** argv) { TF_InitWithConsole(); + if(argc > 0) + TF_AllowPortable(argv[0]); GC gc; gc.Start(); GCList ls(gc); diff --git a/src/crosslangvm.cpp b/src/crosslangvm.cpp index d277e24..1071f3f 100644 --- a/src/crosslangvm.cpp +++ b/src/crosslangvm.cpp @@ -4,11 +4,14 @@ using namespace Tesses::CrossLang; int main(int argc, char** argv) { TF_InitWithConsole(); + if(argc < 2) { printf("USAGE: %s \n",argv[0]); return 1; } + if(argc > 0) + TF_AllowPortable(argv[0]); GC gc; gc.Start(); diff --git a/src/runtime_methods/console.cpp b/src/runtime_methods/console.cpp index 9481e74..655f89f 100644 --- a/src/runtime_methods/console.cpp +++ b/src/runtime_methods/console.cpp @@ -320,6 +320,15 @@ namespace Tesses::CrossLang { dict->DeclareFunction(gc, "getSize", "Get console size",{},Console_getSize); gc->BarrierBegin(); env->DeclareVariable("Console", dict); + auto _new = env->EnsureDictionary(gc,"New"); + _new->DeclareFunction(gc,"ConsoleReader","Read from console",{},[](GCList& ls,std::vector args)->TObject { + return std::make_shared(); + }); + _new->DeclareFunction(gc,"ConsoleWriter","Write to console",{"$isStderr"},[](GCList& ls,std::vector args)->TObject { + bool err; + if(GetArgument(args,0,err)) return std::make_shared(err); + return std::make_shared(); + }); gc->BarrierEnd(); } } diff --git a/src/runtime_methods/env.cpp b/src/runtime_methods/env.cpp index a59fbc6..72d4045 100644 --- a/src/runtime_methods/env.cpp +++ b/src/runtime_methods/env.cpp @@ -118,6 +118,19 @@ namespace Tesses::CrossLang } return Tesses::Framework::Filesystem::VFSPath(); } + static TObject Env_GetAll(GCList& ls, std::vector args) + { + ls.GetGC()->BarrierBegin(); + TList* list = TList::Create(ls); + std::vector> env; + Tesses::Framework::Platform::Environment::GetEnvironmentVariables(env); + for(auto& item : env) + { + list->Add(TDictionary::Create(ls,{TDItem("Key",item.first),TDItem("Value",item.second)})); + } + ls.GetGC()->BarrierEnd(); + return list; + } void TStd::RegisterEnv(GC* gc, TRootEnvironment* env) { @@ -126,8 +139,9 @@ namespace Tesses::CrossLang TDictionary* dict = TDictionary::Create(ls); dict->DeclareFunction(gc,"GetAt","Get environment variable", {"key"}, Env_GetAt); dict->DeclareFunction(gc,"SetAt","Set environment variable", {"key","value"}, Env_SetAt); + dict->DeclareFunction(gc,"GetAll","Get all of the environment variables",{},Env_GetAll); - dict->DeclareFunction(gc,"getDesktop","Get downloads folder",{},Env_getDownloads); + dict->DeclareFunction(gc,"getDesktop","Get desktop folder",{},Env_getDesktop); dict->DeclareFunction(gc,"getDownloads","Get downloads folder",{},Env_getDownloads); dict->DeclareFunction(gc,"getDocuments","Get documents folder",{},Env_getDocuments); dict->DeclareFunction(gc,"getMusic","Get music folder",{},Env_getMusic); diff --git a/src/runtime_methods/net.cpp b/src/runtime_methods/net.cpp index 22d7c3c..bf697b9 100644 --- a/src/runtime_methods/net.cpp +++ b/src/runtime_methods/net.cpp @@ -578,6 +578,7 @@ namespace Tesses::CrossLang } } + return Undefined(); } @@ -897,7 +898,8 @@ namespace Tesses::CrossLang ~THttpResponse() { - Close(); + delete this->response; + this->response = nullptr; } std::string TypeName() { @@ -1478,9 +1480,14 @@ namespace Tesses::CrossLang } static TObject New_MountableServer(GCList& ls, std::vector args) { - if(args.empty()) return Undefined(); + if(args.empty()) return std::make_shared(); return std::make_shared(ToHttpServer(ls.GetGC(),args[0])); } + static TObject New_RouteServer(GCList& ls, std::vector args) + { + if(args.empty()) return std::make_shared(); + return std::make_shared(ToHttpServer(ls.GetGC(),args[0])); + } static TObject New_StreamHttpRequestBody(GCList& ls, std::vector args) { std::shared_ptr strm; @@ -1530,6 +1537,8 @@ namespace Tesses::CrossLang _new->DeclareFunction(gc, "HttpServer", "Create a http server (allows multiple)",{"server","portOrUnixPath","$printIPs"},[env](GCList& ls, std::vector args)->TObject{ return New_HttpServer(ls,args,env); }); + + _new->DeclareFunction(gc, "RouteServer","Create a routeserver",{"$root"}, New_RouteServer); _new->DeclareFunction(gc, "FileServer","Create a file server",{"vfs","allowlisting","spa"}, New_FileServer); _new->DeclareFunction(gc, "BasicAuthServer", "Create a basic auth server", {"$server","$auth","$realm"},New_BasicAuthServer); _new->DeclareFunction(gc, "MountableServer","Create a server you can mount to, must mount parents before child",{"root"}, New_MountableServer); @@ -1564,6 +1573,8 @@ namespace Tesses::CrossLang http->DeclareFunction(gc, "ListenSimpleWithLoop", "Listen (creates application loop)", {"server","port"},Net_Http_ListenSimpleWithLoop); http->DeclareFunction(gc, "ListenOnUnusedPort","Listen on unused localhost port and print Port: theport",{"server"},Net_Http_ListenOnUnusedPort); //FileServer svr() + + http->DeclareFunction(gc, "RouteServer","Create a routeserver",{"$root"}, New_RouteServer); http->DeclareFunction(gc, "FileServer","Create a file server",{"vfs","allowlisting","spa"}, New_FileServer); http->DeclareFunction(gc, "BasicAuthServer", "Create a basic auth server", {"$server","$auth","$realm"},New_BasicAuthServer); http->DeclareFunction(gc, "BasicAuthGetCreds","Get creds from str",{"ctx"},[](GCList& ls, std::vector args)->TObject { @@ -1604,4 +1615,25 @@ namespace Tesses::CrossLang dict->SetValue("Smtp", smtp); gc->BarrierEnd(); } + + Tesses::Framework::Http::ServerRequestHandler TCallable::ToRouteServerRequestHandler(GC* gc) + { + auto value = CreateMarkedTObject(gc,this); + return [value,this](ServerContext& ctx)->bool { + auto v=value; + auto gc = v->GetGC(); + GCList ls(gc); + auto res = TNativeObject::Create(ls, &ctx); + bool result; + auto out = this->Call(ls,{res}); + if(GetObject(out,result)) + { + res->Finish(); + return result; + } + res->Finish(); + + return false; + }; + } } diff --git a/src/runtime_methods/std.cpp b/src/runtime_methods/std.cpp index 0297449..2defcf8 100644 --- a/src/runtime_methods/std.cpp +++ b/src/runtime_methods/std.cpp @@ -556,6 +556,18 @@ namespace Tesses::CrossLang std::shared_ptr strm; return GetArgument(args,0,strm); } + static TObject TypeIsTextReader(GCList& ls, std::vector args) + { + if(args.empty()) return nullptr; + std::shared_ptr strm; + return GetArgument(args,0,strm); + } + static TObject TypeIsTextWriter(GCList& ls, std::vector args) + { + if(args.empty()) return nullptr; + std::shared_ptr strm; + return GetArgument(args,0,strm); + } static TObject TypeIsVFS(GCList& ls, std::vector args) { if(args.empty()) return nullptr; @@ -752,6 +764,7 @@ namespace Tesses::CrossLang { auto fileServer = std::dynamic_pointer_cast(svr); auto mountableServer = std::dynamic_pointer_cast(svr); + auto routableServer = std::dynamic_pointer_cast(svr); if(fileServer != nullptr) { return "FileServer"; @@ -760,10 +773,63 @@ namespace Tesses::CrossLang { return "MountableServer"; } - + if(routableServer != nullptr) + { + return "RoutableServer"; + } } return "HttpServer"; + } + if(std::holds_alternative>(_obj)) + { + auto textReader = std::get>(_obj); + if(textReader != nullptr) + { + auto stringReader = std::dynamic_pointer_cast(textReader); + auto streamReader = std::dynamic_pointer_cast(textReader); + auto consoleReader = std::dynamic_pointer_cast(textReader); + if(stringReader != nullptr) + { + return "StringReader"; + } + if(streamReader != nullptr) + { + return "StreamReader"; + } + if(consoleReader != nullptr) + { + return "ConsoleReader"; + } + } + + return "TextReader"; + + } + if(std::holds_alternative>(_obj)) + { + auto textWriter = std::get>(_obj); + if(textWriter != nullptr) + { + auto stringWriter = std::dynamic_pointer_cast(textWriter); + auto streamWriter = std::dynamic_pointer_cast(textWriter); + auto consoleWriter = std::dynamic_pointer_cast(textWriter); + if(stringWriter != nullptr) + { + return "StringWriter"; + } + if(streamWriter != nullptr) + { + return "StreamWriter"; + } + if(consoleWriter != nullptr) + { + return "ConsoleWriter"; + } + } + + return "TextReader"; + } if(std::holds_alternative>(_obj)) { @@ -997,9 +1063,48 @@ namespace Tesses::CrossLang } return nullptr; } - static TObject New_Task(GCList& ls, std::vector args) + static TObject New_Promise(GCList& ls, std::vector args) { - return TTask::Create(ls); + TCallable* call; + + if(GetArgumentHeap(args,0,call)) + { + + TTask* task = TTask::Create(ls); + + TExternalMethod* resolve = TExternalMethod::Create(ls, "fulfill the promise",{"arg"},[task](GCList& ls,std::vector args)->TObject { + if(!args.empty()) + { + task->SetSucceeded(args[0]); + } + return Undefined(); + }); + resolve->watch.push_back(task); + TExternalMethod* reject = TExternalMethod::Create(ls, "reject the promise",{"arg"},[task](GCList& ls,std::vector args)->TObject { + if(!args.empty()) + { + auto item = args[0]; + if(!std::holds_alternative(item)) + { + try { + VMByteCodeException ex(ls.GetGC(),item,nullptr); + throw ex; + } + catch(...) + { + task->SetFailed(std::current_exception()); + } + } + } + return Undefined(); + }); + reject->watch.push_back(task); + + call->Call(ls,{resolve,reject}); + + return task; + } + return nullptr; } static TObject TimeSpan_Parse(GCList& ls, std::vector args) { @@ -1051,6 +1156,72 @@ namespace Tesses::CrossLang } return nullptr; } + static TObject New_StreamReader(GCList& ls, std::vector args) + { + std::shared_ptr strm; + std::shared_ptr vfs; + Tesses::Framework::Filesystem::VFSPath path; + + if(GetArgument(args,0,strm)) + { + return std::make_shared(strm); + } + else if(GetArgument(args,0,vfs) && GetArgumentAsPath(args,1,path)) + { + strm = vfs->OpenFile(path,"rb"); + return std::make_shared(strm); + } + return nullptr; + } + + static TObject New_StreamWriter(GCList& ls, std::vector args) + { + + std::shared_ptr strm; + std::shared_ptr vfs; + Tesses::Framework::Filesystem::VFSPath path; + + if(GetArgument(args,0,strm)) + { + return std::make_shared(strm); + } + else if(GetArgument(args,0,vfs) && GetArgumentAsPath(args,1,path)) + { + bool append=false; + GetArgument(args,2,append); + + strm = vfs->OpenFile(path,append ? "ab" : "wb"); + return std::make_shared(strm); + } + return nullptr; + } + static TObject New_StringReader(GCList& ls, std::vector args) + { + std::string str; + if(GetArgument(args,0,str)) + { + return std::make_shared(str); + } + return nullptr; + } + static TObject New_StringWriter(GCList& ls, std::vector args) + { + std::string str; + if(GetArgument(args,0,str)) + { + return std::make_shared(str); + } + + return std::make_shared(); + } + static TObject Task_FromResult(GCList& ls, std::vector args) + { + if(!args.empty()) + { + return TTask::FromResult(ls,args[0]); + } + return nullptr; + } void TStd::RegisterRoot(GC* gc, TRootEnvironment* env) { GCList ls(gc); @@ -1095,10 +1266,11 @@ namespace Tesses::CrossLang return TTask::Run(ls,closure); return nullptr; }); - + task->DeclareFunction(gc, "FromResult", "async from result", {"result"}, Task_FromResult); TDictionary* newTypes = env->EnsureDictionary(gc, "New"); - + //newTypes->DeclareFunction(gc,) + newTypes->DeclareFunction(gc, "Promise", "Create an async object",{"resolve","reject"},New_Promise); newTypes->DeclareFunction(gc, "DateTime","Create a DateTime object, if only one arg is provided year is epoch, isLocal defaults to true unless epoch",{"year","$month","$day","$hour","$minute","$second","$isLocal"},New_DateTime); newTypes->DeclareFunction(gc, "TimeSpan","Create a DateTime object, if only one arg is provided days is totalSeconds, if there are only three arguments days will be hours, hours will be minutes, minutes will be seconds (according to the argument documentation)",{"days","$hours","$minutes","$seconds"},New_TimeSpan); @@ -1133,7 +1305,18 @@ namespace Tesses::CrossLang return TVMVersion((uint8_t)major,(uint8_t)minor,(uint8_t)patch,(uint16_t)build,stage); }); - + newTypes->DeclareFunction(gc,"Random","Create random number generator",{"$seed"}, [](GCList& ls,std::vector args)->TObject{ + int64_t seed; + if(GetArgument(args,0,seed)) + { + return TNativeObject::Create(ls, (uint64_t)seed); + } + return TNativeObject::Create(ls); + }); + newTypes->DeclareFunction(gc, "StreamReader","Create a StreamReader", {"strmOrVFS","$pathIfVFS"},New_StreamReader); + newTypes->DeclareFunction(gc, "StreamWriter","Create a StreamWriter", {"strmOrVFS","$pathIfVFS","$appendIfVFS"},New_StreamWriter); + newTypes->DeclareFunction(gc, "StringReader","Create a StringReader", {"str"},New_StringReader); + newTypes->DeclareFunction(gc, "StringWriter","Create a StringWriter", {"$str"},New_StringWriter); env->DeclareFunction(gc, "ParseLong","Parse Long from String",{"arg","$base"},ParseLong); env->DeclareFunction(gc, "ParseDouble","Parse Double from String",{"arg"},ParseDouble); @@ -1154,6 +1337,8 @@ namespace Tesses::CrossLang env->DeclareFunction(gc, "TypeIsVFS","Get whether object is a virtual filesystem",{"object"},TypeIsVFS); env->DeclareFunction(gc, "TypeIsDateTime","Get whether object is a DateTime",{"object"},TypeIsDateTime); env->DeclareFunction(gc, "TypeIsTimeSpan","Get whether object is a TimeSpan",{"object"},TypeIsTimeSpan); + env->DeclareFunction(gc, "TypeIsTextReader","Get whether object is a TextReader",{"object"},TypeIsTextReader); + env->DeclareFunction(gc, "TypeIsTextWriter","Get whether object is a TextWriter",{"object"},TypeIsTextWriter); newTypes->DeclareFunction(gc, "Regex", "Create regex object",{"regex"},[](GCList& ls,std::vector args)->TObject { @@ -1200,7 +1385,6 @@ namespace Tesses::CrossLang return TAssociativeArray::Create(ls); }); newTypes->DeclareFunction(gc,"ByteArray","Create bytearray, with optional either size (to size it) or string argument (to fill byte array)",{"$data"},ByteArray); - newTypes->DeclareFunction(gc,"Task","Create a task for async, to manually create an async object",{},New_Task); env->DeclareVariable("Version", TDictionary::Create(ls,{ TDItem("Parse",TExternalMethod::Create(ls,"Parse version from string",{"versionStr"},[](GCList& ls, std::vector args)->TObject{ diff --git a/src/types/random.cpp b/src/types/random.cpp new file mode 100644 index 0000000..de190d6 --- /dev/null +++ b/src/types/random.cpp @@ -0,0 +1,47 @@ +#include "CrossLang.hpp" + +namespace Tesses::CrossLang +{ + TRandom::TRandom() : random() + { + + } + TRandom::TRandom(uint64_t seed) : random(seed) + { + + } + std::string TRandom::TypeName() + { + return "Random"; + } + TObject TRandom::CallMethod(GCList& ls,std::string name, std::vector args) + { + if(name == "Next") + { + int64_t first; + int64_t second; + if(GetArgument(args,0,first)) + { + if(GetArgument(args,1,second)) + { + return (int64_t)random.Next((int32_t)first,(int32_t)second); + } + + return (int64_t)random.Next((uint32_t)first); + } + + return random.Next(); + + } + + if(name == "NextByte") + { + return (int64_t)random.NextByte(); + } + + if(name == "ToString") { + return ""; + } + return Undefined(); + } +} \ No newline at end of file diff --git a/src/types/streamheapobject.cpp b/src/types/streamheapobject.cpp index afb8018..72b3150 100644 --- a/src/types/streamheapobject.cpp +++ b/src/types/streamheapobject.cpp @@ -210,7 +210,11 @@ namespace Tesses::CrossLang } TObjectStream::~TObjectStream() { - Close(); + TDictionary* dict; + if(GetObjectHeap(this->obj, dict)) + { + dict->CallMethod(*ls,"Close",{}); + } delete this->ls; } diff --git a/src/types/vfsheapobject.cpp b/src/types/vfsheapobject.cpp index a504ccb..cf33594 100644 --- a/src/types/vfsheapobject.cpp +++ b/src/types/vfsheapobject.cpp @@ -169,6 +169,26 @@ namespace Tesses::CrossLang { } } + void TObjectVFS::Lock(Tesses::Framework::Filesystem::VFSPath path) + { + TDictionary* dict; + if(GetObjectHeap(this->obj, dict)) + { + GCList ls(this->ls->GetGC()); + dict->CallMethod(ls, "Lock",{path}); + + } + } + void TObjectVFS::Unlock(Tesses::Framework::Filesystem::VFSPath path) + { + TDictionary* dict; + if(GetObjectHeap(this->obj, dict)) + { + GCList ls(this->ls->GetGC()); + dict->CallMethod(ls, "Unlock",{path}); + + } + } bool TObjectVFS::RegularFileExists(Tesses::Framework::Filesystem::VFSPath path) { @@ -573,8 +593,12 @@ namespace Tesses::CrossLang { } TObjectVFS::~TObjectVFS() { - - Close(); + TDictionary* dict; + if(GetObjectHeap(this->obj, dict)) + { + GCList ls(this->ls->GetGC()); + dict->CallMethod(ls,"Close",{}); + } delete this->ls; } diff --git a/src/vm/vm.cpp b/src/vm/vm.cpp index a7e19d3..86cc3e1 100644 --- a/src/vm/vm.cpp +++ b/src/vm/vm.cpp @@ -3411,6 +3411,17 @@ namespace Tesses::CrossLang { cse.back()->Push(gc, nullptr); return false; } + if(key == "ReadLineHttp") + { + std::string line; + if(textReader->ReadLineHttp(line)) + { + cse.back()->Push(gc, line); + return false; + } + cse.back()->Push(gc, nullptr); + return false; + } if(key == "ReadAllLines") { std::vector lines; @@ -3763,6 +3774,7 @@ namespace Tesses::CrossLang { if(svr != nullptr) { auto mountable = std::dynamic_pointer_cast(svr); + auto routable = std::dynamic_pointer_cast(svr); if(mountable != nullptr) { @@ -3793,6 +3805,82 @@ namespace Tesses::CrossLang { } } } + if(routable != nullptr) + { + if(key == "Add") + { + std::string method; + std::string pattern; + TCallable* callable; + if(GetArgument(args,0,method) && GetArgument(args,1,pattern) && GetArgumentHeap(args,2,callable)) + { + routable->Add(method,pattern, callable->ToRouteServerRequestHandler(gc)); + } + } + else if(key == "Delete") + { + std::string pattern; + TCallable* callable; + if(GetArgument(args,0,pattern) && GetArgumentHeap(args,1,callable)) + { + routable->Delete(pattern, callable->ToRouteServerRequestHandler(gc)); + } + } + else if(key == "Get") + { + std::string pattern; + TCallable* callable; + if(GetArgument(args,0,pattern) && GetArgumentHeap(args,1,callable)) + { + routable->Get(pattern, callable->ToRouteServerRequestHandler(gc)); + } + } + else if(key == "Options") + { + std::string pattern; + TCallable* callable; + if(GetArgument(args,0,pattern) && GetArgumentHeap(args,1,callable)) + { + routable->Options(pattern, callable->ToRouteServerRequestHandler(gc)); + } + } + else if(key == "Patch") + { + std::string pattern; + TCallable* callable; + if(GetArgument(args,0,pattern) && GetArgumentHeap(args,1,callable)) + { + routable->Patch(pattern, callable->ToRouteServerRequestHandler(gc)); + } + } + else if(key == "Post") + { + std::string pattern; + TCallable* callable; + if(GetArgument(args,0,pattern) && GetArgumentHeap(args,1,callable)) + { + routable->Post(pattern, callable->ToRouteServerRequestHandler(gc)); + } + } + else if(key == "Put") + { + std::string pattern; + TCallable* callable; + if(GetArgument(args,0,pattern) && GetArgumentHeap(args,1,callable)) + { + routable->Put(pattern, callable->ToRouteServerRequestHandler(gc)); + } + } + else if(key == "Trace") + { + std::string pattern; + TCallable* callable; + if(GetArgument(args,0,pattern) && GetArgumentHeap(args,1,callable)) + { + routable->Trace(pattern, callable->ToRouteServerRequestHandler(gc)); + } + } + } if(key == "Handle") { cse.back()->Push(gc,IHttpServer_Handle(svr,args)); @@ -4107,6 +4195,26 @@ namespace Tesses::CrossLang { cse.back()->Push(gc, nullptr); return false; } + if(key == "Lock") + { + Tesses::Framework::Filesystem::VFSPath filename; + if(GetArgumentAsPath(args,0,filename)) + { + vfs->Lock(filename); + } + cse.back()->Push(gc, nullptr); + return false; + } + if(key == "Unlock") + { + Tesses::Framework::Filesystem::VFSPath filename; + if(GetArgumentAsPath(args,0,filename)) + { + vfs->Unlock(filename); + } + cse.back()->Push(gc, nullptr); + return false; + } if(key == "DeleteDirectoryRecurse") { Tesses::Framework::Filesystem::VFSPath dirname; @@ -4223,28 +4331,6 @@ namespace Tesses::CrossLang { if(ttask != nullptr) { - if(key == "SetSucceeded") - { - if(args.size() > 0) - { - ttask->SetSucceeded(args[0]); - } - cse.back()->Push(gc, Undefined()); - return false; - } - if(key == "SetFailed") - { - if(args.size() > 0) - { - try { - throw VMByteCodeException(gc,args[0],cse.back()); - } catch(...) { - ttask->SetFailed(std::current_exception()); - } - } - cse.back()->Push(gc, Undefined()); - return false; - } if(key == "ContinueWith") { TCallable* callable2; @@ -5581,6 +5667,15 @@ namespace Tesses::CrossLang { if(std::holds_alternative>(instance)) { auto writer = std::get>(instance); + auto stringWriter = std::dynamic_pointer_cast(writer); + if(stringWriter != nullptr) + { + if(key == "Text") + { + cse.back()->Push(gc, stringWriter->GetString()); + return false; + } + } if(key == "NewLine") { cse.back()->Push(gc,writer->newline); @@ -6245,6 +6340,19 @@ namespace Tesses::CrossLang { if(std::holds_alternative>(instance)) { auto writer = std::get>(instance); + auto stringWriter = std::dynamic_pointer_cast(writer); + if(stringWriter != nullptr) + { + if(key == "Text") + { + if(std::holds_alternative(value)) + { + stringWriter->GetString() = std::get(value); + } + cse.back()->Push(gc, stringWriter->GetString()); + return false; + } + } if(key == "NewLine") { if(std::holds_alternative(value))