From 7e6f0f1fca7b6a4464538c5e66305c5b0d7c0243 Mon Sep 17 00:00:00 2001 From: Mike Nolan Date: Fri, 3 Jan 2025 05:50:44 -0600 Subject: [PATCH] Added memoryfilesystem and working on c wrapper --- CMakeLists.txt | 2 + examples/wrappertest.c | 21 + .../Filesystem/MemoryFilesystem.hpp | 99 +++ .../TessesFramework/Streams/FileStream.hpp | 1 + include/TessesFramework/TessesFramework.h | 77 ++ include/TessesFramework/TessesFramework.hpp | 2 + .../TessesFramework/Threading/ThreadPool.hpp | 23 + src/Filesystem/MemoryFilesystem.cpp | 666 ++++++++++++++++++ src/Filesystem/VFS.cpp | 4 +- src/Http/HttpServer.cpp | 10 + src/Http/HttpUtils.cpp | 2 +- src/Streams/FileStream.cpp | 11 +- src/Streams/MemoryStream.cpp | 2 +- src/Streams/NetworkStream.cpp | 15 +- src/Streams/Stream.cpp | 2 +- src/Threading/ThreadPool.cpp | 69 ++ src/wrapper.cpp | 231 ++++++ 17 files changed, 1229 insertions(+), 8 deletions(-) create mode 100644 examples/wrappertest.c create mode 100644 include/TessesFramework/Filesystem/MemoryFilesystem.hpp create mode 100644 include/TessesFramework/TessesFramework.h create mode 100644 include/TessesFramework/Threading/ThreadPool.hpp create mode 100644 src/Filesystem/MemoryFilesystem.cpp create mode 100644 src/Threading/ThreadPool.cpp create mode 100644 src/wrapper.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 65e036f..35c511b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,11 +24,13 @@ src/Threading/Thread.cpp src/Threading/Mutex.cpp src/Filesystem/VFS.cpp src/Filesystem/LocalFS.cpp +src/Filesystem/MemoryFilesystem.cpp src/Filesystem/SubdirFilesystem.cpp src/Filesystem/NullFilesystem.cpp src/Filesystem/MountableFilesystem.cpp src/Crypto/ClientTLSStream.cpp src/TF_Init.cpp +src/wrapper.cpp ) set(TESSESFRAMEWORK_CERT_BUNDLE_FILE "/etc/ssl/certs/ca-certificates.crt" CACHE FILEPATH "Path to ca-chain") diff --git a/examples/wrappertest.c b/examples/wrappertest.c new file mode 100644 index 0000000..8c7037d --- /dev/null +++ b/examples/wrappertest.c @@ -0,0 +1,21 @@ +#include "TessesFramework.h" + +int main(int argc, char** argv) +{ + tf_vfs_t* local = tf_vfs_create_local(); + + tf_vfs_dir_t* dir = tf_vfs_opendir(local, "/home/mike"); + + string_t* str; + while(str = tf_vfs_readdir(dir)) + { + string_println(str); + } + tf_vfs_closedir(dir); + + tf_stream_t* strm = tf_vfs_open(local,"/home/mike/myPhoto.png", "wb"); + + + + tf_vfs_close(local); +} \ No newline at end of file diff --git a/include/TessesFramework/Filesystem/MemoryFilesystem.hpp b/include/TessesFramework/Filesystem/MemoryFilesystem.hpp new file mode 100644 index 0000000..285ecac --- /dev/null +++ b/include/TessesFramework/Filesystem/MemoryFilesystem.hpp @@ -0,0 +1,99 @@ +#pragma once +#include "VFS.hpp" +#include "VFSFix.hpp" +#include "../Threading/Mutex.hpp" +#include +namespace Tesses::Framework::Filesystem +{ + class MemoryEntry { + public: + std::string name; + virtual ~MemoryEntry(); + }; + class MemoryFileData { + public: + MemoryFileData(); + time_t lastWrite; + + bool canAccess; + size_t readers; + std::vector file; + }; + + class MemoryFile : public MemoryEntry + { + public: + std::shared_ptr data; + ~MemoryFile(); + }; + + class MemoryDirectory : public MemoryEntry + { + public: + MemoryDirectory(); + time_t lastWrite; + std::vector entries; + ~MemoryDirectory(); + }; + + class MemorySymlink : public MemoryEntry + { + public: + time_t lastWrite; + VFSPath linkedTo; + }; + + class MemoryFilesystemStream : public Streams::Stream + { + public: + std::shared_ptr mtx; + std::shared_ptr data; + bool canRead; + bool canWrite; + bool canSeek; + int64_t pos; + MemoryFilesystemStream(std::shared_ptr mtx, std::shared_ptr data,bool canRead, bool canWrite, bool canSeek); + size_t Read(uint8_t* buff, size_t sz); + size_t Write(const uint8_t* buff, size_t sz); + bool CanRead(); + bool CanWrite(); + bool CanSeek(); + int64_t GetPosition(); + void Flush(); + void Seek(int64_t pos, Streams::SeekOrigin whence); + ~MemoryFilesystemStream(); + }; + + + class MemoryFilesystem : public VFS + { + std::shared_ptr mtx; + MemoryDirectory root; + + MemoryEntry* GetEntry(VFSPath path,bool followSymlink); + public: + MemoryFilesystem(); + Tesses::Framework::Streams::Stream* OpenFile(VFSPath path, std::string mode); + + void CreateDirectory(VFSPath path); + void DeleteDirectory(VFSPath path); + bool RegularFileExists(VFSPath path); + bool SymlinkExists(VFSPath path); + bool DirectoryExists(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); + VFSPath ReadLink(VFSPath path); + std::string VFSPathToSystem(VFSPath path); + VFSPath SystemToVFSPath(std::string path); + void GetDate(VFSPath path, time_t& lastWrite, time_t& lastAccess); + void SetDate(VFSPath path, time_t lastWrite, time_t lastAccess); + ~MemoryFilesystem(); + }; +}; \ No newline at end of file diff --git a/include/TessesFramework/Streams/FileStream.hpp b/include/TessesFramework/Streams/FileStream.hpp index 330acab..783568d 100644 --- a/include/TessesFramework/Streams/FileStream.hpp +++ b/include/TessesFramework/Streams/FileStream.hpp @@ -15,6 +15,7 @@ namespace Tesses::Framework::Streams FileStream(FILE* f, bool owns, std::string mode , bool canSeek=true); size_t Read(uint8_t* buff, size_t sz); size_t Write(const uint8_t* buff, size_t sz); + bool EndOfStream(); bool CanRead(); bool CanWrite(); bool CanSeek(); diff --git a/include/TessesFramework/TessesFramework.h b/include/TessesFramework/TessesFramework.h new file mode 100644 index 0000000..e0e862e --- /dev/null +++ b/include/TessesFramework/TessesFramework.h @@ -0,0 +1,77 @@ +#pragma once + +#if defined(__cplusplus) +extern "C" { +#endif +#include +#include +#include + +typedef void string_t; +typedef void tf_vfs_t; +typedef void tf_stream_t; +typedef void tf_thread_t; +typedef void tf_mutex_t; +typedef void tf_vfs_dir_t; + +typedef void (*tf_action_user_data_t)(void* ptr); + + +typedef enum { + TF_SEEK_BEGIN, + TF_SEEK_CURRENT, + TF_SEEK_END +} TF_WHENCE; + +string_t* string_create(); +string_t* string_create_from_buff(const void* text, size_t len); +string_t* string_create_from_charpointer(const char* text); +string_t* string_resize(string_t* str, size_t len); +string_t* string_set_char(string_t* str, size_t index, char c); +char string_get_char(string_t* str,size_t index); +string_t* string_append_char(string_t* str, char c); +string_t* string_append_from_buff(string_t* str,const void* text, size_t len); +string_t* string_append_from_charpointer(string_t* str,const char* text); +string_t* string_append(string_t* str, string_t* toAppend); +string_t* string_append_signed(string_t* str, int64_t num); +string_t* string_append_unsigned(string_t* str, uint64_t num); +string_t* string_append_double(string_t* str, double num); +void string_print(string_t* str); +void string_println(string_t* str); +size_t string_size(string_t* str); +const char* string_c_str(string_t* str); +void string_free(string_t* str); + +void tf_init(); +tf_thread_t* tf_create_thread(void* userData, tf_action_user_data_t cb); +void tf_join_thread(tf_thread_t* thrd); +void tf_detach_thread(tf_thread_t* thrd); + +tf_mutex_t* tf_mutex_create(); +void tf_mutex_lock(tf_mutex_t* mtx); +bool tf_mutex_trylock(tf_mutex_t* mtx); +void tf_mutex_unlock(tf_mutex_t* mtx); +void tf_mutex_free(tf_mutex_t* mtx); + +bool tf_stream_canread(tf_stream_t* strm); +bool tf_stream_canwrite(tf_stream_t* strm); +bool tf_stream_canseek(tf_stream_t* strm); +bool tf_stream_eof(tf_stream_t* strm); +int64_t tf_stream_getlen(tf_stream_t* strm); +int64_t tf_stream_getpos(tf_stream_t* strm); +void tf_stream_seek(tf_stream_t* strm, int64_t pos, TF_WHENCE whence); +size_t tf_stream_read(tf_stream_t* strm, uint8_t* buffer, size_t length); +size_t tf_stream_write(tf_stream_t* strm, const uint8_t* buffer, size_t length); +size_t tf_stream_readblock(tf_stream_t* strm, uint8_t* buffer, size_t length); +void tf_stream_writeblock(tf_stream_t* strm, const uint8_t* buffer, size_t length); +void tf_stream_copyto(tf_stream_t* src, tf_stream_t* dest, size_t blockSize); +void tf_stream_close(tf_stream_t* strm); +void tf_stream_flush(tf_stream_t* strm); +int32_t tf_stream_readbyte(tf_stream_t* strm); +void tf_stream_writebyte(tf_stream_t* strm, uint8_t val); + +tf_stream_t* tf_stream_fopen(const char* file, const char* mode); + +#if defined(__cplusplus) +} +#endif diff --git a/include/TessesFramework/TessesFramework.hpp b/include/TessesFramework/TessesFramework.hpp index fe4ef4e..e90cadb 100644 --- a/include/TessesFramework/TessesFramework.hpp +++ b/include/TessesFramework/TessesFramework.hpp @@ -11,8 +11,10 @@ #include "TextStreams/StreamWriter.hpp" #include "Threading/Thread.hpp" #include "Threading/Mutex.hpp" +#include "Threading/ThreadPool.hpp" #include "Filesystem/LocalFS.hpp" #include "Filesystem/SubdirFilesystem.hpp" #include "Filesystem/NullFilesystem.hpp" #include "Filesystem/MountableFilesystem.hpp" +#include "Filesystem/MemoryFilesystem.hpp" #include "Crypto/ClientTLSStream.hpp" \ No newline at end of file diff --git a/include/TessesFramework/Threading/ThreadPool.hpp b/include/TessesFramework/Threading/ThreadPool.hpp new file mode 100644 index 0000000..aaa69f6 --- /dev/null +++ b/include/TessesFramework/Threading/ThreadPool.hpp @@ -0,0 +1,23 @@ +#pragma once +#include +#include "Thread.hpp" +#include "Mutex.hpp" +#include +#include + +namespace Tesses::Framework::Threading +{ + +class ThreadPool +{ + std::vector threads; + std::queue> callbacks; + Mutex mtx; + volatile bool isRunning; + public: + static size_t GetNumberOfCores(); + ThreadPool(size_t threads); + void Schedule(std::function cb); + ~ThreadPool(); +}; +} \ No newline at end of file diff --git a/src/Filesystem/MemoryFilesystem.cpp b/src/Filesystem/MemoryFilesystem.cpp new file mode 100644 index 0000000..07ef07d --- /dev/null +++ b/src/Filesystem/MemoryFilesystem.cpp @@ -0,0 +1,666 @@ +#include "TessesFramework/Filesystem/MemoryFilesystem.hpp" +#include + +namespace Tesses::Framework::Filesystem +{ + MemoryFilesystemStream::MemoryFilesystemStream(std::shared_ptr mtx, std::shared_ptr data,bool canRead, bool canWrite, bool canSeek) + { + this->mtx = mtx; + this->data = data; + this->canRead = canRead; + this->canWrite = canWrite; + this->canSeek = canSeek; + this->pos=0; + } + size_t MemoryFilesystemStream::Read(uint8_t* buff, size_t sz) + { + if(!this->canRead) return 0; + if(this->pos >= this->data->file.size()) return 0; + size_t toRead = std::min(sz, (size_t)(this->data->file.size()-this->pos)); + memcpy(buff, this->data->file.data() + this->pos, toRead); + + this->pos += toRead; + return toRead; + } + size_t MemoryFilesystemStream::Write(const uint8_t* buff, size_t sz) + { + if(!this->canWrite) return 0; + if(this->canSeek) + { + + if(this->pos > this->data->file.size()) + { + this->data->file.resize(this->pos+sz); + } + this->data->file.insert(this->data->file.begin()+this->pos, buff, buff+sz); + this->pos+=sz; + + } + else + { + this->data->file.insert(this->data->file.end(), buff, buff+sz); + } + return sz; + } + bool MemoryFilesystemStream::CanRead() + { + return canRead; + } + bool MemoryFilesystemStream::CanWrite() + { + return canWrite; + } + bool MemoryFilesystemStream::CanSeek() + { + return canSeek; + } + int64_t MemoryFilesystemStream::GetPosition() + { + if(!this->canSeek) return (int64_t)this->data->file.size(); + return pos; + } + void MemoryFilesystemStream::Flush() + { + //its already flushed + } + void MemoryFilesystemStream::Seek(int64_t pos, Streams::SeekOrigin whence) + { + if(canSeek) return; + switch(whence) + { + case Streams::SeekOrigin::Begin: + this->pos = (size_t)pos; + break; + case Streams::SeekOrigin::Current: + this->pos += (size_t)pos; + break; + case Streams::SeekOrigin::End: + this->pos = (size_t)(this->data->file.size() + pos); + break; + } + } + MemoryFilesystemStream::~MemoryFilesystemStream() + { + mtx->Lock(); + if(this->canWrite) this->data->canAccess=true; + this->data->readers--; + mtx->Unlock(); + } + + MemoryEntry* MemoryFilesystem::GetEntry(VFSPath path,bool followSymlink) + { + if(path.relative) return nullptr; + if(path.path.empty()) return &this->root; + + auto entry = GetEntry(path.GetParent(),true); + if(entry == nullptr) return nullptr; + + auto dir = dynamic_cast(entry); + if(dir != nullptr) + { + for(auto item : dir->entries) + { + if(item->name == path.GetFileName()) + { + auto link = dynamic_cast(item); + if(followSymlink && link != nullptr) + { + item = GetEntry(link->linkedTo,true); + } + return item; + } + } + } + return nullptr; + } + + Streams::Stream* MemoryFilesystem::OpenFile(VFSPath path, std::string mode) + { + bool canRead=false; + bool canWrite=false; + bool canSeek=true; + bool mustExist=false; + bool truncate=false; + + + if(mode.size() >= 1) + { + if(mode[0] == 'r') + { + canRead = true; + mustExist=true; + } + else if(mode[0] == 'w') + { + canWrite = true; + truncate=true; + } + else if(mode[0] == 'a') + { + canSeek = false; + canWrite = true; + } + } + + if(((mode.size() >= 2 && mode[1] == '+') || (mode.size() >= 2 && mode[1] == 'b' && mode[2] == '+'))) + { + canRead = true; + canWrite = true; + } + + mtx->Lock(); + if(mustExist) + { + auto file = GetEntry(path,true); + + if(file == nullptr) + { + mtx->Unlock(); + return nullptr; + } + + auto f = dynamic_cast(file); + if(f == nullptr) + { + mtx->Unlock(); + return nullptr; + } + if(!f->data->canAccess) + { + mtx->Unlock(); + return nullptr; + } + if(canWrite && f->data->readers > 0) + { + mtx->Unlock(); + return nullptr; + } + f->data->readers++; + if(canWrite) f->data->canAccess=false; + + mtx->Unlock(); + return new MemoryFilesystemStream(mtx,f->data,canRead,canWrite,canSeek); + } + else + { + auto file = dynamic_cast(GetEntry(path,true)); + + + if(file != nullptr) + { + if(!file->data->canAccess) + { + mtx->Unlock(); + return nullptr; + } + if(file->data->readers > 0) + { + mtx->Unlock(); + return nullptr; + } + file->data->canAccess=false; + file->data->readers++; + if(truncate) {file->data->file.clear(); file->data->lastWrite=time(NULL);} + mtx->Unlock(); + return new MemoryFilesystemStream(mtx,file->data,canRead,canWrite,canSeek); + + } + + + auto dir = GetEntry(path.GetParent(),true); + + if(dir == nullptr) + { + mtx->Unlock(); + return nullptr; + } + + auto myDir = dynamic_cast(dir); + + + if(myDir == nullptr) + { + mtx->Unlock(); + return nullptr; + } + + MemoryFile* thefile=nullptr; + + for(auto f : myDir->entries) + { + if(f->name == path.GetFileName()) + { + auto symlink = dynamic_cast(f); + while(symlink != nullptr) + { + auto ent = GetEntry(symlink->name,false); + auto sym = dynamic_cast(f); + if(sym != nullptr) + symlink = sym; + else + { + auto myDir0 = dynamic_cast(GetEntry(symlink->linkedTo.GetParent(),true)); + if(myDir0 != nullptr) + { + for(auto f2 : myDir0->entries) + { + if(f2->name == symlink->linkedTo.GetFileName()) + { + auto myFile = dynamic_cast(f2); + if(myFile != nullptr) + { + thefile = myFile; + break; + } + else + { + mtx->Unlock(); + return nullptr; + } + } + + } + myDir = myDir0; + } + else + { + mtx->Unlock(); + return nullptr; + } + break; + } + } + break; + } + } + if(thefile == nullptr) + { + + MemoryFile* f = new MemoryFile(); + f->name = path.GetFileName(); + f->data = std::make_shared(); + f->data->canAccess=false; + f->data->readers++; + + myDir->entries.push_back(f); + + mtx->Unlock(); + return new MemoryFilesystemStream(mtx,f->data,canRead,canWrite,canSeek); + } + if(thefile != nullptr) + { + if(!thefile->data->canAccess) + { + mtx->Unlock(); + return nullptr; + } + if(thefile->data->readers > 0) + { + mtx->Unlock(); + return nullptr; + } + thefile->data->canAccess=false; + thefile->data->readers++; + if(truncate) {thefile->data->file.clear(); thefile->data->lastWrite=time(NULL);} + mtx->Unlock(); + return new MemoryFilesystemStream(mtx,thefile->data,canRead,canWrite,canSeek); + } + } + + mtx->Unlock(); + return nullptr; + } + + void MemoryFilesystem::CreateDirectory(VFSPath path) + { + if(path.relative) return; + if(path.path.empty()) return; + mtx->Lock(); + MemoryDirectory* dir=&root; + for(auto part : path.path) + { + bool have=false; + for(auto dirent : dir->entries) + { + if(dirent->name == part) + { + auto symlink = dynamic_cast(dirent); + if(symlink != nullptr) + { + dirent = GetEntry(symlink->linkedTo,true); + } + auto dirdirent = dynamic_cast(dirent); + if(dirdirent != nullptr) + { + dir = dirdirent; + have=true; + break; + } + else + { + mtx->Unlock(); + return; + } + } + } + if(!have) + { + MemoryDirectory* dir2 = new MemoryDirectory(); + dir2->name = part; + + dir2->lastWrite=time(NULL); + + dir->entries.push_back(dir2); + dir->lastWrite=time(NULL); + + dir=dir2; + } + } + mtx->Unlock(); + } + + void MemoryFilesystem::DeleteFile(VFSPath path) + { + if(path.relative || path.path.empty()) return; + mtx->Lock(); + MemoryDirectory* dir=&root; + if(path.path.size() > 1) + { + dir = dynamic_cast(GetEntry(path.GetParent(),true)); + } + if(dir == nullptr) + { + mtx->Unlock(); + return; + } + std::string fname = path.GetFileName(); + for(auto index = dir->entries.begin(); index < dir->entries.end(); index++) + { + auto item = *index; + if(item->name == fname) + { + auto p = dynamic_cast(item); + if(p == nullptr) + { + delete item; + dir->entries.erase(index); + + dir->lastWrite=time(NULL); + } + break; + } + } + mtx->Unlock(); + } + + bool MemoryFilesystem::RegularFileExists(VFSPath path) + { + + if(path.relative) return false; + if(path.path.empty()) return false; + mtx->Lock(); + auto f = GetEntry(path,false); + mtx->Unlock(); + return dynamic_cast(f) != nullptr; + } + bool MemoryFilesystem::SymlinkExists(VFSPath path) + { + + if(path.relative) return false; + if(path.path.empty()) return false; + mtx->Lock(); + auto f = GetEntry(path,false); + mtx->Unlock(); + return dynamic_cast(f) != nullptr; + } + bool MemoryFilesystem::DirectoryExists(VFSPath path) + { + if(path.relative) return false; + if(path.path.empty()) return true; + mtx->Lock(); + auto f = GetEntry(path,false); + mtx->Unlock(); + return dynamic_cast(f) != nullptr; + } + + void MemoryFilesystem::DeleteDirectory(VFSPath path) + { + if(path.relative || path.path.empty()) return; + mtx->Lock(); + MemoryDirectory* dir=&root; + if(path.path.size() > 1) + { + dir = dynamic_cast(GetEntry(path.GetParent(),true)); + } + if(dir == nullptr) + { + mtx->Unlock(); + return; + } + std::string fname = path.GetFileName(); + for(auto index = dir->entries.begin(); index < dir->entries.end(); index++) + { + auto item = *index; + if(item->name == fname) + { + auto p = dynamic_cast(item); + if(p != nullptr) + { + delete item; + dir->entries.erase(index); + dir->lastWrite=time(NULL); + } + break; + } + } + mtx->Unlock(); + } + + void MemoryFilesystem::CreateSymlink(VFSPath existingFile, VFSPath symlinkFile) + { + if(existingFile.relative || symlinkFile.relative || symlinkFile.path.empty()) return; + mtx->Lock(); + MemoryDirectory* dir=&root; + if(symlinkFile.path.size() > 1) + { + dir = dynamic_cast(GetEntry(symlinkFile.GetParent(),true)); + } + if(dir == nullptr) + { + mtx->Unlock(); + return; + } + std::string fname = symlinkFile.GetFileName(); + for(auto index = dir->entries.begin(); index < dir->entries.end(); index++) + { + auto item = *index; + if(item->name == fname) + { + auto p = dynamic_cast(item); + if(p != nullptr) + { + p->linkedTo = existingFile; + p->lastWrite = time(NULL); + } + mtx->Unlock(); + return; + } + } + MemorySymlink* symlink = new MemorySymlink(); + symlink->name = fname; + symlink->linkedTo = existingFile; + symlink->lastWrite = time(NULL); + dir->entries.push_back(symlink); + dir->lastWrite = time(NULL); + + mtx->Unlock(); + } + VFSPathEnumerator MemoryFilesystem::EnumeratePaths(VFSPath path) + { + std::pair>* paths=new std::pair>(); + paths->first=0; + mtx->Lock(); + auto dir = dynamic_cast(GetEntry(path,true)); + if(dir != nullptr) + { + for(auto item : dir->entries) paths->second.push_back(item->name); + } + mtx->Unlock(); + + return VFSPathEnumerator([paths,path](VFSPath& _path)->bool{ + if(paths->first < paths->second.size()) + { + _path = path / paths->second[paths->first++]; + return true; + } + return false; + },[paths]()->void{ + delete paths; + }); + } + + + void MemoryFilesystem::CreateHardlink(VFSPath existingFile, VFSPath newName) + { + mtx->Lock(); + auto existing = dynamic_cast(GetEntry(existingFile,true)); + if(existing == nullptr) + { + mtx->Unlock(); + return; + } + MemoryDirectory* dir=&root; + if(newName.path.size() > 1) + { + dir = dynamic_cast(GetEntry(newName.GetParent(),true)); + } + if(dir == nullptr) + { + mtx->Unlock(); + return; + } + + std::string fname = newName.GetFileName(); + for(auto index = dir->entries.begin(); index < dir->entries.end(); index++) + { + auto item = *index; + if(item->name == fname) + { + + mtx->Unlock(); + return; + } + } + + MemoryFile* memFile = new MemoryFile(); + memFile->name = fname; + memFile->data = existing->data; + dir->entries.push_back(memFile); + dir->lastWrite=time(NULL); + + mtx->Unlock(); + } + void MemoryFilesystem::MoveFile(VFSPath src, VFSPath dest) + { + DeleteFile(dest); + CreateHardlink(src,dest); + DeleteFile(src); + } + void MemoryFilesystem::MoveDirectory(VFSPath src, VFSPath dest) + { + CreateDirectory(dest); + for(auto ent : EnumeratePaths(src)) + { + VFSPath destPath = dest / ent.GetFileName(); + if(FileExists(ent)) MoveFile(ent,destPath); + if(DirectoryExists(ent)) MoveDirectory(ent,destPath); + + } + DeleteDirectory(src); + } + + VFSPath MemoryFilesystem::ReadLink(VFSPath p) + { + mtx->Lock(); + VFSPath p2; + auto symlink = dynamic_cast(GetEntry(p,false)); + if(symlink != nullptr) + { + p2 = symlink->linkedTo; + } + mtx->Unlock(); + return p2; + } + std::string MemoryFilesystem::VFSPathToSystem(VFSPath path) + { + return path.ToString(); + } + VFSPath MemoryFilesystem::SystemToVFSPath(std::string path) + { + return path; + } + void MemoryFilesystem::GetDate(VFSPath path, time_t& lastWrite, time_t& lastAccess) + { + + mtx->Lock(); + auto node = GetEntry(path,false); + auto dir = dynamic_cast(node); + + auto file = dynamic_cast(node); + + auto sym = dynamic_cast(node); + + if(dir != nullptr) lastWrite = dir->lastWrite; + if(file != nullptr) lastWrite = file->data->lastWrite; + if(sym != nullptr) lastWrite = sym->lastWrite; + mtx->Unlock(); + lastAccess = lastWrite; + } + void MemoryFilesystem::SetDate(VFSPath path, time_t lastWrite, time_t lastAccess) + { + mtx->Lock(); + auto node = GetEntry(path,false); + auto dir = dynamic_cast(node); + + auto file = dynamic_cast(node); + + auto sym = dynamic_cast(node); + + if(dir != nullptr) dir->lastWrite = lastWrite; + if(file != nullptr) file->data->lastWrite = lastWrite; + if(sym != nullptr) sym->lastWrite = lastWrite; + mtx->Unlock(); + } + MemoryFilesystem::~MemoryFilesystem() + { + + } + MemoryFilesystem::MemoryFilesystem() + { + mtx = std::make_shared(); + } + + MemoryEntry::~MemoryEntry() + { + + } + MemoryFile::~MemoryFile() + { + + } + MemoryDirectory::MemoryDirectory() + { + this->lastWrite = time(NULL); + } + MemoryDirectory::~MemoryDirectory() + { + for(auto item : this->entries) delete item; + } + MemoryFileData::MemoryFileData() + { + this->lastWrite = time(NULL); + this->canAccess=true; + this->readers=0; + + } +} diff --git a/src/Filesystem/VFS.cpp b/src/Filesystem/VFS.cpp index dff7c26..5a5cf96 100644 --- a/src/Filesystem/VFS.cpp +++ b/src/Filesystem/VFS.cpp @@ -266,7 +266,9 @@ namespace Tesses::Framework::Filesystem std::vector paths; if(this->path.empty()) return VFSPath(); paths.insert(paths.begin(), this->path.begin(), this->path.end()-1); - return VFSPath(paths); + auto res= VFSPath(paths); + res.relative = this->relative; + return res; } std::string VFSPath::GetFileName() diff --git a/src/Http/HttpServer.cpp b/src/Http/HttpServer.cpp index 0bb4c37..a2d2e0b 100644 --- a/src/Http/HttpServer.cpp +++ b/src/Http/HttpServer.cpp @@ -85,6 +85,16 @@ namespace Tesses::Framework::Http data->currentHeaders.Clear(); return 0; }*/ + std::string ServerContext::GetUrlWithQuery() + { + if(this->queryParams.kvp.empty()) return this->path; + return this->path + "?" + HttpUtils::QueryParamsEncode(this->queryParams); + } + std::string ServerContext::GetOriginalPathWithQuery() + { + if(this->queryParams.kvp.empty()) return this->originalPath; + return this->originalPath + "?" + HttpUtils::QueryParamsEncode(this->queryParams); + } bool ServerContext::NeedToParseFormData() { std::string ct; diff --git a/src/Http/HttpUtils.cpp b/src/Http/HttpUtils.cpp index 6148388..8874d67 100644 --- a/src/Http/HttpUtils.cpp +++ b/src/Http/HttpUtils.cpp @@ -381,7 +381,7 @@ namespace Tesses::Framework::Http { s.push_back(item); else if(item >= '0' && item <= '9') s.push_back(item); - else if(item == '-' || item == '_' || item == '.' || item == '~') + else if(item == '-' || item == '_' || item == '.' || item == '~' || item == '/') s.push_back(item); else { diff --git a/src/Streams/FileStream.cpp b/src/Streams/FileStream.cpp index 6472a8d..e24a381 100644 --- a/src/Streams/FileStream.cpp +++ b/src/Streams/FileStream.cpp @@ -57,16 +57,21 @@ namespace Tesses::Framework::Streams } bool FileStream::CanRead() { - return this->canRead; + return this->canRead && this->f; } bool FileStream::CanWrite() { - return this->canWrite; + return this->canWrite && this->f; } bool FileStream::CanSeek() { - return this->canSeek; + return this->canSeek && this->f; } + bool FileStream::EndOfStream() + { + return feof(this->f); + } + int64_t FileStream::GetPosition() { #if defined(_WIN32) diff --git a/src/Streams/MemoryStream.cpp b/src/Streams/MemoryStream.cpp index de613ac..2134983 100644 --- a/src/Streams/MemoryStream.cpp +++ b/src/Streams/MemoryStream.cpp @@ -15,7 +15,7 @@ namespace Tesses::Framework::Streams { if(this->offset >= this->buffer.size()) return 0; size_t toRead = std::min(sz, this->buffer.size()-this->offset); - memcpy(buff, this->buffer.data() + this->offset, sz); + memcpy(buff, this->buffer.data() + this->offset, toRead); this->offset += toRead; return toRead; } diff --git a/src/Streams/NetworkStream.cpp b/src/Streams/NetworkStream.cpp index f7eb672..b1a0a94 100644 --- a/src/Streams/NetworkStream.cpp +++ b/src/Streams/NetworkStream.cpp @@ -232,6 +232,13 @@ namespace Tesses::Framework::Streams { memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = htons(port); + int on=1; + #if defined(SO_REUSEPORT) + NETWORK_SETSOCKOPT(this->sock,SOL_SOCKET,SO_REUSEPORT,(const char*)&on, (socklen_t)sizeof(on)); + #endif + #if defined(SO_REUSEADDR) + NETWORK_SETSOCKOPT(this->sock,SOL_SOCKET,SO_REUSEADDR,(const char*)&on, (socklen_t)sizeof(on)); + #endif if(NETWORK_BIND(this->sock, (const sockaddr*)&addr, (socklen_t)sizeof(addr)) != 0) { this->valid = false; @@ -432,7 +439,13 @@ namespace Tesses::Framework::Streams { } SetPort((struct sockaddr*)&addr, port); - + int on=1; + #if defined(SO_REUSEPORT) + NETWORK_SETSOCKOPT(this->sock,SOL_SOCKET,SO_REUSEPORT,(const char*)&on, (socklen_t)sizeof(on)); + #endif + #if defined(SO_REUSEADDR) + NETWORK_SETSOCKOPT(this->sock,SOL_SOCKET,SO_REUSEADDR,(const char*)&on, (socklen_t)sizeof(on)); + #endif int r = NETWORK_BIND(this->sock, (struct sockaddr*)&addr, sizeof(addr)); if(r != 0) { diff --git a/src/Streams/Stream.cpp b/src/Streams/Stream.cpp index 922cd4c..3becabc 100644 --- a/src/Streams/Stream.cpp +++ b/src/Streams/Stream.cpp @@ -95,7 +95,7 @@ namespace Tesses::Framework::Streams { void Stream::CopyTo(Stream* strm, size_t buffSize) { if(strm != nullptr) - strm->CopyTo(*strm, buffSize); + this->CopyTo(*strm, buffSize); } void Stream::CopyTo(Stream& strm, size_t buffSize) { diff --git a/src/Threading/ThreadPool.cpp b/src/Threading/ThreadPool.cpp new file mode 100644 index 0000000..4d59453 --- /dev/null +++ b/src/Threading/ThreadPool.cpp @@ -0,0 +1,69 @@ +#include "TessesFramework/Threading/ThreadPool.hpp" +#if !defined(GEKKO) +#include +#endif +namespace Tesses::Framework::Threading +{ + size_t ThreadPool::GetNumberOfCores() + { + #if defined(GEKKO) + return 1; + #else + return (size_t)std::thread::hardware_concurrency(); + #endif + } + ThreadPool::ThreadPool(size_t threads) + { + this->isRunning=true; + for(size_t i = 0; i < threads; i++) + { + this->threads.push_back(new Thread([this]()->void{ + while(true) + { + this->mtx.Lock(); + + if(!this->isRunning) + { + this->mtx.Unlock(); + return; + } + + std::function fn=nullptr; + + if(this->callbacks.empty()) + { + fn=this->callbacks.front(); + this->callbacks.pop(); + } + this->mtx.Unlock(); + if(fn) + fn(); + } + })); + } + } + void ThreadPool::Schedule(std::function cb) + { + this->mtx.Lock(); + this->callbacks.push(cb); + this->mtx.Unlock(); + } + ThreadPool::~ThreadPool() + { + while(true) + { + this->mtx.Lock(); + auto emp=this->callbacks.empty(); + if(emp) this->isRunning=false; + this->mtx.Unlock(); + if(emp) break; + } + + for(auto item : this->threads) + { + item->Join(); + delete item; + } + + } +} \ No newline at end of file diff --git a/src/wrapper.cpp b/src/wrapper.cpp new file mode 100644 index 0000000..4dec880 --- /dev/null +++ b/src/wrapper.cpp @@ -0,0 +1,231 @@ + +#include "TessesFramework/TessesFramework.hpp" + +#include "TessesFramework/TessesFramework.h" +#include + +using namespace Tesses::Framework; +using namespace Tesses::Framework::Streams; +using namespace Tesses::Framework::Filesystem; +using namespace Tesses::Framework::Threading; + + +#if defined(__cplusplus) +extern "C" { +#endif + + + +string_t* string_create() +{ + return static_cast(new std::string()); +} +string_t* string_create_from_buff(const void* text, size_t len) +{ + return static_cast(new std::string((const char*)text,len)); +} +string_t* string_create_from_charpointer(const char* text) +{ + return static_cast(new std::string(text)); +} +string_t* string_resize(string_t* str, size_t len) +{ + static_cast(str)->resize(len); + return str; +} +string_t* string_set_char(string_t* str, size_t index, char c) +{ + static_cast(str)->at(index) = c; + return str; +} +char string_get_char(string_t* str,size_t index) +{ + return static_cast(str)->at(index); +} +string_t* string_append_char(string_t* str, char c) +{ + static_cast(str)->push_back(c); + return str; +} +string_t* string_append_from_buff(string_t* str,const void* text, size_t len) +{ + static_cast(str)->append((const char*)text,len); + return str; +} +string_t* string_append_from_charpointer(string_t* str,const char* text) +{ + static_cast(str)->append(text); + return str; +} +string_t* string_append(string_t* str, string_t* toAppend) +{ + if(str == NULL) return NULL; + static_cast(str)->append(*static_cast(str)); + return str; +} +string_t* string_append_signed(string_t* str, int64_t num) +{ + static_cast(str)->append(std::to_string(num)); + return str; +} +string_t* string_append_unsigned(string_t* str, uint64_t num) +{ + static_cast(str)->append(std::to_string(num)); + return str; +} +string_t* string_append_double(string_t* str, double num) +{ + static_cast(str)->append(std::to_string(num)); + return str; +} +void string_print(string_t* str) +{ + std::cout << *static_cast(str); +} +void string_println(string_t* str) +{ + std::cout << *static_cast(str) << std::endl; +} +size_t string_size(string_t* str) +{ + return static_cast(str)->size(); +} +const char* string_c_str(string_t* str) +{ + return static_cast(str)->c_str(); +} +void string_free(string_t* str) +{ + delete static_cast(str); +} + +void tf_init() +{ + TF_Init(); +} +tf_thread_t* tf_create_thread(void* userData, tf_action_user_data_t cb) +{ + Thread* thrd = new Thread([userData,cb]()->void{ + cb(userData); + }); + return static_cast(thrd); +} +void tf_join_thread(tf_thread_t* thrd) +{ + auto thrd2 = static_cast(thrd); + if(thrd2 != nullptr) + { + thrd2->Join(); + delete thrd2; + } +} +void tf_detach_thread(tf_thread_t* thrd) +{ + auto thrd2 = static_cast(thrd); + if(thrd2 != nullptr) + { + thrd2->Detach(); + delete thrd2; + } +} + +tf_mutex_t* tf_mutex_create() +{ + return static_cast(new Mutex()); +} +void tf_mutex_lock(tf_mutex_t* mtx) +{ + static_cast(mtx)->Lock(); + +} +bool tf_mutex_trylock(tf_mutex_t* mtx) +{ + return static_cast(mtx)->TryLock(); + +} +void tf_mutex_unlock(tf_mutex_t* mtx) +{ + static_cast(mtx)->Unlock(); + +} +void tf_mutex_free(tf_mutex_t* mtx) +{ + delete static_cast(mtx); + +} + +bool tf_stream_canread(tf_stream_t* strm) +{ + return static_cast(strm)->CanRead(); +} +bool tf_stream_canwrite(tf_stream_t* strm) +{ + return static_cast(strm)->CanWrite(); +} +bool tf_stream_canseek(tf_stream_t* strm) +{ + return static_cast(strm)->CanSeek(); +} +bool tf_stream_eof(tf_stream_t* strm) +{ + return static_cast(strm)->EndOfStream(); +} +int64_t tf_stream_getlen(tf_stream_t* strm) +{ + return static_cast(strm)->GetLength(); +} +int64_t tf_stream_getpos(tf_stream_t* strm) +{ + return static_cast(strm)->GetPosition(); +} +void tf_stream_seek(tf_stream_t* strm, int64_t pos, TF_WHENCE whence) +{ + static_cast(strm)->Seek(pos,whence == TF_SEEK_BEGIN ? SeekOrigin::Begin : whence == TF_SEEK_CURRENT ? SeekOrigin::Current : SeekOrigin::End); +} +size_t tf_stream_read(tf_stream_t* strm, uint8_t* buffer, size_t length) +{ + return static_cast(strm)->Read(buffer,length); +} +size_t tf_stream_write(tf_stream_t* strm, const uint8_t* buffer, size_t length) +{ + return static_cast(strm)->Write(buffer,length); +} +size_t tf_stream_readblock(tf_stream_t* strm, uint8_t* buffer, size_t length) +{ + return static_cast(strm)->ReadBlock(buffer,length); +} +void tf_stream_writeblock(tf_stream_t* strm, const uint8_t* buffer, size_t length) +{ + static_cast(strm)->WriteBlock(buffer,length); +} +void tf_stream_copyto(tf_stream_t* src, tf_stream_t* dest, size_t blockSize) +{ + static_cast(src)->CopyTo(static_cast(dest),blockSize); +} +void tf_stream_close(tf_stream_t* strm) +{ + delete static_cast(strm); +} +void tf_stream_flush(tf_stream_t* strm) +{ + static_cast(strm)->Flush(); +} +int32_t tf_stream_readbyte(tf_stream_t* strm) +{ + return static_cast(strm)->ReadByte(); +} +void tf_stream_writebyte(tf_stream_t* strm, uint8_t val) +{ + static_cast(strm)->WriteByte(val); +} + +tf_stream_t* tf_stream_fopen(const char* file, const char* mode) +{ + FILE* f = fopen(file,mode); + if(f == NULL) return NULL; + return static_cast(new FileStream(f,true,std::string(mode))); +} + +#if defined(__cplusplus) +} +#endif