Add RouteServer, TextReader/TextWriter and file locks

This commit is contained in:
2026-01-12 13:56:49 -06:00
parent a49b61c532
commit e6ce053c2e
15 changed files with 493 additions and 44 deletions

View File

@@ -170,6 +170,7 @@ src/types/vfsheapobject.cpp
src/types/streamheapobject.cpp src/types/streamheapobject.cpp
src/types/class.cpp src/types/class.cpp
src/types/classenvironment.cpp src/types/classenvironment.cpp
src/types/random.cpp
src/vm/filereader.cpp src/vm/filereader.cpp
src/vm/gc.cpp src/vm/gc.cpp
src/vm/gclist.cpp src/vm/gclist.cpp

View File

@@ -4,6 +4,8 @@ using namespace Tesses::CrossLang;
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
TF_InitWithConsole(); TF_InitWithConsole();
if(argc > 0)
TF_AllowPortable(argv[0]);
std::string name = argv[0]; std::string name = argv[0];
Tesses::Framework::Filesystem::VFSPath exePath=Tesses::Framework::Filesystem::LocalFS->SystemToVFSPath(name); Tesses::Framework::Filesystem::VFSPath exePath=Tesses::Framework::Filesystem::LocalFS->SystemToVFSPath(name);
exePath.MakeAbsolute(); exePath.MakeAbsolute();

View File

@@ -3,10 +3,10 @@ mkdir build-x86_64-tar
cd build-x86_64-tar cd build-x86_64-tar
cmake -S ../../.. -B . -DTESSESFRAMEWORK_ENABLE_SHARED=ON -DTESSESFRAMEWORK_ENABLE_STATIC=OFF -DTESSESFRAMEWORK_FETCHCONTENT=ON cmake -S ../../.. -B . -DTESSESFRAMEWORK_ENABLE_SHARED=ON -DTESSESFRAMEWORK_ENABLE_STATIC=OFF -DTESSESFRAMEWORK_FETCHCONTENT=ON
make -j`nproc` make -j`nproc`
make install DESTDIR=./crosslang make install DESTDIR=./crosslang-x86_64
mkdir -p crosslang/share/Tesses/CrossLang mkdir -p crosslang-x86_64/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 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 tar cvzf ../../../artifacts/crosslang-linux-x86_64.tar.gz crosslang-x86_64
cd .. cd ..
foreign() { foreign() {
@@ -14,10 +14,10 @@ mkdir build-$1\-tar
cd 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 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 -j`nproc`
make install DESTDIR=./crosslang make install DESTDIR=./crosslang-$1
mkdir -p crosslang/share/Tesses/CrossLang mkdir -p crosslang-$1\/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 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 tar cvzf ../../../artifacts/crosslang-linux-$1\.tar.gz crosslang-$1
cd .. cd ..
} }
foreign arm64 foreign arm64

View File

@@ -1687,6 +1687,8 @@ class GC {
virtual TObject Call(GCList& ls,std::vector<TObject> args)=0; virtual TObject Call(GCList& ls,std::vector<TObject> args)=0;
TObject CallWithFatalError(GCList& ls, std::vector<TObject> args); TObject CallWithFatalError(GCList& ls, std::vector<TObject> args);
virtual void Mark(); virtual void Mark();
Tesses::Framework::Http::ServerRequestHandler ToRouteServerRequestHandler(GC* gc);
}; };
void ThrowFatalError(std::exception& ex); void ThrowFatalError(std::exception& ex);
@@ -2045,6 +2047,9 @@ class GC {
void CreateHardlink(Tesses::Framework::Filesystem::VFSPath existingFile, Tesses::Framework::Filesystem::VFSPath newName); void CreateHardlink(Tesses::Framework::Filesystem::VFSPath existingFile, Tesses::Framework::Filesystem::VFSPath newName);
bool DirectoryExists(Tesses::Framework::Filesystem::VFSPath path); bool DirectoryExists(Tesses::Framework::Filesystem::VFSPath path);
void DeleteFile(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); void DeleteDirectoryRecurse(Tesses::Framework::Filesystem::VFSPath path);
Tesses::Framework::Filesystem::VFSPathEnumerator EnumeratePaths(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); 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 bool Equals(GC* gc, TObject right);
virtual ~TNativeObject(); 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<TObject> args);
};
class TNative : public THeapObject class TNative : public THeapObject
{ {
std::atomic<bool> destroyed; std::atomic<bool> destroyed;
@@ -2387,7 +2402,7 @@ class GC {
~TNative(); ~TNative();
}; };
class ThreadHandle : public THeapObject { class ThreadHandle : public THeapObject {
public: public:
@@ -2604,4 +2619,6 @@ class GC {
std::string VFSPathToSystem(Tesses::Framework::Filesystem::VFSPath path); std::string VFSPathToSystem(Tesses::Framework::Filesystem::VFSPath path);
Tesses::Framework::Filesystem::VFSPath SystemToVFSPath(std::string path); Tesses::Framework::Filesystem::VFSPath SystemToVFSPath(std::string path);
}; };
}; };

