Added memoryfilesystem and working on c wrapper

This commit is contained in:
2025-01-03 05:50:44 -06:00
parent 8e4ec4ee3e
commit 7e6f0f1fca
17 changed files with 1229 additions and 8 deletions

View File

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

21
examples/wrappertest.c Normal file
View File

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

View File

@ -0,0 +1,99 @@
#pragma once
#include "VFS.hpp"
#include "VFSFix.hpp"
#include "../Threading/Mutex.hpp"
#include <atomic>
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<uint8_t> file;
};
class MemoryFile : public MemoryEntry
{
public:
std::shared_ptr<MemoryFileData> data;
~MemoryFile();
};
class MemoryDirectory : public MemoryEntry
{
public:
MemoryDirectory();
time_t lastWrite;
std::vector<MemoryEntry*> entries;
~MemoryDirectory();
};
class MemorySymlink : public MemoryEntry
{
public:
time_t lastWrite;
VFSPath linkedTo;
};
class MemoryFilesystemStream : public Streams::Stream
{
public:
std::shared_ptr<Tesses::Framework::Threading::Mutex> mtx;
std::shared_ptr<MemoryFileData> data;
bool canRead;
bool canWrite;
bool canSeek;
int64_t pos;
MemoryFilesystemStream(std::shared_ptr<Tesses::Framework::Threading::Mutex> mtx, std::shared_ptr<MemoryFileData> 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<Tesses::Framework::Threading::Mutex> 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();
};
};

View File

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

View File

