Add server sent events, change vfs structure, dark mode error pages and dark mode anonydrop
This commit is contained in:
@@ -6,6 +6,7 @@ on:
|
||||
|
||||
env:
|
||||
PACKAGE_AND_BREW: ${{ secrets.PACKAGE_AND_BREW }}
|
||||
VERSION: ${{ gitea.ref_name }}
|
||||
|
||||
jobs:
|
||||
build-arch:
|
||||
@@ -20,3 +21,22 @@ jobs:
|
||||
- run: chown build:build /home/build/PKGBUILD
|
||||
- run: chown build:build /home/build/build-arch.sh
|
||||
- run: su build -c /home/build/build-arch.sh
|
||||
|
||||
update-tap:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: "master"
|
||||
path: "tapdir"
|
||||
repository: "tesses50/tesses-tap.git"
|
||||
token: ${{ env.PACKAGE_AND_BREW }}
|
||||
- run: |
|
||||
cd tapdir
|
||||
bash ../Packaging/edit-formula.sh
|
||||
git config user.name "Tesses Gitea Bot"
|
||||
git config user.email "noreply@tesses.net"
|
||||
git add .
|
||||
git commit -m "Push tesses-framework=${{ env.VERSION }}"
|
||||
git push
|
||||
|
||||
19
Packaging/edit-formula.sh
Normal file
19
Packaging/edit-formula.sh
Normal file
@@ -0,0 +1,19 @@
|
||||
export HASH=`curl https://git.tesses.org/tesses50/tessesframework/archive/$VERSION.tar.gz 2> /dev/null | shasum -a 256 | awk '{print $1}'`
|
||||
|
||||
echo "class Tessesframework < Formula" > "Formula/tessesframework.rb"
|
||||
echo " desc \"\"" >> "Formula/tessesframework.rb"
|
||||
echo " homepage \"\"" >> "Formula/tessesframework.rb"
|
||||
echo " url \"https://git.tesses.org/tesses50/tessesframework/archive/$VERSION.tar.gz\"" >> "Formula/tessesframework.rb"
|
||||
echo " sha256 \"$HASH\"" >> "Formula/tessesframework.rb"
|
||||
echo " license \"MIT\"" >> "Formula/tessesframework.rb"
|
||||
echo " depends_on \"cmake\" => :build" >> "Formula/tessesframework.rb"
|
||||
echo " depends_on \"mbedtls@3\"" >> "Formula/tessesframework.rb"
|
||||
echo " def install" >> "Formula/tessesframework.rb"
|
||||
echo " system \"cmake\", \"-S\", \".\", \"-B\", \"build\", \"-DTESSESFRAMEWORK_FETCHCONTENT=OFF\", *std_cmake_args" >> "Formula/tessesframework.rb"
|
||||
echo " system \"cmake\", \"--build\", \"build\"" >> "Formula/tessesframework.rb"
|
||||
echo " system \"cmake\", \"--install\", \"build\"" >> "Formula/tessesframework.rb"
|
||||
echo " end" >> "Formula/tessesframework.rb"
|
||||
echo " test do" >> "Formula/tessesframework.rb"
|
||||
echo " system \"true\"" >> "Formula/tessesframework.rb"
|
||||
echo " end" >> "Formula/tessesframework.rb"
|
||||
echo "end" >> "Formula/tessesframework.rb"
|
||||
@@ -1,5 +1,8 @@
|
||||
# Changelog
|
||||
|
||||
## 0.0.3
|
||||
Add server sent events, change vfs structure, dark mode error pages and dark mode anonydrop
|
||||
|
||||
## 0.0.2
|
||||
Add UUIDs
|
||||
|
||||
|
||||
@@ -8,6 +8,9 @@ using namespace Tesses::Framework::Http;
|
||||
using namespace Tesses::Framework::Streams;
|
||||
using namespace Tesses::Framework::TextStreams;
|
||||
using namespace Tesses::Framework::Threading;
|
||||
|
||||
std::shared_ptr<ServerSentEvents> sse = std::make_shared<ServerSentEvents>();
|
||||
|
||||
class Johnny : public ServerContextData
|
||||
{
|
||||
public:
|
||||
@@ -65,7 +68,7 @@ class MyWebServer : public IHttpServer {
|
||||
for(size_t i=0;i<10000; i++)
|
||||
{
|
||||
writer.WriteLine("<li>" + std::to_string(i) + "</li>");
|
||||
|
||||
TF_Sleep(10);
|
||||
}
|
||||
|
||||
writer.WriteLine("</ul>");
|
||||
@@ -74,6 +77,15 @@ class MyWebServer : public IHttpServer {
|
||||
writer.WriteLine("</html>");
|
||||
return true;
|
||||
}
|
||||
else if(ctx.path == "/ssetest.html")
|
||||
{
|
||||
|
||||
}
|
||||
else if(ctx.path == "/sse")
|
||||
{
|
||||
ctx.SendServerSentEvents(sse);
|
||||
return true;
|
||||
}
|
||||
else if(ctx.path == "/main.js")
|
||||
{
|
||||
|
||||
@@ -162,6 +174,13 @@ class MyOtherWebServer : public IHttpServer
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
TF_InitWithConsole();
|
||||
int64_t timer = 0;
|
||||
auto timerHDL= TF_Timer([&timer]()->void{
|
||||
timer++;
|
||||
|
||||
sse->SendData("Timer has ticked " + std::to_string(timer) + " times now");
|
||||
});
|
||||
|
||||
std::shared_ptr<RouteServer> routeSvr = std::make_shared<RouteServer>();
|
||||
routeSvr->Get("/name/{name}/greeting",[](ServerContext& ctx)->bool{
|
||||
std::string name;
|
||||
|
||||
@@ -76,6 +76,7 @@ namespace Tesses::Framework
|
||||
void TF_RunEventLoop();
|
||||
void TF_RunEventLoopItteration();
|
||||
bool TF_IsRunning();
|
||||
void TF_Sleep(uint32_t sleepMS);
|
||||
void TF_SetIsRunning(bool _isRunning);
|
||||
void TF_Quit();
|
||||
bool TF_GetConsoleEventsEnabled();
|
||||
|
||||
@@ -13,12 +13,30 @@ namespace Tesses::Framework::Http
|
||||
public:
|
||||
virtual ~ServerContextData();
|
||||
};
|
||||
|
||||
class ServerContext;
|
||||
class ServerSentEvents {
|
||||
std::vector<std::shared_ptr<Tesses::Framework::Streams::Stream>> strms;
|
||||
Tesses::Framework::Threading::Mutex mtx;
|
||||
private:
|
||||
void SendEventRaw(const std::string& evt);
|
||||
public:
|
||||
void SendRetry(uint32_t ms);
|
||||
void SendRetry(std::chrono::milliseconds ms);
|
||||
void SendRetry(Tesses::Framework::Date::TimeSpan ts);
|
||||
void SendData(const std::string& message);
|
||||
void SendData(const std::string& message, const std::string& dataType);
|
||||
void SendId(const std::string& idVal);
|
||||
void SendCustomEvent(const std::string& type, const std::string& value);
|
||||
void SendComment(const std::string& comment);
|
||||
friend class ServerContext;
|
||||
};
|
||||
|
||||
|
||||
class ServerContext {
|
||||
|
||||
bool sent;
|
||||
bool debug;
|
||||
std::vector<std::shared_ptr<ServerSentEvents>> sse;
|
||||
std::shared_ptr<Tesses::Framework::Streams::Stream> strm;
|
||||
std::map<std::string,ServerContextData*> data;
|
||||
std::queue<std::function<bool(ServerContext& ctx)>> headerhandlers;
|
||||
@@ -54,6 +72,7 @@ namespace Tesses::Framework::Http
|
||||
void SendNotFound();
|
||||
void SendBadRequest();
|
||||
void SendException(std::exception& ex);
|
||||
void SendServerSentEvents(std::shared_ptr<ServerSentEvents> sse);
|
||||
std::shared_ptr<Tesses::Framework::Streams::Stream> OpenResponseStream();
|
||||
std::shared_ptr<Tesses::Framework::Streams::Stream> OpenRequestStream();
|
||||
ServerContext& WithStatusCode(StatusCode code);
|
||||
@@ -87,6 +106,9 @@ namespace Tesses::Framework::Http
|
||||
data[name] = item;
|
||||
return item;
|
||||
}
|
||||
friend class ServerSentEvents;
|
||||
|
||||
|
||||
};
|
||||
|
||||
class IHttpServer {
|
||||
|
||||
@@ -46,12 +46,17 @@ namespace Tesses::Framework::Streams
|
||||
void Listen(int32_t backlog);
|
||||
void Bind(std::string ip, uint16_t port);
|
||||
void SetBroadcast(bool bC);
|
||||
void SetReuseAddress(bool reuse);
|
||||
void SetReusePort(bool reuse);
|
||||
void SetMulticastTTL(uint8_t ttl);
|
||||
void SetMulticastMembership(std::string multicastAddress, std::string ifaceIP="0.0.0.0");
|
||||
std::shared_ptr<NetworkStream> Accept(std::string& ip, uint16_t& port);
|
||||
size_t Read(uint8_t* buff, size_t sz);
|
||||
size_t Write(const uint8_t* buff, size_t sz);
|
||||
size_t ReadFrom(uint8_t* buff, size_t sz, std::string& ip, uint16_t& port);
|
||||
size_t WriteTo(const uint8_t* buff, size_t sz, std::string ip, uint16_t port);
|
||||
static std::vector<std::pair<std::string,std::string>> GetIPs(bool ipV6=false);
|
||||
|
||||
~NetworkStream();
|
||||
void SetNoDelay(bool noDelay);
|
||||
void Close();
|
||||
|
||||
@@ -27,6 +27,79 @@ using namespace Tesses::Framework::TextStreams;
|
||||
|
||||
namespace Tesses::Framework::Http
|
||||
{
|
||||
|
||||
void ServerSentEvents::SendEventRaw(const std::string& evt)
|
||||
{
|
||||
this->mtx.Lock();
|
||||
for(auto& item : this->strms)
|
||||
{
|
||||
try {
|
||||
StreamWriter writer(item);
|
||||
writer.newline = "\r\n";
|
||||
writer.WriteLine(evt);
|
||||
|
||||
|
||||
}catch(...) {
|
||||
|
||||
}
|
||||
}
|
||||
this->mtx.Unlock();
|
||||
}
|
||||
|
||||
void ServerSentEvents::SendId(const std::string& id)
|
||||
{
|
||||
SendCustomEvent("id",id);
|
||||
}
|
||||
|
||||
void ServerSentEvents::SendData(const std::string& message)
|
||||
{
|
||||
SendCustomEvent("data", message);
|
||||
}
|
||||
void ServerSentEvents::SendComment(const std::string& comment)
|
||||
{
|
||||
SendCustomEvent("", comment);
|
||||
}
|
||||
void ServerSentEvents::SendCustomEvent(const std::string& etype, const std::string& message)
|
||||
{
|
||||
std::string text = etype + ": ";
|
||||
for(auto item : message)
|
||||
{
|
||||
if(item == '\r') continue;
|
||||
if(item == '\n') {
|
||||
text += "\r\n" + etype + ": ";
|
||||
}
|
||||
else text += item;
|
||||
}
|
||||
|
||||
SendEventRaw(text);
|
||||
}
|
||||
void ServerSentEvents::SendData(const std::string& message, const std::string& mtype)
|
||||
{
|
||||
std::string text = "event: " + mtype + "\r\ndata: ";
|
||||
for(auto item : message)
|
||||
{
|
||||
if(item == '\r') continue;
|
||||
if(item == '\n') {
|
||||
text += "\r\ndata: ";
|
||||
}
|
||||
else text += item;
|
||||
}
|
||||
|
||||
SendEventRaw(text);
|
||||
}
|
||||
void ServerSentEvents::SendRetry(uint32_t ms)
|
||||
{
|
||||
SendCustomEvent("retry", std::to_string(ms));
|
||||
}
|
||||
void ServerSentEvents::SendRetry(std::chrono::milliseconds ms)
|
||||
{
|
||||
SendCustomEvent("retry", std::to_string(ms.count()));
|
||||
}
|
||||
void ServerSentEvents::SendRetry(Tesses::Framework::Date::TimeSpan ts)
|
||||
{
|
||||
SendRetry((uint32_t)ts.TotalSeconds() * 1000);
|
||||
}
|
||||
|
||||
class WSServer
|
||||
{
|
||||
public:
|
||||
@@ -282,6 +355,7 @@ namespace Tesses::Framework::Http
|
||||
this->conn->OnClose(false);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
static int _header_field(multipart_parser* p, const char *at, size_t length)
|
||||
{
|
||||
@@ -344,6 +418,7 @@ namespace Tesses::Framework::Http
|
||||
data->currentHeaders.Clear();
|
||||
return 0;
|
||||
}*/
|
||||
|
||||
std::string ServerContext::GetUrlWithQuery()
|
||||
{
|
||||
if(this->queryParams.kvp.empty()) return this->path;
|
||||
@@ -364,6 +439,34 @@ namespace Tesses::Framework::Http
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ServerContext::SendServerSentEvents(std::shared_ptr<ServerSentEvents> sse)
|
||||
{
|
||||
this->responseHeaders.SetValue("X-Accel-Buffering","no");
|
||||
this->responseHeaders.SetValue("Content-Type","text/event-stream");
|
||||
this->responseHeaders.SetValue("Cache-Control","no-cache");
|
||||
auto strm = this->OpenResponseStream();
|
||||
if(strm == nullptr || this->method == "HEAD") return;
|
||||
sse->mtx.Lock();
|
||||
sse->strms.push_back(strm);
|
||||
sse->mtx.Unlock();
|
||||
while(!this->strm->EndOfStream())
|
||||
{
|
||||
TF_Sleep(10);
|
||||
}
|
||||
sse->mtx.Lock();
|
||||
for(auto index = sse->strms.begin(); index != sse->strms.end(); index++)
|
||||
{
|
||||
if(*index == strm)
|
||||
{
|
||||
sse->strms.erase(index);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
sse->mtx.Unlock();
|
||||
}
|
||||
|
||||
std::string ServerContext::ReadString()
|
||||
{
|
||||
if(strm == nullptr) return {};
|
||||
|
||||
@@ -160,20 +160,30 @@ namespace Tesses::Framework::Http
|
||||
if(this->length == -1 && this->http1_1 && !done && !this->recv)
|
||||
{
|
||||
this->done=true;
|
||||
try {
|
||||
|
||||
StreamWriter writer(this->strm);
|
||||
writer.newline = "\r\n";
|
||||
writer.WriteLine("0");
|
||||
writer.WriteLine();
|
||||
}catch(...){
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
HttpStream::~HttpStream()
|
||||
{
|
||||
if(this->length == -1 && this->http1_1 && !done && !this->recv)
|
||||
{
|
||||
try {
|
||||
|
||||
StreamWriter writer(this->strm);
|
||||
writer.newline = "\r\n";
|
||||
writer.WriteLine("0");
|
||||
writer.WriteLine();
|
||||
}catch(...) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,10 @@
|
||||
#include "TessesFramework/Streams/NetworkStream.hpp"
|
||||
#include "TessesFramework/Http/HttpUtils.hpp"
|
||||
#include <TessesFramework/Streams/NetworkStream.hpp>
|
||||
#include <iostream>
|
||||
#include <cstring>
|
||||
using HttpUtils = Tesses::Framework::Http::HttpUtils;
|
||||
|
||||
#if defined(TESSESFRAMEWORK_ENABLE_NETWORKING)
|
||||
|
||||
|
||||
@@ -34,6 +36,8 @@ using HttpUtils = Tesses::Framework::Http::HttpUtils;
|
||||
#endif
|
||||
#undef min
|
||||
#pragma comment(lib, "ws2_32.lib")
|
||||
|
||||
|
||||
#else
|
||||
|
||||
extern "C" {
|
||||
@@ -47,6 +51,7 @@ extern "C" {
|
||||
#if defined(AF_UNIX) && !defined(GEKKO) && !defined(__SWITCH__) && !defined(__PS2__)
|
||||
#include <sys/un.h>
|
||||
#endif
|
||||
|
||||
#include <poll.h>
|
||||
}
|
||||
#endif
|
||||
@@ -720,10 +725,75 @@ namespace Tesses::Framework::Streams {
|
||||
return;
|
||||
}
|
||||
}
|
||||
void NetworkStream::SetReuseAddress(bool reuse)
|
||||
{
|
||||
if(!this->success) return;
|
||||
int no = reuse ? 1 : 0;
|
||||
if (NETWORK_SETSOCKOPT(sock, SOL_SOCKET, SO_REUSEADDR, (const char*)&no, sizeof(no)) != 0)
|
||||
{
|
||||
this->success=false;
|
||||
if(this->owns)
|
||||
NETWORK_CLOSE(this->sock);
|
||||
|
||||
}
|
||||
}
|
||||
void NetworkStream::SetReusePort(bool reuse)
|
||||
{
|
||||
if(!this->success) return;
|
||||
int no = reuse ? 1 : 0;
|
||||
if (NETWORK_SETSOCKOPT(sock, SOL_SOCKET, SO_REUSEPORT, (const char*)&no, sizeof(no)) != 0)
|
||||
{
|
||||
this->success=false;
|
||||
if(this->owns)
|
||||
NETWORK_CLOSE(this->sock);
|
||||
|
||||
}
|
||||
}
|
||||
void NetworkStream::SetMulticastTTL(uint8_t ttl)
|
||||
{
|
||||
if(!this->success) return;
|
||||
#if defined(IPPROTO_IP) && defined(IP_MULTICAST_TTL)
|
||||
if (NETWORK_SETSOCKOPT(sock, IPPROTO_IP, IP_MULTICAST_TTL, (const char*)&ttl, sizeof(ttl)) != 0)
|
||||
{
|
||||
this->success=false;
|
||||
if(this->owns)
|
||||
NETWORK_CLOSE(this->sock);
|
||||
|
||||
}
|
||||
#endif
|
||||
}
|
||||
void NetworkStream::SetMulticastMembership(std::string multicastAddress, std::string ifaceIP)
|
||||
{
|
||||
if(!this->success) return;
|
||||
#if defined(IPPROTO_IP) && defined(IP_MULTICAST_TTL)
|
||||
struct sockaddr_storage maddr;
|
||||
struct sockaddr_storage iaddr;
|
||||
|
||||
bool success = IPParse(multicastAddress, &maddr) && IPParse(ifaceIP, &iaddr);
|
||||
if(success && maddr.ss_family == AF_INET && iaddr.ss_family == AF_INET)
|
||||
{
|
||||
|
||||
struct ip_mreq req;
|
||||
req.imr_multiaddr = ((struct sockaddr_in*)&maddr)->sin_addr;
|
||||
req.imr_interface = ((struct sockaddr_in*)&iaddr)->sin_addr;
|
||||
|
||||
if(NETWORK_SETSOCKOPT(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (const char*)&req, sizeof(req)) != 0)
|
||||
{
|
||||
|
||||
this->success=false;
|
||||
if(this->owns)
|
||||
NETWORK_CLOSE(this->sock);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void NetworkStream::SetBroadcast(bool bC)
|
||||
{
|
||||
if(!this->success) return;
|
||||
int broadcast = 1;
|
||||
int broadcast = bC ? 1 : 0;
|
||||
if (NETWORK_SETSOCKOPT(sock, SOL_SOCKET, SO_BROADCAST, (const char*)&broadcast, sizeof(broadcast)) != 0)
|
||||
{
|
||||
this->success=false;
|
||||
@@ -906,6 +976,23 @@ void NetworkStream::SetBroadcast(bool bC)
|
||||
{
|
||||
|
||||
}
|
||||
void NetworkStream::SetReuseAddress(bool reuse)
|
||||
{
|
||||
|
||||
}
|
||||
void NetworkStream::SetReusePort(bool reuse)
|
||||
{
|
||||
|
||||
}
|
||||
void NetworkStream::SetMulticastTTL(uint8_t ttl)
|
||||
{
|
||||
|
||||
}
|
||||
void NetworkStream::SetMulticastMembership(std::string multicastAddress, std::string ifaceIP="0.0.0.0")
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
std::shared_ptr<NetworkStream> NetworkStream::Accept(std::string& ip, uint16_t& port)
|
||||
{
|
||||
return nullptr;
|
||||
|
||||
@@ -49,7 +49,9 @@ namespace Tesses::Framework::Streams {
|
||||
read = len;
|
||||
if(read > 0)
|
||||
{
|
||||
size_t r0=read;
|
||||
read=this->Write(buffer,read);
|
||||
|
||||
if(read == 0)
|
||||
{
|
||||
throw std::out_of_range("Failed to write!");
|
||||
|
||||
@@ -53,6 +53,10 @@ static GXRModeObj *rmode = NULL;
|
||||
|
||||
#endif
|
||||
|
||||
#if !defined(_WIN32)
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
|
||||
namespace Tesses::Framework
|
||||
{
|
||||
@@ -85,7 +89,19 @@ namespace Tesses::Framework
|
||||
cb();
|
||||
#endif
|
||||
}
|
||||
void TF_Sleep(uint32_t sleepMS)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
Sleep((DWORD)sleepMS);
|
||||
#else
|
||||
struct timespec ts;
|
||||
|
||||
ts.tv_sec = (time_t)(sleepMS / 1000);
|
||||
ts.tv_nsec = (sleepMS % 1000) * 1000000;
|
||||
|
||||
nanosleep(&ts,NULL);
|
||||
#endif
|
||||
}
|
||||
void TF_ConnectToSelf(uint16_t port)
|
||||
{
|
||||
Tesses::Framework::Streams::NetworkStream ns("127.0.0.1",port,false,false,false);
|
||||
|
||||
Reference in New Issue
Block a user