View File

@@ -49,6 +49,8 @@ bool Download(Tesses::Framework::Filesystem::VFSPath filename,std::shared_ptr<Te
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
TF_InitWithConsole(); TF_InitWithConsole();
if(argc > 0)
TF_AllowPortable(argv[0]);

View File

@@ -9,6 +9,8 @@ using namespace Tesses::Framework::Filesystem;
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
TF_InitWithConsole(); TF_InitWithConsole();
if(argc > 0)
TF_AllowPortable(argv[0]);
GC gc; GC gc;
gc.Start(); gc.Start();
GCList ls(gc); GCList ls(gc);

View File

@@ -4,11 +4,14 @@ using namespace Tesses::CrossLang;
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
TF_InitWithConsole(); TF_InitWithConsole();
if(argc < 2) if(argc < 2)
{ {
printf("USAGE: %s <filename.crvm> <args...>\n",argv[0]); printf("USAGE: %s <filename.crvm> <args...>\n",argv[0]);
return 1; return 1;
} }
if(argc > 0)
TF_AllowPortable(argv[0]);
GC gc; GC gc;
gc.Start(); gc.Start();

View File

@@ -320,6 +320,15 @@ namespace Tesses::CrossLang {
dict->DeclareFunction(gc, "getSize", "Get console size",{},Console_getSize); dict->DeclareFunction(gc, "getSize", "Get console size",{},Console_getSize);
gc->BarrierBegin(); gc->BarrierBegin();
env->DeclareVariable("Console", dict); env->DeclareVariable("Console", dict);
auto _new = env->EnsureDictionary(gc,"New");
_new->DeclareFunction(gc,"ConsoleReader","Read from console",{},[](GCList& ls,std::vector<TObject> args)->TObject {
return std::make_shared<Tesses::Framework::TextStreams::ConsoleReader>();
});
_new->DeclareFunction(gc,"ConsoleWriter","Write to console",{"$isStderr"},[](GCList& ls,std::vector<TObject> args)->TObject {
bool err;
if(GetArgument(args,0,err)) return std::make_shared<Tesses::Framework::TextStreams::ConsoleWriter>(err);
return std::make_shared<Tesses::Framework::TextStreams::ConsoleWriter>();
});
gc->BarrierEnd(); gc->BarrierEnd();
} }
} }

View File

