6 Commits

Author SHA1 Message Date
266ef5f830 Add relative filesystem
All checks were successful
Build and Deploy on Tag / build-arch (push) Successful in 14m5s
Build and Deploy on Tag / update-tap (push) Successful in 5s
2026-05-01 09:58:10 -05:00
86b062771a Add server sent events, change vfs structure, dark mode error pages and dark mode anonydrop
All checks were successful
Build and Deploy on Tag / build-arch (push) Successful in 14m44s
Build and Deploy on Tag / update-tap (push) Successful in 19s
2026-04-30 07:04:45 -05:00
c55f0c0f4f Add server sent events, change vfs structure, dark mode error pages and dark mode anonydrop
All checks were successful
Build and Deploy on Tag / build-arch (push) Successful in 2m9s
Build and Deploy on Tag / update-tap (push) Successful in 4s
2026-04-23 02:37:07 -05:00
e2c7a5f5bd Add server sent events, change vfs structure, dark mode error pages and dark mode anonydrop
Some checks failed
Build and Deploy on Tag / build-arch (push) Failing after 7s
Build and Deploy on Tag / update-tap (push) Successful in 4s
2026-04-23 02:34:00 -05:00
4cdfbc9542 Add server sent events, change vfs structure, dark mode error pages and dark mode anonydrop
Some checks failed
Build and Deploy on Tag / build-arch (push) Failing after 8s
Build and Deploy on Tag / update-tap (push) Failing after 4s
2026-04-23 02:23:22 -05:00
3807bc5f36 Update 2026-04-20 04:03:47 -05:00
31 changed files with 803 additions and 224 deletions

View File

