Files
crosslang/src/runtime_methods/net.cpp
T

1623 lines
62 KiB
C++

#include "CrossLang.hpp"
#include <TessesFramework/Crypto/ClientTLSStream.hpp>
#include <TessesFramework/Http/HttpClient.hpp>
#include <TessesFramework/Mail/Smtp.hpp>
#include <TessesFramework/Streams/MemoryStream.hpp>
#include <TessesFramework/Streams/NetworkStream.hpp>
#include <TessesFramework/Streams/Stream.hpp>
#include <csignal>
#include <cstring>
#include <iostream>
#include <sys/types.h>
using namespace Tesses::Framework::Streams;
using namespace Tesses::Framework::Http;
using namespace Tesses::Framework::Mail;
namespace Tesses::CrossLang {
static std::shared_ptr<SMTPBody>
TObjectToSMTPBody(GCList &ls, std::string mimeType, TObject obj) {
std::shared_ptr<SMTPBody> body;
std::string text;
TByteArray *ba;
std::shared_ptr<Tesses::Framework::Streams::Stream> sho;
if (GetObject(obj, text)) {
body = std::make_shared<SMTPStringBody>(text, mimeType);
} else if (GetObjectHeap(obj, ba)) {
std::shared_ptr<MemoryStream> ms = std::make_shared<MemoryStream>(true);
ms->WriteBlock(ba->data.data(), ba->data.size());
ms->Seek(0L, SeekOrigin::Begin);
body = std::make_shared<SMTPStreamBody>(mimeType, ms);
} else if (GetObject(obj, sho)) {
ls.Add(sho);
body = std::make_shared<SMTPStreamBody>(mimeType, sho);
}
return body;
}
class TNativeObjectThatReturnsHttpDictionary : public TNativeObject {
public:
virtual bool IsAvailable() = 0;
};
class DummyTNativeObjectThatReturnsHttpDictionary
: public TNativeObjectThatReturnsHttpDictionary {
bool isAvail;
public:
DummyTNativeObjectThatReturnsHttpDictionary() { this->isAvail = true; }
bool IsAvailable() { return this->isAvail; }
void Close() { this->isAvail = false; }
std::string TypeName() { return "Dummy"; }
TObject CallMethod(GCList &ls, std::string key, std::vector<TObject> args) {
return Undefined();
}
};
class THttpDictionary : public TNativeObject {
TNativeObjectThatReturnsHttpDictionary *ctx;
HttpDictionary *dict;
public:
THttpDictionary(HttpDictionary *dict,
TNativeObjectThatReturnsHttpDictionary *ctx) {
this->dict = dict;
this->ctx = ctx;
}
std::string TypeName() { return "Net.Http.HttpDictionary"; }
void Mark() {
if (this->marked)
return;
this->marked = true;
ctx->Mark();
}
TObject CallMethod(GCList &ls, std::string key, std::vector<TObject> args) {
if (!ctx->IsAvailable())
return Undefined();
else if (key == "AddValue") {
std::string key;
std::string value;
int64_t i64;
double d64;
std::shared_ptr<Tesses::Framework::Date::DateTime> da;
if (GetArgument(args, 0, key)) {
if (GetArgument(args, 1, value))
this->dict->AddValue(key, value);
else if (GetArgument(args, 1, i64))
this->dict->AddValue(key, i64);
else if (GetArgument(args, 1, d64))
this->dict->AddValue(key, d64);
else if (GetArgument(args, 1, da))
this->dict->AddValue(key, *da);
}
} else if (key == "SetValue") {
std::string key;
std::string value;
int64_t i64;
double d64;
std::shared_ptr<Tesses::Framework::Date::DateTime> da;
if (GetArgument(args, 0, key)) {
if (GetArgument(args, 1, value))
this->dict->SetValue(key, value);
else if (GetArgument(args, 1, i64))
this->dict->SetValue(key, i64);
else if (GetArgument(args, 1, d64))
this->dict->SetValue(key, d64);
else if (GetArgument(args, 1, da))
this->dict->SetValue(key, *da);
}
} else if (key == "Clear") {
std::string key;
bool existsAfter;
if (GetArgument(args, 0, key) && GetArgument(args, 0, existsAfter))
dict->Clear(key, existsAfter);
else
dict->Clear();
} else if (key == "GetFirstBoolean") {
std::string key;
if (GetArgument(args, 0, key)) {
return dict->GetFirstBoolean(key);
}
return false;
} else if (key == "TryGetFirst") {
std::string key;
std::string value;
if (GetArgument(args, 0, key) && dict->TryGetFirst(key, value)) {
return value;
}
return nullptr;
} else if (key == "TryGetFirstDouble") {
std::string key;
double value;
if (GetArgument(args, 0, key) &&
dict->TryGetFirstDouble(key, value)) {
return value;
}
return nullptr;
} else if (key == "TryGetFirstInt") {
std::string key;
int64_t value;
if (GetArgument(args, 0, key) && dict->TryGetFirstInt(key, value)) {
return value;
}
return nullptr;
} else if (key == "TryGetFirstDate") {
std::string key;
Tesses::Framework::Date::DateTime value;
if (GetArgument(args, 0, key) &&
dict->TryGetFirstDate(key, value)) {
return std::make_shared<Tesses::Framework::Date::DateTime>(
value);
}
return nullptr;
} else if (key == "TryGetOnlyOne") {
std::string key;
std::string value;
if (GetArgument(args, 0, key) && dict->TryGetOnlyOne(key, value)) {
return value;
}
return nullptr;
} else if (key == "TryGetOnlyOneBoolean") {
std::string key;
bool value;
if (GetArgument(args, 0, key) &&
dict->TryGetOnlyOneBoolean(key, value)) {
return value;
}
return nullptr;
} else if (key == "TryGetOnlyOneDouble") {
std::string key;
double value;
if (GetArgument(args, 0, key) &&
dict->TryGetOnlyOneDouble(key, value)) {
return value;
}
return nullptr;
} else if (key == "TryGetOnlyOneInt") {
std::string key;
int64_t value;
if (GetArgument(args, 0, key) &&
dict->TryGetOnlyOneInt(key, value)) {
return value;
}
return nullptr;
} else if (key == "TryGetOnlyOneDate") {
std::string key;
Tesses::Framework::Date::DateTime value;
if (GetArgument(args, 0, key) &&
dict->TryGetOnlyOneDate(key, value)) {
return std::make_shared<Tesses::Framework::Date::DateTime>(
value);
}
return nullptr;
} else if (key == "ToList") {
TList *_ls = TList::Create(ls);
for (auto item : dict->kvp) {
for (auto i : item.second) {
auto d = TDictionary::Create(ls);
ls.GetGC()->BarrierBegin();
d->SetValue("Key", item.first);
d->SetValue("Value", i);
_ls->Add(d);
ls.GetGC()->BarrierEnd();
}
}
return _ls;
} else if (key == "SetContentDisposition") {
std::string type;
std::string filename;
std::string fieldName;
if (GetArgument(args, 0, filename) && GetArgument(args, 1, type)) {
ContentDisposition dispo;
dispo.filename = filename;
dispo.type = type;
if (GetArgument(args, 2, fieldName))
dispo.fieldName = fieldName;
this->dict->SetValue("Content-Disposition", dispo.ToString());
}
return nullptr;
} else if (key == "TryGetContentDisposition") {
std::string cdStr;
ContentDisposition cd;
if (this->dict->TryGetFirst("Content-Disposition", cdStr) &&
ContentDisposition::TryParse(cdStr, cd)) {
return TDictionary::Create(ls,
{TDItem("Type", cd.type),
TDItem("FileName", cd.filename),
TDItem("FieldName", cd.fieldName)});
}
return nullptr;
}
return Undefined();
}
};
class TServerContext : public TNativeObjectThatReturnsHttpDictionary {
ServerContext *ctx;
public:
TServerContext(ServerContext *ctx) { this->ctx = ctx; }
std::string TypeName() { return "Net.Http.ServerContext"; }
bool IsAvailable() { return ctx != nullptr; }
ServerContext *GetContext() { return this->ctx; }
TObject CallMethod(GCList &ls, std::string key, std::vector<TObject> args) {
if (this->ctx == nullptr)
return Undefined();
else if (key == "getEncrypted")
return ctx->encrypted;
else if (key == "getMethod")
return ctx->method;
else if (key == "getIP")
return ctx->ip;
else if (key == "getPort")
return (int64_t)ctx->port;
else if (key == "getOriginalPath")
return ctx->originalPath;
else if (key == "getPath")
return ctx->path;
else if (key == "setPath") {
std::string str;
if (GetArgument(args, 0, str)) {
ctx->path = str;
return str;
}
} else if (key == "getVersion")
return ctx->version;
else if (key == "setStatusCode") {
int64_t sc;
if (GetArgument(args, 0, sc)) {
ctx->statusCode = (StatusCode)sc;
return sc;
}
} else if (key == "getStatusCode")
return (int64_t)ctx->statusCode;
else if (key == "getQueryParams")
return TNativeObject::Create<THttpDictionary>(ls, &ctx->queryParams,
this);
else if (key == "getBodyParams")
return TNativeObject::Create<THttpDictionary>(ls, &ctx->bodyParams,
this);
else if (key == "getRequestHeaders")
return TNativeObject::Create<THttpDictionary>(
ls, &ctx->requestHeaders, this);
else if (key == "getResponseHeaders")
return TNativeObject::Create<THttpDictionary>(
ls, &ctx->responseHeaders, this);
else if (key == "getPathArguments")
return TNativeObject::Create<THttpDictionary>(
ls, &ctx->pathArguments, this);
else if (key == "GetStream")
return ctx->GetStream();
else if (key == "OpenRequestStream")
return ctx->OpenRequestStream();
else if (key == "OpenResponseStream")
return ctx->OpenResponseStream();
else if (key == "ParseFormData") {
TCallable *callable;
std::shared_ptr<Tesses::Framework::Filesystem::VFS> vfs;
if (GetArgumentHeap(args, 0, callable)) {
ctx->ParseFormData(
[callable, &ls](std::string a, std::string b, std::string c)
-> std::shared_ptr<Tesses::Framework::Streams::Stream> {
auto res = callable->Call(ls, {a, b, c});
std::shared_ptr<Tesses::Framework::Streams::Stream>
strm;
if (GetObject(res, strm)) {
return strm;
}
return nullptr;
});
} else if (GetArgument(args, 0, vfs)) {
int i = 1;
std::vector<TObject> response;
ctx->ParseFormData(
[vfs, &response, &ls, &i](std::string mime,
std::string filename,
std::string name)
-> std::shared_ptr<Tesses::Framework::Streams::Stream> {
std::string realFileName =
"/" + std::to_string(i) + ".bin";
i++;
response.push_back(TDictionary::Create(
ls, {TDItem("RealFileName", realFileName),
TDItem("FileName", filename),
TDItem("Mime", mime), TDItem("Name", name)}));
auto strm = vfs->OpenFile(realFileName, "wb");
return strm;
});
return TList::Create(ls, response.begin(), response.end());
}
} else if (key == "getNeedToParseFormData")
return ctx->NeedToParseFormData();
else if (key == "ReadString")
return ctx->ReadString();
else if (key == "ReadStream") {
std::shared_ptr<Tesses::Framework::Streams::Stream> strm;
if (GetArgument(args, 0, strm)) {
ctx->ReadStream(strm);
}
} else if (key == "ReadJson") {
return Json_Decode(ls, ctx->ReadString());
} else if (key == "SendJson") {
if (args.size() > 0) {
ctx->WithMimeType("application/json")
.SendText(Json_Encode(args[0]));
}
} else if (key == "SendText") {
std::string text;
if (GetArgument(args, 0, text))
ctx->SendText(text);
} else if (key == "WithMimeType") {
std::string text;
if (GetArgument(args, 0, text))
ctx->WithMimeType(text);
return this;
} else if (key == "WithLastModified") {
std::shared_ptr<Tesses::Framework::Date::DateTime> da;
if (GetArgument(args, 0, da))
ctx->WithLastModified(*da);
return this;
} else if (key == "WithDebug") {
bool debug = true;
GetArgument(args, 0, debug);
ctx->WithDebug(debug);
return this;
}
else if (key == "getDebug") {
return ctx->Debug();
} else if (key == "SendServerSentEvents") {
if (!args.empty() &&
std::holds_alternative<
std::shared_ptr<Tesses::Framework::Http::ServerSentEvents>>(
args[0])) {
ctx->SendServerSentEvents(
std::get<std::shared_ptr<
Tesses::Framework::Http::ServerSentEvents>>(args[0]));
}
} else if (key == "WithHeaderIntercepter") {
TCallable *callable;
if (GetArgumentHeap(args, 0, callable)) {
auto marked = CreateMarkedTObject(ls.GetGC(), callable);
ctx->WithHeaderIntercepter(
[marked](ServerContext &ctx) -> bool {
auto obj = marked->GetObject();
TCallable *callable;
if (GetObjectHeap(obj, callable)) {
GCList ls(marked->GetGC());
auto ptr =
TNativeObject::Create<TServerContext>(ls, &ctx);
auto res = callable->Call(ls, {ptr});
ptr->Finish();
bool r0;
if (GetObject(res, r0))
return r0;
}
return false;
});
}
return this;
} else if (key == "WithContentDisposition") {
std::string filename;
bool isInline;
if (GetArgument(args, 0, filename) &&
GetArgument(args, 1, isInline))
ctx->WithContentDisposition(filename, isInline);
return this;
} else if (key == "WithHeader") {
std::string key;
std::string value;
if (GetArgument(args, 0, key) && GetArgument(args, 1, value))
ctx->WithHeader(key, value);
return this;
} else if (key == "WithSingleHeader") {
std::string key;
std::string value;
if (GetArgument(args, 0, key) && GetArgument(args, 1, value))
ctx->WithSingleHeader(key, value);
return this;
} else if (key == "SendStream") {
std::shared_ptr<Tesses::Framework::Streams::Stream> strm;
if (GetArgument(args, 0, strm))
ctx->SendStream(strm);
} else if (key == "SendBytes") {
TByteArray *ba;
if (GetArgumentHeap(args, 0, ba))
ctx->SendBytes(ba->data);
} else if (key == "GetUrlWithQuery") {
return ctx->GetUrlWithQuery();
} else if (key == "GetOriginalPathWithQuery") {
return ctx->GetOriginalPathWithQuery();
} else if (key == "MakeAbsolute") {
std::string path;
if (GetArgument(args, 0, path)) {
return ctx->MakeAbsolute(path);
}
return nullptr;
} else if (key == "WithLocationHeader") {
std::string path;
if (GetArgument(args, 0, path)) {
int64_t sc;
if (GetArgument(args, 1, sc)) {
ctx->WithLocationHeader(path, (StatusCode)sc);
return nullptr;
}
ctx->WithLocationHeader(path);
}
return this;
} else if (key == "GetServerRoot") {
return ctx->GetServerRoot();
} else if (key == "SendRedirect") {
std::string path;
if (GetArgument(args, 0, path)) {
int64_t sc;
if (GetArgument(args, 1, sc)) {
ctx->SendRedirect(path, (StatusCode)sc);
return nullptr;
}
ctx->SendRedirect(path);
}
return nullptr;
} else if (key == "WriteHeaders")
ctx->WriteHeaders();
else if (key == "StartWebSocketSession") {
TDictionary *dict;
TClassObject *cls;
if (GetArgumentHeap(args, 0, dict)) {
ctx->StartWebSocketSession(
[dict,
&ls](std::function<void(WebSocketMessage &)> sendMessage,
std::function<void()> ping,
std::function<void()> close) -> void {
GCList ls2(ls.GetGC());
dict->CallMethod(
ls2, "Open",
{TExternalMethod::Create(
ls2, "Send a message",
{"messageTextOrByteArray"},
[sendMessage](
GCList &ls,
std::vector<TObject> args) -> TObject {
std::string str;
TByteArray *bArray;
if (GetArgument(args, 0, str)) {
WebSocketMessage msg(str);
sendMessage(msg);
} else if (GetArgumentHeap(args, 0,
bArray)) {
WebSocketMessage msg(bArray->data);
sendMessage(msg);
}
return nullptr;
}),
TExternalMethod::Create(
ls2, "Ping client", {},
[ping](GCList &ls,
std::vector<TObject> args) -> TObject {
ping();
return nullptr;
}),
TExternalMethod::Create(
ls2, "Close client", {},
[close](GCList &ls,
std::vector<TObject> args) -> TObject {
close();
return nullptr;
})});
},
[dict, &ls](WebSocketMessage &msg) -> void {
GCList ls2(ls.GetGC());
TObject v;
if (msg.isBinary) {
auto r = TByteArray::Create(ls2);
r->data = msg.data;
v = r;
} else {
v = msg.ToString();
}
dict->CallMethod(ls2, "Receive", {v});
},
[dict, &ls](bool close) -> void {
GCList ls2(ls.GetGC());
dict->CallMethod(ls2, "Close", {close});
});
} else if (GetArgumentHeap(args, 0, cls)) {
ctx->StartWebSocketSession(
[cls,
&ls](std::function<void(WebSocketMessage &)> sendMessage,
std::function<void()> ping,
std::function<void()> close) -> void {
GCList ls2(ls.GetGC());
cls->CallMethod(
ls2, "", "Open",
{TExternalMethod::Create(
ls2, "Send a message",
{"messageTextOrByteArray"},
[sendMessage](
GCList &ls,
std::vector<TObject> args) -> TObject {
std::string str;
TByteArray *bArray;
if (GetArgument(args, 0, str)) {
WebSocketMessage msg(str);
sendMessage(msg);
} else if (GetArgumentHeap(args, 0,
bArray)) {
WebSocketMessage msg(bArray->data);
sendMessage(msg);
}
return nullptr;
}),
TExternalMethod::Create(
ls2, "Ping client", {},
[ping](GCList &ls,
std::vector<TObject> args) -> TObject {
ping();
return nullptr;
}),
TExternalMethod::Create(
ls2, "Close client", {},
[close](GCList &ls,
std::vector<TObject> args) -> TObject {
close();
return nullptr;
})});
},
[cls, &ls](WebSocketMessage &msg) -> void {
GCList ls2(ls.GetGC());
TObject v;
if (msg.isBinary) {
auto r = TByteArray::Create(ls2);
r->data = msg.data;
v = r;
} else {
v = msg.ToString();
}
cls->CallMethod(ls2, "", "Receive", {v});
},
[cls, &ls](bool close) -> void {
GCList ls2(ls.GetGC());
cls->CallMethod(ls2, "", "Close", {close});
});
}
}
return Undefined();
}
void Finish() { this->ctx = nullptr; }
};
TObjectHttpServer::TObjectHttpServer(std::shared_ptr<GC> gc, TObject obj) {
this->ls = new GCList(gc);
this->ls->Add(obj);
this->obj = obj;
}
class TDictionaryHttpRequestBody : public HttpRequestBody {
std::shared_ptr<GC> gc;
TDictionary *req;
public:
TDictionaryHttpRequestBody(std::shared_ptr<GC> gc, TDictionary *req) {
this->gc = gc;
this->req = req;
}
void HandleHeaders(HttpDictionary &dict) {
GCList ls(gc);
auto dummy =
TNativeObject::Create<DummyTNativeObjectThatReturnsHttpDictionary>(
ls);
auto res = TNativeObject::Create<THttpDictionary>(ls, &dict, dummy);
req->CallMethod(ls, "HandleHeaders", {res});
dummy->Close();
}
void Write(std::shared_ptr<Tesses::Framework::Streams::Stream> strm) {
GCList ls(gc);
req->CallMethod(ls, "Write", {strm});
}
~TDictionaryHttpRequestBody() {
GCList ls(gc);
req->CallMethod(ls, "Close", {});
}
};
bool TObjectHttpServer::Handle(ServerContext &ctx) {
TCallable *callable;
TDictionary *dict;
TClassObject *clsObj;
if (GetObjectHeap<TCallable *>(this->obj, callable)) {
GCList ls2(this->ls->GetGC());
auto res = TNativeObject::Create<TServerContext>(ls2, &ctx);
bool result;
auto out = callable->Call(ls2, {res});
if (GetObject(out, result)) {
res->Finish();
return result;
}
res->Finish();
} else if (GetObjectHeap<TDictionary *>(this->obj, dict)) {
GCList ls2(this->ls->GetGC());
auto res = TNativeObject::Create<TServerContext>(ls2, &ctx);
bool result;
auto out = dict->CallMethod(ls2, "Handle", {res});
if (GetObject(out, result)) {
res->Finish();
return result;
}
res->Finish();
} else if (GetObjectHeap(this->obj, clsObj) &&
clsObj->HasMethod("", "Handle")) {
GCList ls2(this->ls->GetGC());
auto res = TNativeObject::Create<TServerContext>(ls2, &ctx);
bool result;
this->ls->GetGC()->BarrierBegin();
auto callableO = clsObj->GetValue("", "Handle");
this->ls->GetGC()->BarrierEnd();
TCallable *callable;
if (GetObjectHeap(callableO, callable)) {
auto out = callable->Call(ls2, {res});
if (GetObject(out, result)) {
res->Finish();
return result;
}
res->Finish();
}
}
return false;
}
TObjectHttpServer::~TObjectHttpServer() { delete ls; }
static TObject Net_UrlDecode(GCList &ls, std::vector<TObject> args) {
if (args.size() == 1 && std::holds_alternative<std::string>(args[0])) {
return HttpUtils::UrlDecode(std::get<std::string>(args[0]));
}
return Undefined();
}
static TObject Net_HtmlEncode(GCList &ls, std::vector<TObject> args) {
if (args.size() == 1 && std::holds_alternative<std::string>(args[0])) {
return HttpUtils::HtmlEncode(std::get<std::string>(args[0]));
}
return Undefined();
}
static TObject Net_UrlEncode(GCList &ls, std::vector<TObject> args) {
if (args.size() == 1 && std::holds_alternative<std::string>(args[0])) {
return HttpUtils::UrlEncode(std::get<std::string>(args[0]));
}
return Undefined();
}
static TObject Net_UrlPathDecode(GCList &ls, std::vector<TObject> args) {
if (args.size() == 1 && std::holds_alternative<std::string>(args[0])) {
return HttpUtils::UrlPathDecode(std::get<std::string>(args[0]));
}
return Undefined();
}
static TObject Net_UrlPathEncode(GCList &ls, std::vector<TObject> args) {
if (args.size() == 1 && std::holds_alternative<std::string>(args[0])) {
return HttpUtils::UrlPathEncode(std::get<std::string>(args[0]));
}
return Undefined();
}
static TObject New_NetworkStream(GCList &ls, std::vector<TObject> args) {
bool ipv6;
bool datagram;
if (GetArgument(args, 0, ipv6) && GetArgument(args, 1, datagram)) {
return std::make_shared<NetworkStream>(ipv6, datagram);
}
return nullptr;
}
class HttpServerNativeObject : public TNativeObject {
HttpServer *server;
public:
HttpServerNativeObject(uint16_t port,
std::shared_ptr<IHttpServer> httpServer,
bool printIps) {
server = new HttpServer(port, httpServer, printIps);
}
HttpServerNativeObject(std::string unixPath,
std::shared_ptr<IHttpServer> httpServer) {
server = new HttpServer(unixPath, httpServer);
}
std::string TypeName() { return "Net.Http.HttpServer"; }
TObject CallMethod(GCList &ls, std::string key, std::vector<TObject> args) {
if (key == "getPort") {
return (int64_t)server->GetPort();
}
if (key == "StartAccepting")
server->StartAccepting();
return nullptr;
}
~HttpServerNativeObject() { delete server; }
};
static TObject New_HttpServer(GCList &ls, std::vector<TObject> args,
TRootEnvironment *env) {
int64_t port;
std::string pathStr;
if (GetArgument(args, 1, port)) {
bool printIPs = true;
GetArgument(args, 2, printIPs);
std::shared_ptr<IHttpServer> httpSvr =
ToHttpServer(ls.GetGC(), args[0]);
if (httpSvr) {
uint16_t p = (uint16_t)port;
return TNativeObject::Create<HttpServerNativeObject>(
ls, port, httpSvr, printIPs);
}
}
if (GetArgument(args, 1, pathStr) && env->permissions.localfs) {
std::shared_ptr<IHttpServer> httpSvr =
ToHttpServer(ls.GetGC(), args[0]);
if (httpSvr) {
return TNativeObject::Create<HttpServerNativeObject>(ls, pathStr,
httpSvr);
}
}
return nullptr;
}
static TObject Net_Http_ListenSimpleWithLoop(GCList &ls,
std::vector<TObject> args) {
int64_t port;
if (GetArgument(args, 1, port)) {
std::shared_ptr<IHttpServer> httpSvr =
ToHttpServer(ls.GetGC(), args[0]);
if (httpSvr) {
uint16_t p = (uint16_t)port;
HttpServer server(p, httpSvr);
server.StartAccepting();
Tesses::Framework::TF_RunEventLoop();
}
}
return nullptr;
}
static TObject Net_Http_ListenOnUnusedPort(GCList &ls,
std::vector<TObject> args) {
if (args.empty())
return nullptr;
std::shared_ptr<IHttpServer> httpSvr =
ToHttpServer(ls.GetGC(), args.front());
if (httpSvr) {
uint16_t p = 0;
HttpServer server(p, httpSvr);
std::cout << "Port: " << server.GetPort() << std::endl;
server.StartAccepting();
Tesses::Framework::TF_RunEventLoop();
}
return nullptr;
}
static TObject Net_Http_MimeType(GCList &ls, std::vector<TObject> args) {
Tesses::Framework::Filesystem::VFSPath p;
if (GetArgumentAsPath(args, 0, p)) {
return HttpUtils::GetMimeTypePath(p);
}
return std::string("application/octet-stream");
}
class THttpRequestBody : public TNativeObject {
std::shared_ptr<HttpRequestBody> body;
public:
THttpRequestBody(std::shared_ptr<HttpRequestBody> body) {
this->body = body;
}
bool IsClosed() { return body == nullptr; }
std::shared_ptr<HttpRequestBody> GetBody() { return this->body; }
std::string TypeName() { return "Net.Http.HttpRequestBody"; }
TObject CallMethod(GCList &ls, std::string key, std::vector<TObject> args) {
return Undefined();
}
void Close() { this->body = nullptr; }
};
class THttpResponse : public TNativeObjectThatReturnsHttpDictionary {
HttpResponse *response;
public:
THttpResponse(HttpResponse *resp) { this->response = resp; }
bool IsAvailable() { return this->response != nullptr; }
void Close() {
delete this->response;
this->response = nullptr;
}
~THttpResponse() {
delete this->response;
this->response = nullptr;
}
std::string TypeName() { return "Net.Http.HttpResponse"; }
TObject CallMethod(GCList &ls, std::string key, std::vector<TObject> args) {
if (!this->IsAvailable())
return Undefined();
else if (key == "CopyToStream") {
std::shared_ptr<Stream> strm;
if (GetArgument(args, 0, strm)) {
response->CopyToStream(strm);
}
} else if (key == "ReadAsString") {
return response->ReadAsString();
} else if (key == "ReadAsJson") {
return Json_Decode(ls, response->ReadAsString());
} else if (key == "ReadAsStream") {
return response->ReadAsStream();
} else if (key == "getStatusCode") {
return (int64_t)response->statusCode;
} else if (key == "getVersion") {
return response->version;
} else if (key == "getResponseHeaders") {
return TNativeObject::Create<THttpDictionary>(
ls, &response->responseHeaders, this);
}
return Undefined();
}
};
static TObject Net_Http_MakeRequest(GCList &ls, std::vector<TObject> args,
TRootEnvironment *env) {
auto gc = ls.GetGC();
std::string url;
if (GetArgument(args, 0, url)) {
TDictionary *body1 = nullptr;
THttpRequestBody *body2 = nullptr;
HttpRequest req;
req.method = "GET";
req.ignoreSSLErrors = false;
req.followRedirects = false;
req.trusted_root_cert_bundle = "";
req.url = url;
req.body = nullptr;
TDictionary *options;
if (GetArgumentHeap(args, 1, options)) {
gc->BarrierBegin();
auto _obj = options->GetValue("Method");
GetObject(_obj, req.method);
_obj = options->GetValue("IgnoreSSLErrors");
GetObject(_obj, req.ignoreSSLErrors);
_obj = options->GetValue("FollowRedirects");
GetObject(_obj, req.followRedirects);
_obj = options->GetValue("TrustedRootCertBundle");
GetObject(_obj, req.trusted_root_cert_bundle);
if (env->permissions.localfs) {
_obj = options->GetValue("UnixSocket");
GetObject(_obj, req.unixSocket);
}
_obj = options->GetValue("RequestHeaders");
TList *headers;
if (GetObjectHeap(_obj, headers)) {
for (int64_t index = 0; index < headers->Count(); index++) {
_obj = headers->Get(index);
TDictionary *dict;
if (GetObjectHeap(_obj, dict)) {
std::string key = {};
std::string value = {};
_obj = dict->GetValue("Key");
GetObject(_obj, key);
_obj = dict->GetValue("Value");
GetObject(_obj, value);
req.requestHeaders.AddValue(key, value);
}
}
}
_obj = options->GetValue("Body");
if (GetObjectHeap(_obj, body1)) {
req.body =
std::make_shared<TDictionaryHttpRequestBody>(gc, body1);
} else if (GetObjectHeap(_obj, body2) && !body2->IsClosed()) {
req.body = body2->GetBody();
}
gc->BarrierEnd();
}
HttpResponse *resp = new HttpResponse(req);
if (req.body != nullptr) {
if (body2 != nullptr) {
body2->Close();
}
}
return TNativeObject::Create<THttpResponse>(ls, resp);
}
return nullptr;
}
static TObject Net_Smtp_Send(GCList &ls, std::vector<TObject> args) {
TDictionary *dict;
if (GetArgumentHeap(args, 0, dict)) {
// the body should be either type text/plain or text/html
// the body and attachment data can also point to bytearray of stream
// server can also be a stream
// as of right now the email is fire and forget (ie no error checking)
// check function return type just in case (this function returns a
// empty string if no error) we rolled our own smtp client
/*
dict looks like this from crosslang's point of view
{
server = {
host = "smtp.example.com",
tls = true
},
auth = {
username = "from",
password = "THEPASSWORD"
},
domain = "example.com",
from = {
name = "The name shown in the mail where it is from",
email = "from@example.com"
},
to = "to@example.com",
subject = "My little message",
body = {
type = "text/html",
data = "<h1>Hello, world</h1>"
},
attachments = [
{
name = "myimg.png",
type = "image/png",
data = embed("myimg.png")
}
]
}
*/
ls.GetGC()->BarrierBegin();
auto server = dict->GetValue("server");
TDictionary *dict2;
std::shared_ptr<Tesses::Framework::Streams::Stream> strm;
bool ownsStream = true;
std::shared_ptr<Stream> objStrm;
if (GetObjectHeap(server, dict2)) {
auto tlsO = dict2->GetValue("tls");
auto hostO = dict2->GetValue("host");
auto portO = dict2->GetValue("port");
std::string host;
bool tls = false;
int64_t port;
GetObject(tlsO, tls);
if (!GetObject(portO, port))
port = tls ? 465 : 25;
GetObject(hostO, host);
strm = std::make_shared<NetworkStream>(host, (uint16_t)port, false,
false, false);
if (tls) {
strm = std::make_shared<Framework::Crypto::ClientTLSStream>(
strm, true, host);
}
} else if (GetObject(server, objStrm)) {
ownsStream = false;
strm = objStrm;
}
Tesses::Framework::Mail::SMTPClient client(strm);
auto o = dict->GetValue("domain");
GetObject(o, client.domain);
o = dict->GetValue("to");
GetObject(o, client.to);
o = dict->GetValue("subject");
GetObject(o, client.subject);
o = dict->GetValue("auth");
if (GetObjectHeap(o, dict2)) {
o = dict2->GetValue("username");
GetObject(o, client.username);
o = dict2->GetValue("password");
GetObject(o, client.password);
}
o = dict->GetValue("from");
if (GetObjectHeap(o, dict2)) {
o = dict2->GetValue("email");
GetObject(o, client.from);
o = dict2->GetValue("name");
GetObject(o, client.from_name);
}
o = dict->GetValue("body");
if (GetObjectHeap(o, dict2)) {
// type, data
std::string type = "text/plain";
o = dict2->GetValue("type");
GetObject(o, type);
o = dict2->GetValue("data");
client.body = TObjectToSMTPBody(ls, type, o);
}
o = dict->GetValue("attachments");
TList *als;
if (GetObjectHeap(o, als)) {
for (int64_t i = 0; i < als->Count(); i++) {
auto item = als->Get(i);
if (GetObjectHeap(item, dict2)) {
o = dict2->GetValue("name");
std::string name;
GetObject(o, name);
std::string type = "text/plain";
o = dict2->GetValue("type");
GetObject(o, type);
o = dict2->GetValue("data");
client.attachments.push_back(
std::pair<std::string, std::shared_ptr<SMTPBody>>(
name, TObjectToSMTPBody(ls, type, o)));
}
}
}
ls.GetGC()->BarrierEnd();
client.Send();
return "";
}
return nullptr;
}
static TObject Net_Http_WebSocketClient(GCList &ls, std::vector<TObject> args) {
std::string url;
TList *headers;
TDictionary *dict;
TClassObject *co;
TCallable *callable = nullptr;
TObject _obj;
if (GetArgument(args, 0, url) && GetArgumentHeap(args, 1, headers) &&
GetArgumentHeap(args, 2, dict)) {
GetArgumentHeap(args, 3, callable);
HttpDictionary hdict(false);
for (int64_t index = 0; index < headers->Count(); index++) {
_obj = headers->Get(index);
TDictionary *dict;
if (GetObjectHeap(_obj, dict)) {
std::string key = {};
std::string value = {};
_obj = dict->GetValue("Key");
GetObject(_obj, key);
_obj = dict->GetValue("Value");
GetObject(_obj, value);
hdict.AddValue(key, value);
}
}
auto conn = std::make_shared<CallbackWebSocketConnection>(
[dict, &ls](std::function<void(WebSocketMessage &)> sendMessage,
std::function<void()> ping,
std::function<void()> close) -> void {
GCList ls2(ls.GetGC());
dict->CallMethod(
ls2, "Open",
{TExternalMethod::Create(
ls2, "Send a message", {"messageTextOrByteArray"},
[sendMessage](GCList &ls,
std::vector<TObject> args) -> TObject {
std::string str;
TByteArray *bArray;
if (GetArgument(args, 0, str)) {
WebSocketMessage msg(str);
sendMessage(msg);
} else if (GetArgumentHeap(args, 0, bArray)) {
WebSocketMessage msg(bArray->data);
sendMessage(msg);
}
return nullptr;
}),
TExternalMethod::Create(
ls2, "Ping client", {},
[ping](GCList &ls,
std::vector<TObject> args) -> TObject {
ping();
return nullptr;
}),
TExternalMethod::Create(
ls2, "Close client", {},
[close](GCList &ls,
std::vector<TObject> args) -> TObject {
close();
return nullptr;
})});
},
[dict, &ls](WebSocketMessage &msg) -> void {
GCList ls2(ls.GetGC());
TObject v;
if (msg.isBinary) {
auto r = TByteArray::Create(ls2);
r->data = msg.data;
v = r;
} else {
v = msg.ToString();
}
dict->CallMethod(ls2, "Receive", {v});
},
[dict, &ls](bool close) -> void {
GCList ls2(ls.GetGC());
dict->CallMethod(ls2, "Close", {close});
});
WebSocketClient(
url, hdict, conn,
[&ls, callable](Tesses::Framework::Http::HttpDictionary &dict,
bool success) -> bool {
if (callable != nullptr) {
auto dummy = TNativeObject::Create<
DummyTNativeObjectThatReturnsHttpDictionary>(ls);
bool res = ToBool(callable->Call(
ls, {TNativeObject::Create<THttpDictionary>(ls, &dict,
dummy),
success}));
dummy->Close();
return res;
}
return true;
});
} else if (GetArgument(args, 0, url) && GetArgumentHeap(args, 1, co)) {
TObject hobj;
if (co->HasMethod("", "GetRequestHeaders"))
hobj = co->CallMethod(ls, "", "GetRequestHeaders", {});
else if (co->HasField("", "RequestHeaders"))
hobj = co->GetValue("", "RequestHeaders");
else
return Undefined();
if (!GetObjectHeap(hobj, headers))
return Undefined();
HttpDictionary hdict(false);
for (int64_t index = 0; index < headers->Count(); index++) {
_obj = headers->Get(index);
TDictionary *dict;
if (GetObjectHeap(_obj, dict)) {
std::string key = {};
std::string value = {};
_obj = dict->GetValue("Key");
GetObject(_obj, key);
_obj = dict->GetValue("Value");
GetObject(_obj, value);
hdict.AddValue(key, value);
}
}
auto conn = std::make_shared<CallbackWebSocketConnection>(
[co, &ls](std::function<void(WebSocketMessage &)> sendMessage,
std::function<void()> ping,
std::function<void()> close) -> void {
GCList ls2(ls.GetGC());
co->CallMethod(
ls2, "", "Open",
{TExternalMethod::Create(
ls2, "Send a message", {"messageTextOrByteArray"},
[sendMessage](GCList &ls,
std::vector<TObject> args) -> TObject {
std::string str;
TByteArray *bArray;
if (GetArgument(args, 0, str)) {
WebSocketMessage msg(str);
sendMessage(msg);
} else if (GetArgumentHeap(args, 0, bArray)) {
WebSocketMessage msg(bArray->data);
sendMessage(msg);
}
return nullptr;
}),
TExternalMethod::Create(
ls2, "Ping client", {},
[ping](GCList &ls,
std::vector<TObject> args) -> TObject {
ping();
return nullptr;
}),
TExternalMethod::Create(
ls2, "Close client", {},
[close](GCList &ls,
std::vector<TObject> args) -> TObject {
close();
return nullptr;
})});
},
[co, &ls](WebSocketMessage &msg) -> void {
GCList ls2(ls.GetGC());
TObject v;
if (msg.isBinary) {
auto r = TByteArray::Create(ls2);
r->data = msg.data;
v = r;
} else {
v = msg.ToString();
}
co->CallMethod(ls2, "", "Receive", {v});
},
[co, &ls](bool close) -> void {
GCList ls2(ls.GetGC());
co->CallMethod(ls2, "", "Close", {close});
});
WebSocketClient(
url, hdict, conn,
[&ls, co](Tesses::Framework::Http::HttpDictionary &dict,
bool success) -> bool {
if (co->HasMethod("", "HandleResponseHeaders")) {
auto dummy = TNativeObject::Create<
DummyTNativeObjectThatReturnsHttpDictionary>(ls);
bool res = ToBool(
co->CallMethod(ls, "", "HandleResponseHeaders",
{TNativeObject::Create<THttpDictionary>(
ls, &dict, dummy),
success}));
dummy->Close();
return res;
}
return true;
});
}
return Undefined();
// Net.Http.CreateWebSocketConnection("wss://example.com/",[],conn, (dict,
// success)=>{ return true;})
}
static TObject Net_Http_DownloadToString(GCList &ls,
std::vector<TObject> args) {
std::string url;
if (GetArgument(args, 0, url))
return DownloadToStringSimple(url);
return nullptr;
}
static TObject Net_Http_DownloadToStream(GCList &ls,
std::vector<TObject> args) {
std::string url;
std::shared_ptr<Stream> strm;
if (GetArgument(args, 0, url) && GetArgument(args, 1, strm)) {
DownloadToStreamSimple(url, strm);
}
return nullptr;
}
static TObject Net_Http_DownloadToFile(GCList &ls, std::vector<TObject> args) {
std::string url;
std::shared_ptr<Tesses::Framework::Filesystem::VFS> vfs;
Tesses::Framework::Filesystem::VFSPath path;
if (GetArgument(args, 0, url) && GetArgument(args, 1, vfs) &&
GetArgumentAsPath(args, 2, path)) {
DownloadToFileSimple(url, vfs, path);
}
return nullptr;
}
bool IHttpServer_Handle(std::shared_ptr<IHttpServer> svr,
std::vector<TObject> &args) {
TServerContext *ctx;
if (GetArgumentHeap(args, 0, ctx)) {
return svr->Handle(*ctx->GetContext());
}
return false;
}
std::shared_ptr<IHttpServer> ToHttpServer(std::shared_ptr<GC> gc, TObject obj) {
if (std::holds_alternative<std::shared_ptr<IHttpServer>>(obj))
return std::get<std::shared_ptr<IHttpServer>>(obj);
TDictionary *dict;
TClassObject *clo;
TCallable *call;
if (GetObjectHeap(obj, dict)) {
return std::make_shared<TObjectHttpServer>(gc, dict);
} else if (GetObjectHeap(obj, clo)) {
return std::make_shared<TObjectHttpServer>(gc, clo);
} else if (GetObjectHeap(obj, call)) {
return std::make_shared<TObjectHttpServer>(gc, call);
}
return nullptr;
}
static TObject Net_Http_HtmlP(GCList &ls, std::vector<TObject> args) {
std::string str;
if (GetArgument(args, 0, str)) {
return HttpUtils::HtmlP(str);
}
return "";
}
static TObject Net_Http_StatusCodeString(GCList &ls,
std::vector<TObject> args) {
int64_t sc;
if (GetArgument(args, 0, sc)) {
return HttpUtils::StatusCodeString((StatusCode)sc);
}
return "";
}
static TObject New_FileServer(GCList &ls, std::vector<TObject> args) {
std::shared_ptr<Tesses::Framework::Filesystem::VFS> vfs;
bool allowlisting;
bool spa;
if (GetArgument(args, 0, vfs) && GetArgument(args, 1, allowlisting) &&
GetArgument(args, 2, spa)) {
return std::make_shared<FileServer>(vfs, allowlisting, spa);
}
return nullptr;
}
static TObject New_BasicAuthServer(GCList &ls, std::vector<TObject> args) {
auto bAuth = std::make_shared<BasicAuthServer>();
TCallable *cb;
if (!args.empty())
bAuth->server = ToHttpServer(ls.GetGC(), args[0]);
if (GetArgumentHeap(args, 1, cb)) {
auto marked = CreateMarkedTObject(ls, cb);
bAuth->authorization = [marked](std::string user,
std::string password) -> bool {
GCList ls(marked->GetGC());
TCallable *callable;
if (GetObjectHeap(marked->GetObject(), callable)) {
return ToBool(callable->Call(ls, {user, password}));
}
return false;
};
}
GetArgument(args, 2, bAuth->realm);
return bAuth;
}
static TObject New_MountableServer(GCList &ls, std::vector<TObject> args) {
if (args.empty())
return std::make_shared<MountableServer>();
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) {
std::shared_ptr<Stream> strm;
std::string mimeType;
if (GetArgument(args, 0, strm) && GetArgument(args, 1, mimeType)) {
return TNativeObject::Create<THttpRequestBody>(
ls, std::make_shared<StreamHttpRequestBody>(strm, mimeType));
}
return nullptr;
}
static TObject New_TextHttpRequestBody(GCList &ls, std::vector<TObject> args) {
std::string text;
std::string mimeType;
if (GetArgument(args, 0, text) && GetArgument(args, 1, mimeType)) {
return TNativeObject::Create<THttpRequestBody>(
ls, std::make_shared<TextHttpRequestBody>(text, mimeType));
}
return nullptr;
}
static TObject New_JsonHttpRequestBody(GCList &ls, std::vector<TObject> args) {
if (!args.empty()) {
return TNativeObject::Create<THttpRequestBody>(
ls, std::make_shared<TextHttpRequestBody>(Json_Encode(args[0]),
"application/json"));
}
return nullptr;
}
static TObject New_ServerSentEvents(GCList &ls, std::vector<TObject> args) {
return std::make_shared<Tesses::Framework::Http::ServerSentEvents>();
}
void TStd::RegisterNet(std::shared_ptr<GC> gc, TRootEnvironment *env) {
env->permissions.canRegisterNet = true;
GCList ls(gc);
gc->BarrierBegin();
TDictionary *dict = env->EnsureDictionary(gc, "Net");
TDictionary *_new = env->EnsureDictionary(gc, "New");
_new->DeclareFunction(gc, "StreamHttpRequestBody",
"Create a stream request body",
{"stream", "mimeType"}, New_StreamHttpRequestBody);
_new->DeclareFunction(gc, "TextHttpRequestBody",
"Create a text request body", {"text", "mimeType"},
New_TextHttpRequestBody);
_new->DeclareFunction(gc, "JsonHttpRequestBody",
"Create a json request body", {"json"},
New_JsonHttpRequestBody);
_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);
});
_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);
_new->DeclareFunction(gc, "NetworkStream", "Create a network stream",
{"ipv6", "datagram"}, New_NetworkStream);
_new->DeclareFunction(gc, "ServerSentEvents",
"Create server sent events object", {""},
New_ServerSentEvents);
TDictionary *http = TDictionary::Create(ls);
TDictionary *smtp = TDictionary::Create(ls);
http->DeclareFunction(gc, "StatusCodeString", "Get the status code string",
{"statusCode"}, Net_Http_StatusCodeString);
http->DeclareFunction(gc, "HtmlP", "Linkify text", {"text"},
Net_Http_HtmlP);
http->DeclareFunction(gc, "HtmlEncode", "Html encode", {"param"},
Net_HtmlEncode);
http->DeclareFunction(gc, "UrlEncode", "Url encode query param", {"param"},
Net_UrlEncode);
http->DeclareFunction(gc, "UrlDecode", "Url decode query param", {"param"},
Net_UrlDecode);
http->DeclareFunction(gc, "UrlPathEncode", "Url encode path", {"path"},
Net_UrlPathEncode);
http->DeclareFunction(gc, "UrlPathDecode", "Url decode path", {"path"},
Net_UrlPathDecode);
http->DeclareFunction(gc, "MimeType", "Get mimetype from extension",
{"ext"}, Net_Http_MimeType);
http->DeclareFunction(gc, "StreamHttpRequestBody",
"Create a stream request body",
{"stream", "mimeType"}, New_StreamHttpRequestBody);
http->DeclareFunction(gc, "TextHttpRequestBody",
"Create a text request body", {"text", "mimeType"},
New_TextHttpRequestBody);
http->DeclareFunction(gc, "JsonHttpRequestBody",
"Create a text request body", {"json"},
New_JsonHttpRequestBody);
http->DeclareFunction(
gc, "MakeRequest", "Create an http request", {"url", "$extra"},
[env](GCList &ls, std::vector<TObject> args) -> TObject {
return Net_Http_MakeRequest(ls, args, env);
});
http->DeclareFunction(
gc, "WebSocketClient", "Create a websocket connection",
{"url", "headers", "conn", "$successCB"}, Net_Http_WebSocketClient);
http->DeclareFunction(gc, "DownloadToString",
"Return the http file's contents as a string",
{"url"}, Net_Http_DownloadToString);
http->DeclareFunction(gc, "DownloadToStream", "Download file to stream",
{"url", "stream"}, Net_Http_DownloadToStream);
http->DeclareFunction(gc, "DownloadToFile", "Download file to file in vfs",
{"url", "vfs", "path"}, Net_Http_DownloadToFile);
http->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);
});
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<TObject> args) -> TObject {
TServerContext *sc;
if (GetArgumentHeap(args, 0, sc)) {
std::string user;
std::string pass;
if (sc->IsAvailable() &&
BasicAuthServer::GetCreds(*sc->GetContext(), user, pass)) {
return TDictionary::Create(ls, {TDItem("Username", user),
TDItem("Password", pass)});
}
}
return nullptr;
});
http->DeclareFunction(
gc, "MountableServer",
"Create a server you can mount to, must mount parents before child",
{"root"}, New_MountableServer);
dict->DeclareFunction(gc, "NetworkStream", "Create a network stream",
{"ipv6", "datagram"}, New_NetworkStream);
smtp->DeclareFunction(gc, "Send", "Send email via smtp server",
{"messageStruct"}, Net_Smtp_Send);
dict->DeclareFunction(
gc, "getIPAddresses", "Get the ip addresses of this machine", {"$ipv6"},
[](GCList &ls, std::vector<TObject> args) -> TObject {
TList *a = TList::Create(ls);
bool ipv6 = false;
GetArgument(args, 0, ipv6);
ls.GetGC()->BarrierBegin();
for (auto item :
Tesses::Framework::Streams::NetworkStream::GetIPs(ipv6)) {
a->Add(
TDictionary::Create(ls, {TDItem("Interface", item.first),
TDItem("Address", item.second)}));
}
ls.GetGC()->BarrierEnd();
;
return a;
});
dict->SetValue("Http", http);
dict->SetValue("Smtp", smtp);
gc->BarrierEnd();
}
Tesses::Framework::Http::ServerRequestHandler
TCallable::ToRouteServerRequestHandler(std::shared_ptr<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;
};
}
} // namespace Tesses::CrossLang