@@ -118,6 +118,19 @@ namespace Tesses::CrossLang
} }
return Tesses::Framework::Filesystem::VFSPath(); return Tesses::Framework::Filesystem::VFSPath();
} }
static TObject Env_GetAll(GCList& ls, std::vector<TObject> args)
{
ls.GetGC()->BarrierBegin();
TList* list = TList::Create(ls);
std::vector<std::pair<std::string, std::string>> 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) void TStd::RegisterEnv(GC* gc, TRootEnvironment* env)
{ {
@@ -126,8 +139,9 @@ namespace Tesses::CrossLang
TDictionary* dict = TDictionary::Create(ls); TDictionary* dict = TDictionary::Create(ls);
dict->DeclareFunction(gc,"GetAt","Get environment variable", {"key"}, Env_GetAt); dict->DeclareFunction(gc,"GetAt","Get environment variable", {"key"}, Env_GetAt);
dict->DeclareFunction(gc,"SetAt","Set environment variable", {"key","value"}, Env_SetAt); 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,"getDownloads","Get downloads folder",{},Env_getDownloads);
dict->DeclareFunction(gc,"getDocuments","Get documents folder",{},Env_getDocuments); dict->DeclareFunction(gc,"getDocuments","Get documents folder",{},Env_getDocuments);
dict->DeclareFunction(gc,"getMusic","Get music folder",{},Env_getMusic); dict->DeclareFunction(gc,"getMusic","Get music folder",{},Env_getMusic);

View File

@@ -578,6 +578,7 @@ namespace Tesses::CrossLang
} }
} }
return Undefined(); return Undefined();
} }
@@ -897,7 +898,8 @@ namespace Tesses::CrossLang
~THttpResponse() ~THttpResponse()
{ {
Close(); delete this->response;
this->response = nullptr;
} }
std::string TypeName() std::string TypeName()
{ {
@@ -1478,9 +1480,14 @@ namespace Tesses::CrossLang
} }
static TObject New_MountableServer(GCList& ls, std::vector<TObject> args) static TObject New_MountableServer(GCList& ls, std::vector<TObject> args)
{ {
if(args.empty()) return Undefined(); if(args.empty()) return std::make_shared<MountableServer>();
return std::make_shared<MountableServer>(ToHttpServer(ls.GetGC(),args[0])); return std::make_shared<MountableServer>(ToHttpServer(ls.GetGC(),args[0]));
} }
static TObject New_RouteServer(GCList& ls, std::vector<TObject> args)
{
if(args.empty()) return std::make_shared<RouteServer>();
return std::make_shared<RouteServer>(ToHttpServer(ls.GetGC(),args[0]));
}
static TObject New_StreamHttpRequestBody(GCList& ls, std::vector<TObject> args) static TObject New_StreamHttpRequestBody(GCList& ls, std::vector<TObject> args)
{ {
std::shared_ptr<Stream> strm; std::shared_ptr<Stream> 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<TObject> args)->TObject{ _new->DeclareFunction(gc, "HttpServer", "Create a http server (allows multiple)",{"server","portOrUnixPath","$printIPs"},[env](GCList& ls, std::vector<TObject> args)->TObject{
return New_HttpServer(ls,args,env); 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, "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, "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); _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, "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); http->DeclareFunction(gc, "ListenOnUnusedPort","Listen on unused localhost port and print Port: theport",{"server"},Net_Http_ListenOnUnusedPort);
//FileServer svr() //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, "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, "BasicAuthServer", "Create a basic auth server", {"$server","$auth","$realm"},New_BasicAuthServer);
http->DeclareFunction(gc, "BasicAuthGetCreds","Get creds from str",{"ctx"},[](GCList& ls, std::vector<TObject> args)->TObject { http->DeclareFunction(gc, "BasicAuthGetCreds","Get creds from str",{"ctx"},[](GCList& ls, std::vector<TObject> args)->TObject {
@@ -1604,4 +1615,25 @@ namespace Tesses::CrossLang
dict->SetValue("Smtp", smtp); dict->SetValue("Smtp", smtp);
gc->BarrierEnd(); 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<TServerContext>(ls, &ctx);
bool result;
auto out = this->Call(ls,{res});
if(GetObject(out,result))
{
res->Finish();
return result;
}
res->Finish();
return false;
};
}
} }

View File

@@ -556,6 +556,18 @@ namespace Tesses::CrossLang
std::shared_ptr<Tesses::Framework::Streams::Stream> strm; std::shared_ptr<Tesses::Framework::Streams::Stream> strm;
return GetArgument(args,0,strm); return GetArgument(args,0,strm);
} }
static TObject TypeIsTextReader(GCList& ls, std::vector<TObject> args)
{
if(args.empty()) return nullptr;
std::shared_ptr<Tesses::Framework::TextStreams::TextReader> strm;
return GetArgument(args,0,strm);
}
static TObject TypeIsTextWriter(GCList& ls, std::vector<TObject> args)
{
if(args.empty()) return nullptr;
std::shared_ptr<Tesses::Framework::TextStreams::TextWriter> strm;
return GetArgument(args,0,strm);
}
static TObject TypeIsVFS(GCList& ls, std::vector<TObject> args) static TObject TypeIsVFS(GCList& ls, std::vector<TObject> args)
{ {
if(args.empty()) return nullptr; if(args.empty()) return nullptr;
@@ -752,6 +764,7 @@ namespace Tesses::CrossLang
{ {
auto fileServer = std::dynamic_pointer_cast<Tesses::Framework::Http::FileServer>(svr); auto fileServer = std::dynamic_pointer_cast<Tesses::Framework::Http::FileServer>(svr);
auto mountableServer = std::dynamic_pointer_cast<Tesses::Framework::Http::MountableServer>(svr); auto mountableServer = std::dynamic_pointer_cast<Tesses::Framework::Http::MountableServer>(svr);
auto routableServer = std::dynamic_pointer_cast<Tesses::Framework::Http::RouteServer>(svr);
if(fileServer != nullptr) if(fileServer != nullptr)
{ {
return "FileServer"; return "FileServer";
@@ -760,10 +773,63 @@ namespace Tesses::CrossLang
{ {
return "MountableServer"; return "MountableServer";
} }
if(routableServer != nullptr)
{
return "RoutableServer";
}
} }
return "HttpServer"; return "HttpServer";
}
if(std::holds_alternative<std::shared_ptr<Tesses::Framework::TextStreams::TextReader>>(_obj))
{
auto textReader = std::get<std::shared_ptr<Tesses::Framework::TextStreams::TextReader>>(_obj);
if(textReader != nullptr)
{
auto stringReader = std::dynamic_pointer_cast<Tesses::Framework::TextStreams::StringReader>(textReader);
auto streamReader = std::dynamic_pointer_cast<Tesses::Framework::TextStreams::StreamReader>(textReader);
auto consoleReader = std::dynamic_pointer_cast<Tesses::Framework::TextStreams::ConsoleReader>(textReader);
if(stringReader != nullptr)
{
return "StringReader";
}
if(streamReader != nullptr)
{
return "StreamReader";
}
if(consoleReader != nullptr)
{
return "ConsoleReader";
}
}
return "TextReader";
}
if(std::holds_alternative<std::shared_ptr<Tesses::Framework::TextStreams::TextWriter>>(_obj))
{
auto textWriter = std::get<std::shared_ptr<Tesses::Framework::TextStreams::TextWriter>>(_obj);
if(textWriter != nullptr)
{
auto stringWriter = std::dynamic_pointer_cast<Tesses::Framework::TextStreams::StringWriter>(textWriter);
auto streamWriter = std::dynamic_pointer_cast<Tesses::Framework::TextStreams::StreamWriter>(textWriter);
auto consoleWriter = std::dynamic_pointer_cast<Tesses::Framework::TextStreams::ConsoleReader>(textWriter);
if(stringWriter != nullptr)
{
return "StringWriter";
}
if(streamWriter != nullptr)
{
return "StreamWriter";
}
if(consoleWriter != nullptr)
{
return "ConsoleWriter";
}
}
return "TextReader";
} }
if(std::holds_alternative<std::shared_ptr<Tesses::Framework::Filesystem::VFS>>(_obj)) if(std::holds_alternative<std::shared_ptr<Tesses::Framework::Filesystem::VFS>>(_obj))
{ {
@@ -997,9 +1063,48 @@ namespace Tesses::CrossLang
} }
return nullptr; return nullptr;
} }
static TObject New_Task(GCList& ls, std::vector<TObject> args) static TObject New_Promise(GCList& ls, std::vector<TObject> 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<TObject> 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<TObject> args)->TObject {
if(!args.empty())
{
auto item = args[0];
if(!std::holds_alternative<Undefined>(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<TObject> args) static TObject TimeSpan_Parse(GCList& ls, std::vector<TObject> args)
{ {
@@ -1051,6 +1156,72 @@ namespace Tesses::CrossLang
} }
return nullptr; return nullptr;
} }
static TObject New_StreamReader(GCList& ls, std::vector<TObject> args)
{
std::shared_ptr<Tesses::Framework::Streams::Stream> strm;
std::shared_ptr<Tesses::Framework::Filesystem::VFS> vfs;
Tesses::Framework::Filesystem::VFSPath path;
if(GetArgument(args,0,strm))
{
return std::make_shared<Tesses::Framework::TextStreams::StreamReader>(strm);
}
else if(GetArgument(args,0,vfs) && GetArgumentAsPath(args,1,path))
{
strm = vfs->OpenFile(path,"rb");
return std::make_shared<Tesses::Framework::TextStreams::StreamReader>(strm);
}
return nullptr;
}
static TObject New_StreamWriter(GCList& ls, std::vector<TObject> args)
{
std::shared_ptr<Tesses::Framework::Streams::Stream> strm;
std::shared_ptr<Tesses::Framework::Filesystem::VFS> vfs;
Tesses::Framework::Filesystem::VFSPath path;
if(GetArgument(args,0,strm))
{
return std::make_shared<Tesses::Framework::TextStreams::StreamWriter>(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<Tesses::Framework::TextStreams::StreamWriter>(strm);
}
return nullptr;
}
static TObject New_StringReader(GCList& ls, std::vector<TObject> args)
{
std::string str;
if(GetArgument(args,0,str))
{
return std::make_shared<Tesses::Framework::TextStreams::StringReader>(str);
}
return nullptr;
}
static TObject New_StringWriter(GCList& ls, std::vector<TObject> args)
{
std::string str;
if(GetArgument(args,0,str))
{
return std::make_shared<Tesses::Framework::TextStreams::StringWriter>(str);
}
return std::make_shared<Tesses::Framework::TextStreams::StringWriter>();
}
static TObject Task_FromResult(GCList& ls, std::vector<TObject> args)
{
if(!args.empty())
{
return TTask::FromResult(ls,args[0]);
}
return nullptr;
}
void TStd::RegisterRoot(GC* gc, TRootEnvironment* env) void TStd::RegisterRoot(GC* gc, TRootEnvironment* env)
{ {
GCList ls(gc); GCList ls(gc);
@@ -1095,10 +1266,11 @@ namespace Tesses::CrossLang
return TTask::Run(ls,closure); return TTask::Run(ls,closure);
return nullptr; return nullptr;
}); });
task->DeclareFunction(gc, "FromResult", "async from result", {"result"}, Task_FromResult);
TDictionary* newTypes = env->EnsureDictionary(gc, "New"); 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, "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); 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); 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<TObject> args)->TObject{
int64_t seed;
if(GetArgument(args,0,seed))
{
return TNativeObject::Create<TRandom>(ls, (uint64_t)seed);
}
return TNativeObject::Create<TRandom>(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, "ParseLong","Parse Long from String",{"arg","$base"},ParseLong);
env->DeclareFunction(gc, "ParseDouble","Parse Double from String",{"arg"},ParseDouble); 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, "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, "TypeIsDateTime","Get whether object is a DateTime",{"object"},TypeIsDateTime);
env->DeclareFunction(gc, "TypeIsTimeSpan","Get whether object is a TimeSpan",{"object"},TypeIsTimeSpan); 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<TObject> args)->TObject { newTypes->DeclareFunction(gc, "Regex", "Create regex object",{"regex"},[](GCList& ls,std::vector<TObject> args)->TObject {
@@ -1200,7 +1385,6 @@ namespace Tesses::CrossLang
return TAssociativeArray::Create(ls); 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,"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,{ env->DeclareVariable("Version", TDictionary::Create(ls,{
TDItem("Parse",TExternalMethod::Create(ls,"Parse version from string",{"versionStr"},[](GCList& ls, std::vector<TObject> args)->TObject{ TDItem("Parse",TExternalMethod::Create(ls,"Parse version from string",{"versionStr"},[](GCList& ls, std::vector<TObject> args)->TObject{

47
src/types/random.cpp Normal file
View File

@@ -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<TObject> 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();
}
}

View File

@@ -210,7 +210,11 @@ namespace Tesses::CrossLang
} }
TObjectStream::~TObjectStream() TObjectStream::~TObjectStream()
{ {
Close(); TDictionary* dict;
if(GetObjectHeap(this->obj, dict))
{
dict->CallMethod(*ls,"Close",{});
}
delete this->ls; delete this->ls;
} }

View File

@@ -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) bool TObjectVFS::RegularFileExists(Tesses::Framework::Filesystem::VFSPath path)
{ {
@@ -573,8 +593,12 @@ namespace Tesses::CrossLang {
} }
TObjectVFS::~TObjectVFS() TObjectVFS::~TObjectVFS()
{ {
TDictionary* dict;
Close(); if(GetObjectHeap(this->obj, dict))
{
GCList ls(this->ls->GetGC());
dict->CallMethod(ls,"Close",{});
}
delete this->ls; delete this->ls;
} }

View File

@@ -3411,6 +3411,17 @@ namespace Tesses::CrossLang {
cse.back()->Push(gc, nullptr); cse.back()->Push(gc, nullptr);
return false; 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") if(key == "ReadAllLines")
{ {
std::vector<std::string> lines; std::vector<std::string> lines;
@@ -3763,6 +3774,7 @@ namespace Tesses::CrossLang {
if(svr != nullptr) if(svr != nullptr)
{ {
auto mountable = std::dynamic_pointer_cast<Tesses::Framework::Http::MountableServer>(svr); auto mountable = std::dynamic_pointer_cast<Tesses::Framework::Http::MountableServer>(svr);
auto routable = std::dynamic_pointer_cast<Tesses::Framework::Http::RouteServer>(svr);
if(mountable != nullptr) 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") if(key == "Handle")
{ {
cse.back()->Push(gc,IHttpServer_Handle(svr,args)); cse.back()->Push(gc,IHttpServer_Handle(svr,args));
@@ -4107,6 +4195,26 @@ namespace Tesses::CrossLang {
cse.back()->Push(gc, nullptr); cse.back()->Push(gc, nullptr);
return false; 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") if(key == "DeleteDirectoryRecurse")
{ {
Tesses::Framework::Filesystem::VFSPath dirname; Tesses::Framework::Filesystem::VFSPath dirname;
@@ -4223,28 +4331,6 @@ namespace Tesses::CrossLang {
if(ttask != nullptr) 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") if(key == "ContinueWith")
{ {
TCallable* callable2; TCallable* callable2;
@@ -5581,6 +5667,15 @@ namespace Tesses::CrossLang {
if(std::holds_alternative<std::shared_ptr<Tesses::Framework::TextStreams::TextWriter>>(instance)) if(std::holds_alternative<std::shared_ptr<Tesses::Framework::TextStreams::TextWriter>>(instance))
{ {
auto writer = std::get<std::shared_ptr<Tesses::Framework::TextStreams::TextWriter>>(instance); auto writer = std::get<std::shared_ptr<Tesses::Framework::TextStreams::TextWriter>>(instance);
auto stringWriter = std::dynamic_pointer_cast<Tesses::Framework::TextStreams::StringWriter>(writer);
if(stringWriter != nullptr)
{
if(key == "Text")
{
cse.back()->Push(gc, stringWriter->GetString());
return false;
}
}
if(key == "NewLine") if(key == "NewLine")
{ {
cse.back()->Push(gc,writer->newline); cse.back()->Push(gc,writer->newline);
@@ -6245,6 +6340,19 @@ namespace Tesses::CrossLang {
if(std::holds_alternative<std::shared_ptr<Tesses::Framework::TextStreams::TextWriter>>(instance)) if(std::holds_alternative<std::shared_ptr<Tesses::Framework::TextStreams::TextWriter>>(instance))
{ {
auto writer = std::get<std::shared_ptr<Tesses::Framework::TextStreams::TextWriter>>(instance); auto writer = std::get<std::shared_ptr<Tesses::Framework::TextStreams::TextWriter>>(instance);
auto stringWriter = std::dynamic_pointer_cast<Tesses::Framework::TextStreams::StringWriter>(writer);
if(stringWriter != nullptr)
{
if(key == "Text")
{
if(std::holds_alternative<std::string>(value))
{
stringWriter->GetString() = std::get<std::string>(value);
}
cse.back()->Push(gc, stringWriter->GetString());
return false;
}
}
if(key == "NewLine") if(key == "NewLine")
{ {
if(std::holds_alternative<std::string>(value)) if(std::holds_alternative<std::string>(value))