@@ -5,14 +5,15 @@ on:
- "v*"
env:
GITEA_AUTH: ${{ secrets.MY_GITEA_AUTH }}
PACKAGE_AND_BREW: ${{ secrets.PACKAGE_AND_BREW }}
VERSION: ${{ gitea.ref_name }}
jobs:
build-arch:
runs-on: arch-builder
steps:
- uses: actions/checkout@v4
- run: pacman --noconfirm -Sy mbedtls curl
- run: pacman --noconfirm -Sy mbedtls curl zip zig ninja
- run: pacman --config /opt/cross/ppc/pacman.conf --noconfirm -Sy mbedtls
- run: cp Packaging/Linux/PKGBUILD /home/build/PKGBUILD
- run: cp Packaging/Linux/build-arch.sh /home/build/build-arch.sh
@@ -20,3 +21,30 @@ 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
- run: env -C Packaging/Tools bash build.sh
- uses: akkuman/gitea-release-action@v1
env:
NODE_OPTIONS: '--experimental-fetch' # if nodejs < 18
with:
prerelease: true
files: |-
artifacts/**
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

1
.gitignore vendored
View File

@@ -3,3 +3,4 @@ builds
.vscode
out
/.vs
artifacts

View File

@@ -137,11 +137,6 @@ else()
target_compile_definitions(TessesFramework PUBLIC TESSESFRAMEWORK_CERT_BUNDLE_FILE=${TESSESFRAMEWORK_CERT_BUNDLE_FILE})
endif()
if(NOT TESSESFRAMEWORK_FETCHCONTENT)
if(MBEDTLS_DIR STREQUAL "")
else()
target_include_directories(${TessesFramework_TARGET} PUBLIC ${MBEDTLS_DIR}/include)
target_link_directories(${TessesFramework_TARGET} PUBLIC ${MBEDTLS_DIR}/lib)
endif()
target_link_libraries(${TessesFramework_TARGET} PUBLIC mbedtls mbedx509 mbedcrypto)
endif()
endif()
@@ -219,7 +214,7 @@ if(TESSESFRAMEWORK_FETCHCONTENT)
target_link_libraries(tessesframework_shared PUBLIC mbedtls mbedx509 mbedcrypto everest p256m)
else()
target_link_libraries(tessesframework_shared PUBLIC MbedTLS::mbedcrypto MbedTLS::mbedtls MbedTLS::mbedx509)
target_link_libraries(tessesframework_shared PUBLIC mbedtls mbedx509 mbedcrypto)
endif()
endif()

View File

@@ -1,90 +0,0 @@
{
"version": 3,
"configurePresets": [
{
"name": "linux-debug",
"displayName": "Linux Debug",
"description": "Target the Windows Subsystem for Linux (WSL) or a remote Linux system.",
"generator": "Ninja",
"binaryDir": "${sourceDir}/out/build/${presetName}",
"installDir": "${sourceDir}/out/install/${presetName}",
"cacheVariables": { "CMAKE_BUILD_TYPE": "Debug" },
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Linux"
},
"vendor": { "microsoft.com/VisualStudioRemoteSettings/CMake/2.0": { "remoteSourceRootDir": "$env{HOME}/.vs/$ms{projectDirName}" } }
},
{
"name": "macos-debug",
"displayName": "macOS Debug",
"description": "Target a remote macOS system.",
"generator": "Ninja",
"binaryDir": "${sourceDir}/out/build/${presetName}",
"installDir": "${sourceDir}/out/install/${presetName}",
"cacheVariables": { "CMAKE_BUILD_TYPE": "Debug" },
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Darwin"
},
"vendor": { "microsoft.com/VisualStudioRemoteSettings/CMake/1.0": { "sourceDir": "$env{HOME}/.vs/$ms{projectDirName}" } }
},
{
"name": "windows-base",
"description": "Target Windows with the Visual Studio development environment.",
"hidden": true,
"generator": "Ninja",
"binaryDir": "${sourceDir}/out/build/${presetName}",
"installDir": "${sourceDir}/out/install/${presetName}",
"cacheVariables": {
"CMAKE_C_COMPILER": "cl.exe",
"CMAKE_CXX_COMPILER": "cl.exe",
"TESSESFRAMEWORK_ENABLE_MBED": false,
"TESSESFRAMEWORK_FETCHCONTENT": false
},
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Windows"
}
},
{
"name": "x64-debug",
"displayName": "x64 Debug",
"description": "Target Windows (64-bit) with the Visual Studio development environment. (Debug)",
"inherits": "windows-base",
"architecture": {
"value": "x64",
"strategy": "external"
},
"cacheVariables": { "CMAKE_BUILD_TYPE": "Debug" }
},
{
"name": "x64-release",
"displayName": "x64 Release",
"description": "Target Windows (64-bit) with the Visual Studio development environment. (RelWithDebInfo)",
"inherits": "x64-debug",
"cacheVariables": { "CMAKE_BUILD_TYPE": "Release" }
},
{
"name": "x86-debug",
"displayName": "x86 Debug",
"description": "Target Windows (32-bit) with the Visual Studio development environment. (Debug)",
"inherits": "windows-base",
"architecture": {
"value": "x86",
"strategy": "external"
},
"cacheVariables": { "CMAKE_BUILD_TYPE": "Debug" }
},
{
"name": "x86-release",
"displayName": "x86 Release",
"description": "Target Windows (32-bit) with the Visual Studio development environment. (RelWithDebInfo)",
"inherits": "x86-debug",
"cacheVariables": { "CMAKE_BUILD_TYPE": "Release" }
}
]
}

View File

@@ -4,13 +4,13 @@ pkgver=0.0.3
pkgrel=1
pkgdesc=""
arch=('x86_64' 'powerpc')
url="https://git.tesses.org/tessesframework"
url="https://git.tesses.org/tesses50/tessesframework"
license=('MIT')
groups=()
depends=('mbedtls')
makedepends=('git' 'cmake' 'make' 'base-devel' 'wget') # 'bzr', 'git', 'mercurial' or 'subversion'
install=
source=('tessesframework::git+https://git.tesses.org/tesses-framework')
source=('tessesframework::git+https://git.tesses.org/tesses50/tessesframework')
noextract=()
sha256sums=('SKIP')
if [[ -z "$CMAKE_TOOLCHAIN" ]]; then

View File

@@ -4,7 +4,7 @@ mkdir x86_64
cd x86_64
cp ../PKGBUILD .
makepkg
curl --user tesses50:$GITEA_AUTH \
curl --user tesses50:$PACKAGE_AND_BREW \
--upload-file *.pkg.tar.zst \
https://git.tesses.org/api/packages/tesses50/arch/core
cd ..
@@ -12,6 +12,6 @@ mkdir powerpc
cd powerpc
cp ../PKGBUILD .
CARCH=powerpc CMAKE_TOOLCHAIN=/opt/cross/ppc/toolchain.cmake makepkg
curl --user tesses50:$GITEA_AUTH \
curl --user tesses50:$PACKAGE_AND_BREW \
--upload-file *.pkg.tar.zst \
https://git.tesses.org/api/packages/tesses50/arch/core

35
Packaging/Tools/build.sh Normal file
View File

@@ -0,0 +1,35 @@
mkdir -p ../../artifacts
mkdir -p builds
git clone --depth 1 https://git.tesses.org/tesses50/zig-cross builds/zig-cross
for tripple in x86_64-linux-musl x86-linux-musl aarch64-linux-musl arm-linux-musleabi riscv64-linux-musl powerpc-linux-musleabihf; do
export BUILDDIR=builds/$tripple
mkdir -p $BUILDDIR
cmake -S ../.. -B $BUILDDIR --toolchain $PWD/builds/zig-cross/$tripple\.cmake -DCMAKE_BUILD_TYPE=Release -DTESSESFRAMEWORK_INSTALL_DEVELOPMENT=OFF -DTESSESFRAMEWORK_ENABLE_EXAMPLES=OFF -DTESSESFRAMEWORK_ENABLE_SHARED=OFF -DTESSESFRAMEWORK_ENABLE_STATIC=ON -DCMAKE_EXE_LINKER_FLAGS="-static-libgcc -static-libstdc++ -static -Wl,--strip-all" -DCMAKE_POSITION_INDEPENDENT_CODE=ON -GNinja
cmake --build $BUILDDIR || exit 1
cmake --install $BUILDDIR --prefix $BUILDDIR/out
tar cvzf ../../artifacts/tessesframework-tools-$tripple\.tar.gz -C $BUILDDIR/out/ bin
done
for tripple in x86_64-windows-gnu x86-windows-gnu aarch64-windows-gnu; do
export BUILDDIR=builds/$tripple
mkdir -p $BUILDDIR
cmake -S ../.. -B $BUILDDIR --toolchain $PWD/builds/zig-cross/$tripple\.cmake -DCMAKE_BUILD_TYPE=Release -DTESSESFRAMEWORK_INSTALL_DEVELOPMENT=OFF -DTESSESFRAMEWORK_ENABLE_EXAMPLES=OFF -DTESSESFRAMEWORK_ENABLE_SHARED=OFF -DTESSESFRAMEWORK_ENABLE_STATIC=ON -DCMAKE_EXE_LINKER_FLAGS="-static-libgcc -static-libstdc++ -static -Wl,--strip-all" -DCMAKE_POSITION_INDEPENDENT_CODE=ON -GNinja
cmake --build $BUILDDIR || exit 1
cmake --install $BUILDDIR --prefix $BUILDDIR/out
env -C $BUILDDIR/out zip -r ../../../../../artifacts/tessesframework-tools-$tripple\.zip bin
done
for tripple in x86_64-macos-none aarch64-macos-none; do
export BUILDDIR=builds/$tripple
mkdir -p $BUILDDIR
cmake -S ../.. -B $BUILDDIR --toolchain $PWD/builds/zig-cross/$tripple\.cmake -DCMAKE_BUILD_TYPE=Release -DTESSESFRAMEWORK_INSTALL_DEVELOPMENT=OFF -DTESSESFRAMEWORK_ENABLE_EXAMPLES=OFF -DTESSESFRAMEWORK_ENABLE_SHARED=OFF -DTESSESFRAMEWORK_ENABLE_STATIC=ON -DCMAKE_POSITION_INDEPENDENT_CODE=ON -GNinja -DCMAKE_EXE_LINKER_FLAGS="-Wl,--strip-all"
cmake --build $BUILDDIR || exit 1
cmake --install $BUILDDIR --prefix $BUILDDIR/out
tar cvzf ../../artifacts/tessesframework-tools-$tripple\.tar.gz -C $BUILDDIR/out/ bin
done

19
Packaging/edit-formula.sh Normal file
View 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"

View File

@@ -50,7 +50,7 @@ int main(int argc, char** argv)
.SendText(
"<!DOCTYPE html>"
"<html>"
"<head><title>AnonyDrop - Uploaded successfully</title>"
"<head><meta name=\"color-scheme\" content=\"dark light\"><title>AnonyDrop - Uploaded successfully</title></head>"
"<body>"
"<h1>Uploaded successfully</h1>"
"<a href=\"./\">Back</a>"

View File

@@ -1,8 +1,10 @@
# Changelog
## 0.0.3
Add server sent events, change vfs structure, dark mode error pages and dark mode anonydrop
## 0.0.2
Add UUIDs
## 0.0.1
Start versioning

View File

@@ -47,6 +47,7 @@ src/Filesystem/LocalFS.cpp
src/Filesystem/SubdirFilesystem.cpp
src/Filesystem/NullFilesystem.cpp
src/Filesystem/MountableFilesystem.cpp
src/Filesystem/RelativeFilesystem.cpp
src/Filesystem/FSHelpers.cpp
src/Filesystem/TempFS.cpp
src/Crypto/MbedTLS/ClientTLSStream.cpp

View File

@@ -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;

View File

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

View File

@@ -0,0 +1,54 @@
#pragma once
#include "VFS.hpp"
#include "VFSFix.hpp"
namespace Tesses::Framework::Filesystem
{
class RelativeFilesystem : public VFS {
Tesses::Framework::Threading::Mutex mtx;
VFSPath working;
std::shared_ptr<VFS> vfs;
private:
VFSPath ToParent(VFSPath path);
public:
RelativeFilesystem(std::shared_ptr<VFS> vfs, VFSPath working);
VFSPath GetWorking();
void SetWorking(VFSPath path);
std::shared_ptr<VFS> GetVFS();
std::shared_ptr<Tesses::Framework::Streams::Stream> OpenFile(VFSPath path, std::string mode);
void CreateDirectory(VFSPath path);
void DeleteDirectory(VFSPath path);
void DeleteFile(VFSPath path);
void CreateSymlink(VFSPath existingFile, VFSPath symlinkFile);
VFSPathEnumerator EnumeratePaths(VFSPath path);
void CreateHardlink(VFSPath existingFile, VFSPath newName);
void MoveFile(VFSPath src, VFSPath dest);
void MoveDirectory(VFSPath src, VFSPath dest);
void DeleteDirectoryRecurse(VFSPath path);
VFSPath ReadLink(VFSPath path);
std::string VFSPathToSystem(VFSPath path);
VFSPath SystemToVFSPath(std::string path);
void SetDate(VFSPath path, Date::DateTime lastWrite, Date::DateTime lastAccess);
bool StatVFS(VFSPath path, StatVFSData& vfsData);
bool Stat(VFSPath path, StatData& data);
void Chown(VFSPath path, uint32_t uid, uint32_t gid);
void Chmod(VFSPath path, uint32_t mode);
FIFOCreationResult CreateFIFO(VFSPath path, uint32_t mode);
void Lock(VFSPath path);
void Unlock(VFSPath path);
protected:
std::shared_ptr<FSWatcher> CreateWatcher(std::shared_ptr<VFS> vfs, VFSPath path);
class Watcher : public FSWatcher {
std::shared_ptr<FSWatcher> watcher;
protected:
void SetEnabledImpl(bool enabled);
public:
Watcher(std::shared_ptr<RelativeFilesystem> vfs, VFSPath path);
~Watcher();
};
};
}

View File

@@ -35,5 +35,19 @@ namespace Tesses::Framework::Filesystem
FIFOCreationResult CreateFIFO(VFSPath path, uint32_t mode);
void Lock(VFSPath path);
void Unlock(VFSPath path);
protected:
std::shared_ptr<FSWatcher> CreateWatcher(std::shared_ptr<VFS> vfs, VFSPath path);
class Watcher : public FSWatcher {
std::shared_ptr<FSWatcher> watcher;
protected:
void SetEnabledImpl(bool enabled);
public:
Watcher(std::shared_ptr<SubdirFilesystem> vfs, VFSPath path);
~Watcher();
};
};
}

View File

@@ -44,5 +44,9 @@ namespace Tesses::Framework::Filesystem
void Lock(VFSPath path);
void Unlock(VFSPath path);
~TempFS();
protected:
std::shared_ptr<FSWatcher> CreateWatcher(std::shared_ptr<VFS> vfs, VFSPath path);
};
}

View File

@@ -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 {

View File

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

View File

@@ -31,6 +31,7 @@
#include "Filesystem/SubdirFilesystem.hpp"
#include "Filesystem/NullFilesystem.hpp"
#include "Filesystem/MountableFilesystem.hpp"
#include "Filesystem/RelativeFilesystem.hpp"
#include "Filesystem/FSHelpers.hpp"
#include "Crypto/ClientTLSStream.hpp"
#include "Crypto/Crypto.hpp"

View File

@@ -33,9 +33,17 @@ namespace Tesses::Framework::Filesystem
#endif
bool LocalFilesystem::Stat(VFSPath path, StatData& sfs)
{
std::string s = VFSPathToSystem(path);
#if defined(_WIN32)
struct __stat64 st;
if(_stat64(s.c_str(),&st) == 0)
#else
struct stat st;
if(stat(s.c_str(),&st) == 0)
#endif
{
sfs.Device = (uint64_t)st.st_dev;
@@ -46,8 +54,13 @@ namespace Tesses::Framework::Filesystem
sfs.GroupId = (uint32_t)st.st_gid;
sfs.DeviceId = (uint64_t)st.st_rdev;
sfs.Size = (uint64_t)st.st_size;
#if defined(_WIN32)
sfs.BlockSize = 512;
sfs.BlockCount = sfs.Size / sfs.BlockSize;
#else
sfs.BlockSize = (uint64_t)st.st_blksize;
sfs.BlockCount = (uint64_t)st.st_blocks;
#endif
sfs.LastAccess = Date::DateTime((int64_t)st.st_atime);
sfs.LastModified = Date::DateTime((int64_t)st.st_mtime);
sfs.LastStatus = Date::DateTime((int64_t)st.st_ctime);

View File

@@ -0,0 +1,206 @@
#include "TessesFramework/Filesystem/RelativeFilesystem.hpp"
namespace Tesses::Framework::Filesystem
{
VFSPath RelativeFilesystem::ToParent(VFSPath path)
{
if(path.relative)
{
return path.MakeAbsolute(GetWorking());
}
else
{
return path;
}
}
RelativeFilesystem::RelativeFilesystem(std::shared_ptr<VFS> vfs, VFSPath working) : vfs(vfs), working(working)
{
}
VFSPath RelativeFilesystem::GetWorking()
{
mtx.Lock();
auto p = this->working;
mtx.Unlock();
return p;
}
void RelativeFilesystem::SetWorking(VFSPath path)
{
mtx.Lock();
this->working=path;
mtx.Unlock();
}
std::shared_ptr<VFS> RelativeFilesystem::GetVFS()
{
return vfs;
}
std::shared_ptr<Tesses::Framework::Streams::Stream> RelativeFilesystem::OpenFile(VFSPath path, std::string mode)
{
return this->vfs->OpenFile(ToParent(path),mode);
}
void RelativeFilesystem::CreateDirectory(VFSPath path)
{
this->vfs->CreateDirectory(ToParent(path));
}
void RelativeFilesystem::DeleteDirectory(VFSPath path)
{
this->vfs->DeleteDirectory(ToParent(path));
}
void RelativeFilesystem::DeleteFile(VFSPath path)
{
this->vfs->DeleteFile(ToParent(path));
}
void RelativeFilesystem::CreateSymlink(VFSPath existingFile, VFSPath symlinkFile)
{
this->vfs->CreateSymlink(existingFile, ToParent(symlinkFile));
}
VFSPathEnumerator RelativeFilesystem::EnumeratePaths(VFSPath path)
{
VFSPathEnumerator* enumerator = this->vfs->EnumeratePaths(ToParent(path)).MakePointer();
return VFSPathEnumerator([enumerator,path,this](VFSPath& path0)->bool{
if(enumerator->MoveNext())
{
path0 = path / enumerator->Current.GetFileName();
return true;
}
return false;
},[enumerator]()->void{
delete enumerator;
});
}
void RelativeFilesystem::CreateHardlink(VFSPath existingFile, VFSPath newName)
{
if(existingFile.relative || newName.relative)
{
auto working = GetWorking();
if(existingFile.relative)
existingFile = existingFile.MakeAbsolute(working);
if(newName.relative)
newName = newName.MakeAbsolute(working);
}
vfs->CreateHardlink(existingFile, newName);
}
void RelativeFilesystem::MoveFile(VFSPath src, VFSPath dest)
{
if(src.relative || dest.relative)
{
auto working = GetWorking();
if(src.relative)
src = src.MakeAbsolute(working);
if(dest.relative)
dest = dest.MakeAbsolute(working);
}
vfs->MoveFile(src, dest);
}
void RelativeFilesystem::MoveDirectory(VFSPath src, VFSPath dest)
{
if(src.relative || dest.relative)
{
auto working = GetWorking();
if(src.relative)
src = src.MakeAbsolute(working);
if(dest.relative)
dest = dest.MakeAbsolute(working);
}
vfs->MoveDirectory(src, dest);
}
void RelativeFilesystem::DeleteDirectoryRecurse(VFSPath path)
{
vfs->DeleteDirectoryRecurse(ToParent(path));
}
VFSPath RelativeFilesystem::ReadLink(VFSPath path)
{
return vfs->ReadLink(ToParent(path));
}
std::string RelativeFilesystem::VFSPathToSystem(VFSPath path)
{
return vfs->VFSPathToSystem(path);
}
VFSPath RelativeFilesystem::SystemToVFSPath(std::string path)
{
return vfs->SystemToVFSPath(path);
}
void RelativeFilesystem::SetDate(VFSPath path, Date::DateTime lastWrite, Date::DateTime lastAccess)
{
vfs->SetDate(ToParent(path),lastWrite,lastAccess);
}
bool RelativeFilesystem::StatVFS(VFSPath path, StatVFSData& vfsData)
{
return vfs->StatVFS(ToParent(path), vfsData);
}
bool RelativeFilesystem::Stat(VFSPath path, StatData& data)
{
return vfs->Stat(ToParent(path),data);
}
void RelativeFilesystem::Chown(VFSPath path, uint32_t uid, uint32_t gid)
{
vfs->Chown(ToParent(path),uid,gid);
}
void RelativeFilesystem::Chmod(VFSPath path, uint32_t mode)
{
vfs->Chmod(ToParent(path), mode);
}
FIFOCreationResult RelativeFilesystem::CreateFIFO(VFSPath path, uint32_t mode)
{
return vfs->CreateFIFO(ToParent(path),mode);
}
void RelativeFilesystem::Lock(VFSPath path)
{
vfs->Lock(ToParent(path));
}
void RelativeFilesystem::Unlock(VFSPath path)
{
vfs->Unlock(ToParent(path));
}
RelativeFilesystem::Watcher::Watcher(std::shared_ptr<RelativeFilesystem> vfs, VFSPath path) : FSWatcher(vfs, path)
{
this->watcher = FSWatcher::Create(vfs->vfs, vfs->ToParent(path));
this->watcher->event = [vfs,this,path](FSWatcherEvent & evt)-> void{
if(path.relative)
{
auto working = vfs->GetWorking();
FSWatcherEvent e2=evt;
if(evt.IsEvent(FSWatcherEventType::Moved))
{
e2.dest = e2.dest.MakeRelative(working);
}
e2.src = e2.src.MakeRelative(working);
if(this->event) this->event(e2);
}
else {
if(this->event)
this->event(evt);
}
};
}
void RelativeFilesystem::Watcher::SetEnabledImpl(bool enabled)
{
this->enabled = enabled;
this->watcher->events = this->events;
this->watcher->SetEnabled(enabled);
}
RelativeFilesystem::Watcher::~Watcher()
{
this->watcher->SetEnabled(false);
}
std::shared_ptr<FSWatcher> RelativeFilesystem::CreateWatcher(std::shared_ptr<VFS> vfs, VFSPath path)
{
auto sdfs = std::dynamic_pointer_cast<RelativeFilesystem>(vfs);
if(sdfs)
{
return std::make_shared<Watcher>(sdfs,path);
}
return VFS::CreateWatcher(vfs,path);
}
}

View File

@@ -77,7 +77,7 @@ namespace Tesses::Framework::Filesystem
{
VFSPathEnumerator* enumerator = this->parent->EnumeratePaths(ToParent(path)).MakePointer();
return VFSPathEnumerator([enumerator,path,this](VFSPath& path0)->bool{
return VFSPathEnumerator([enumerator,this](VFSPath& path0)->bool{
if(enumerator->MoveNext())
{
path0 = FromParent(enumerator->Current);
@@ -146,4 +146,40 @@ namespace Tesses::Framework::Filesystem
{
return this->parent->CreateFIFO(path, mod);
}
SubdirFilesystem::Watcher::Watcher(std::shared_ptr<SubdirFilesystem> vfs, VFSPath path) : FSWatcher(vfs, path)
{
this->watcher = FSWatcher::Create(vfs->parent, vfs->ToParent(path));
this->watcher->event = [vfs,this](FSWatcherEvent & evt)-> void{
FSWatcherEvent e2=evt;
if(evt.IsEvent(FSWatcherEventType::Moved))
{
e2.dest = vfs->FromParent(e2.dest);
}
e2.src = vfs->FromParent(e2.src);
if(this->event) this->event(e2);
};
}
void SubdirFilesystem::Watcher::SetEnabledImpl(bool enabled)
{
this->enabled = enabled;
this->watcher->events = this->events;
this->watcher->SetEnabled(enabled);
}
SubdirFilesystem::Watcher::~Watcher()
{
this->watcher->SetEnabled(false);
}
std::shared_ptr<FSWatcher> SubdirFilesystem::CreateWatcher(std::shared_ptr<VFS> vfs, VFSPath path)
{
auto sdfs = std::dynamic_pointer_cast<SubdirFilesystem>(vfs);
if(sdfs)
{
return std::make_shared<Watcher>(sdfs,path);
}
return VFS::CreateWatcher(vfs,path);
}
}

View File

@@ -170,6 +170,11 @@ namespace Tesses::Framework::Filesystem {
if(this->deleteOnDestroy && this->parent->DirectoryExists(p))
this->parent->DeleteDirectoryRecurse(p);
}
std::shared_ptr<FSWatcher> TempFS::CreateWatcher(std::shared_ptr<VFS> vfs, VFSPath path)
{
return FSWatcher::Create(vfs,path);
}
TempFS::~TempFS()
{
VFSPath p;

View File

@@ -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 {};
@@ -390,7 +493,7 @@ namespace Tesses::Framework::Http
static bool parseUntillBoundaryEnd(std::shared_ptr<Tesses::Framework::Streams::Stream> src, std::shared_ptr<Tesses::Framework::Streams::Stream> dest, std::string boundary)
{
bool hasMore=true;
uint8_t* checkBuffer = new uint8_t[boundary.size()];
std::vector<uint8_t> checkBuffer(boundary.size());
int b;
size_t i = 0;
@@ -455,8 +558,6 @@ namespace Tesses::Framework::Http
{
dest->Write(buffer,offsetInMem);
}
delete[] checkBuffer;
return hasMore;
}
@@ -1025,10 +1126,9 @@ namespace Tesses::Framework::Http
if(ctx.requestHeaders.TryGetFirst("Content-Type",type) && type == "application/x-www-form-urlencoded" && ctx.requestHeaders.TryGetFirstInt("Content-Length",length))
{
size_t len = (size_t)length;
uint8_t* buffer = new uint8_t[len];
len = bStrm->ReadBlock(buffer,len);
std::string query((const char*)buffer,len);
delete[] buffer;
std::vector<uint8_t> buffer(len);
len = bStrm->ReadBlock(buffer.data(),len);
std::string query((const char*)buffer.data(),len);
HttpUtils::QueryParamsDecode(ctx.queryParams, query);
}

View File

@@ -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(...) {
}
}
}
}

View File

@@ -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,77 @@ 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 !defined(_WIN32)
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);
}
#endif
}
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 +978,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;

View File

@@ -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!");
@@ -106,36 +108,34 @@ namespace Tesses::Framework::Streams {
void Stream::CopyToLimit(std::shared_ptr<Stream> strm,uint64_t len, size_t buffSize)
{
size_t read;
uint8_t* buffer = new uint8_t[buffSize];
std::vector<uint8_t> buffer(buffSize);
uint64_t offset = 0;
do {
if(offset >= len) break;
read = (size_t)std::min(len-offset,(uint64_t)buffSize);
read = (size_t)std::min(len-offset,(uint64_t)buffer.size());
read = this->Read(buffer,read);
strm->WriteBlock(buffer, read);
read = this->Read(buffer.data(),read);
strm->WriteBlock(buffer.data(), read);
offset += read;
} while(read > 0 && !strm->EndOfStream());
strm->Flush();
delete[] buffer;
}
void Stream::CopyTo(std::shared_ptr<Stream> strm, size_t buffSize)
{
size_t read;
uint8_t* buffer = new uint8_t[buffSize];
std::vector<uint8_t> buffer(buffSize);
do {
read = this->Read(buffer,buffSize);
strm->WriteBlock(buffer, read);
read = this->Read(buffer.data(),buffer.size());
strm->WriteBlock(buffer.data(), read);
} while(read > 0 && !strm->EndOfStream());
strm->Flush();
delete[] buffer;
}
Stream::~Stream()

View File

@@ -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);

View File

@@ -16,12 +16,12 @@ namespace Tesses::Framework::Text {
uint64_t total = 0;
size_t read;
uint8_t* data = new uint8_t[BLK_SZ];
std::vector<uint8_t> data(BLK_SZ);
bool first=true;
do {
read = strm->ReadBlock(data, BLK_SZ);
read = strm->ReadBlock(data.data(), data.size());
for(size_t i = 0; i < read; i++)
{
@@ -33,7 +33,6 @@ namespace Tesses::Framework::Text {
} while(read != 0);
delete data;
writer->WriteLine("};");
writer->Write("const size_t ");

View File

@@ -9,23 +9,18 @@ namespace Tesses::Framework::TextStreams
}
bool ConsoleReader::ReadBlock(std::string& str,size_t len)
{
#if defined(_WIN32)
uint8_t* buff = new uint8_t[len];
#else
uint8_t buff[len];
#endif
std::vector<uint8_t> buff(len);
size_t read=0;
size_t readTotal=0;
uint8_t* buffOff=buff;
uint8_t* buffOff=buff.data();
do {
read=fread(buffOff,1,len,stdin);
if(read != 0) {readTotal+= read;len-=read; buffOff+=read;}
} while(read != 0);
if(readTotal == 0) return false;
str.append((const char*)buff, readTotal);
#if defined(_WIN32)
delete buff;
#endif
str.append((const char*)buff.data(), readTotal);
return true;
}

View File

@@ -30,13 +30,12 @@ namespace Tesses::Framework::TextStreams {
bool StreamReader::ReadBlock(std::string& str, size_t len)
{
uint8_t* buff = new uint8_t[len];
std::vector<uint8_t> buff(len);
len = strm->ReadBlock(buff,len);
if(len == 0) {delete buff; return false;}
str.append((const char*)buff, len);
len = strm->ReadBlock(buff.data(),len);
if(len == 0) { return false;}
str.append((const char*)buff.data(), len);
delete buff;
return true;
}