@ -0,0 +1,77 @@
#pragma once
#if defined(__cplusplus)
extern "C" {
#endif
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
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

View File

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

View File

@ -0,0 +1,23 @@
#pragma once
#include <functional>
#include "Thread.hpp"
#include "Mutex.hpp"
#include <vector>
#include <queue>
namespace Tesses::Framework::Threading
{
class ThreadPool
{
std::vector<Thread*> threads;
std::queue<std::function<void()>> callbacks;
Mutex mtx;
volatile bool isRunning;
public:
static size_t GetNumberOfCores();
ThreadPool(size_t threads);
void Schedule(std::function<void()> cb);
~ThreadPool();
};
}

View File

@ -0,0 +1,666 @@
#include "TessesFramework/Filesystem/MemoryFilesystem.hpp"
#include <iostream>
namespace Tesses::Framework::Filesystem
{
MemoryFilesystemStream::MemoryFilesystemStream(std::shared_ptr<Tesses::Framework::Threading::Mutex> mtx, std::shared_ptr<MemoryFileData> 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<MemoryDirectory*>(entry);
if(dir != nullptr)
{
for(auto item : dir->entries)
{
if(item->name == path.GetFileName())
{
auto link = dynamic_cast<MemorySymlink*>(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<MemoryFile*>(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<MemoryFile*>(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<MemoryDirectory*>(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<MemorySymlink*>(f);
while(symlink != nullptr)
{
auto ent = GetEntry(symlink->name,false);
auto sym = dynamic_cast<MemorySymlink*>(f);
if(sym != nullptr)
symlink = sym;
else
{
auto myDir0 = dynamic_cast<MemoryDirectory*>(GetEntry(symlink->linkedTo.GetParent(),true));
if(myDir0 != nullptr)
{
for(auto f2 : myDir0->entries)
{
if(f2->name == symlink->linkedTo.GetFileName())
{
auto myFile = dynamic_cast<MemoryFile*>(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<MemoryFileData>();
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<MemorySymlink*>(dirent);
if(symlink != nullptr)
{
dirent = GetEntry(symlink->linkedTo,true);
}
auto dirdirent = dynamic_cast<MemoryDirectory*>(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<MemoryDirectory*>(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<MemoryDirectory*>(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<MemoryFile*>(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<MemorySymlink*>(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<MemoryDirectory*>(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<MemoryDirectory*>(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<MemoryDirectory*>(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<MemoryDirectory*>(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<MemorySymlink*>(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<size_t,std::vector<std::string>>* paths=new std::pair<size_t,std::vector<std::string>>();
paths->first=0;
mtx->Lock();
auto dir = dynamic_cast<MemoryDirectory*>(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<MemoryFile*>(GetEntry(existingFile,true));
if(existing == nullptr)
{
mtx->Unlock();
return;
}
MemoryDirectory* dir=&root;
if(newName.path.size() > 1)
{
dir = dynamic_cast<MemoryDirectory*>(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<MemorySymlink*>(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<MemoryDirectory*>(node);
auto file = dynamic_cast<MemoryFile*>(node);
auto sym = dynamic_cast<MemorySymlink*>(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<MemoryDirectory*>(node);
auto file = dynamic_cast<MemoryFile*>(node);
auto sym = dynamic_cast<MemorySymlink*>(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<Threading::Mutex>();
}
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;
}
}

View File

@ -266,7 +266,9 @@ namespace Tesses::Framework::Filesystem
std::vector<std::string> 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()

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,69 @@
#include "TessesFramework/Threading/ThreadPool.hpp"
#if !defined(GEKKO)
#include <thread>
#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<void()> fn=nullptr;
if(this->callbacks.empty())
{
fn=this->callbacks.front();
this->callbacks.pop();
}
this->mtx.Unlock();
if(fn)
fn();
}
}));
}
}
void ThreadPool::Schedule(std::function<void()> 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;
}
}
}

231
src/wrapper.cpp Normal file
View File

@ -0,0 +1,231 @@
#include "TessesFramework/TessesFramework.hpp"
#include "TessesFramework/TessesFramework.h"
#include <iostream>
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<string_t*>(new std::string());
}
string_t* string_create_from_buff(const void* text, size_t len)
{
return static_cast<string_t*>(new std::string((const char*)text,len));
}
string_t* string_create_from_charpointer(const char* text)
{
return static_cast<string_t*>(new std::string(text));
}
string_t* string_resize(string_t* str, size_t len)
{
static_cast<std::string*>(str)->resize(len);
return str;
}
string_t* string_set_char(string_t* str, size_t index, char c)
{
static_cast<std::string*>(str)->at(index) = c;
return str;
}
char string_get_char(string_t* str,size_t index)
{
return static_cast<std::string*>(str)->at(index);
}
string_t* string_append_char(string_t* str, char c)
{
static_cast<std::string*>(str)->push_back(c);
return str;
}
string_t* string_append_from_buff(string_t* str,const void* text, size_t len)
{
static_cast<std::string*>(str)->append((const char*)text,len);
return str;
}
string_t* string_append_from_charpointer(string_t* str,const char* text)
{
static_cast<std::string*>(str)->append(text);
return str;
}
string_t* string_append(string_t* str, string_t* toAppend)
{
if(str == NULL) return NULL;
static_cast<std::string*>(str)->append(*static_cast<std::string*>(str));
return str;
}
string_t* string_append_signed(string_t* str, int64_t num)
{
static_cast<std::string*>(str)->append(std::to_string(num));
return str;
}
string_t* string_append_unsigned(string_t* str, uint64_t num)
{
static_cast<std::string*>(str)->append(std::to_string(num));
return str;
}
string_t* string_append_double(string_t* str, double num)
{
static_cast<std::string*>(str)->append(std::to_string(num));
return str;
}
void string_print(string_t* str)
{
std::cout << *static_cast<std::string*>(str);
}
void string_println(string_t* str)
{
std::cout << *static_cast<std::string*>(str) << std::endl;
}
size_t string_size(string_t* str)
{
return static_cast<std::string*>(str)->size();
}
const char* string_c_str(string_t* str)
{
return static_cast<std::string*>(str)->c_str();
}
void string_free(string_t* str)
{
delete static_cast<std::string*>(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<tf_thread_t*>(thrd);
}
void tf_join_thread(tf_thread_t* thrd)
{
auto thrd2 = static_cast<Thread*>(thrd);
if(thrd2 != nullptr)
{
thrd2->Join();
delete thrd2;
}
}
void tf_detach_thread(tf_thread_t* thrd)
{
auto thrd2 = static_cast<Thread*>(thrd);
if(thrd2 != nullptr)
{
thrd2->Detach();
delete thrd2;
}
}
tf_mutex_t* tf_mutex_create()
{
return static_cast<tf_mutex_t*>(new Mutex());
}
void tf_mutex_lock(tf_mutex_t* mtx)
{
static_cast<Mutex*>(mtx)->Lock();
}
bool tf_mutex_trylock(tf_mutex_t* mtx)
{
return static_cast<Mutex*>(mtx)->TryLock();
}
void tf_mutex_unlock(tf_mutex_t* mtx)
{
static_cast<Mutex*>(mtx)->Unlock();
}
void tf_mutex_free(tf_mutex_t* mtx)
{
delete static_cast<Mutex*>(mtx);
}
bool tf_stream_canread(tf_stream_t* strm)
{
return static_cast<Stream*>(strm)->CanRead();
}
bool tf_stream_canwrite(tf_stream_t* strm)
{
return static_cast<Stream*>(strm)->CanWrite();
}
bool tf_stream_canseek(tf_stream_t* strm)
{
return static_cast<Stream*>(strm)->CanSeek();
}
bool tf_stream_eof(tf_stream_t* strm)
{
return static_cast<Stream*>(strm)->EndOfStream();
}
int64_t tf_stream_getlen(tf_stream_t* strm)
{
return static_cast<Stream*>(strm)->GetLength();
}
int64_t tf_stream_getpos(tf_stream_t* strm)
{
return static_cast<Stream*>(strm)->GetPosition();
}
void tf_stream_seek(tf_stream_t* strm, int64_t pos, TF_WHENCE whence)
{
static_cast<Stream*>(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<Stream*>(strm)->Read(buffer,length);
}
size_t tf_stream_write(tf_stream_t* strm, const uint8_t* buffer, size_t length)
{
return static_cast<Stream*>(strm)->Write(buffer,length);
}
size_t tf_stream_readblock(tf_stream_t* strm, uint8_t* buffer, size_t length)
{
return static_cast<Stream*>(strm)->ReadBlock(buffer,length);
}
void tf_stream_writeblock(tf_stream_t* strm, const uint8_t* buffer, size_t length)
{
static_cast<Stream*>(strm)->WriteBlock(buffer,length);
}
void tf_stream_copyto(tf_stream_t* src, tf_stream_t* dest, size_t blockSize)
{
static_cast<Stream*>(src)->CopyTo(static_cast<Stream*>(dest),blockSize);
}
void tf_stream_close(tf_stream_t* strm)
{
delete static_cast<Stream*>(strm);
}
void tf_stream_flush(tf_stream_t* strm)
{
static_cast<Stream*>(strm)->Flush();
}
int32_t tf_stream_readbyte(tf_stream_t* strm)
{
return static_cast<Stream*>(strm)->ReadByte();
}
void tf_stream_writebyte(tf_stream_t* strm, uint8_t val)
{
static_cast<Stream*>(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<tf_stream_t*>(new FileStream(f,true,std::string(mode)));
}
#if defined(__cplusplus)
}
#endif