13 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
38bb29ecc0 Change html to dark mode by default and stat in vfs 2026-04-19 23:39:15 -05:00
c5cf13e1b7 Change html to dark mode by default and stat in vfs 2026-04-19 23:07:17 -05:00
5435280209 Fix gitea
Some checks failed
Build and Deploy on Tag / build-jammy (push) Has been cancelled
Build and Deploy on Tag / build-plucky (push) Has been cancelled
Build and Deploy on Tag / build-arch (push) Has been cancelled
2026-02-26 01:56:19 -06:00
65d87a1759 Fix bitconverter code 2026-02-16 17:41:16 -06:00
3889c746fe Add signed to bitconverter and float 2026-02-15 15:29:28 -06:00
9dae77a0b9 Revamp uuid code 2026-02-15 14:55:01 -06:00
61275c0f5f Add Uuids 2026-02-15 13:28:06 -06:00
66 changed files with 2556 additions and 2211 deletions

View File

@@ -2,18 +2,18 @@ name: Build and Deploy on Tag
on:
push:
tags:
- 'v*'
- "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:
- run: pacman --noconfirm -Sy nodejs npm
- 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
@@ -21,24 +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
build-jammy:
runs-on: deb-builder-jammy
steps:
- uses: actions/checkout@v4
- name: Build for jammy, noble
run: |
bash build-ubuntu-jammy.sh
bash push-ubuntu-jammy.sh
working-directory: ./Packaging/Linux
build-plucky:
runs-on: deb-builder-plucky
steps:
- uses: actions/checkout@v4
- name: Build for plucky, resolute
run: |
bash build-ubuntu-plucky.sh
bash push-ubuntu-plucky.sh
working-directory: ./Packaging/Linux
- 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

@@ -1,52 +0,0 @@
version: 43
jobs:
- name: Build for x86_64
steps:
- type: CheckoutStep
name: Checkout
cloneCredential:
type: DefaultCredential
withLfs: true
withSubmodules: false
condition: SUCCESSFUL
optional: false
- type: CommandStep
name: Execute build
runInContainer: true
image: onedev.site.tesses.net/dependencies/dependencies:latest
interpreter:
type: DefaultInterpreter
commands: |
mkdir build
cd build
cmake -S .. -B . -DTESSESFRAMEWORK_FETCHCONTENT=OFF
make -j12
make install DESTDIR=out
useTTY: true
condition: SUCCESSFUL
optional: false
- type: BuildImageStep
name: Build Docker Image
dockerfile: Dockerfile.run
output:
type: RegistryOutput
tags: onedev.site.tesses.net/tesses-framework/tesses-framework:latest onedev.site.tesses.net/tesses-framework/tesses-framework:@commit_hash@ git.tesseslanguage.com/tesses50/tesses-framework:latest git.tesseslanguage.com/tesses50/tesses-framework:@commit_hash@
registryLogins:
- registryUrl: '@server_url@'
userName: '@job_token@'
passwordSecret: dockersecret
- registryUrl: git.tesseslanguage.com
userName: tesses50
passwordSecret: GITEA_AUTH
platforms: linux/amd64
condition: SUCCESSFUL
optional: false
triggers:
- type: BranchUpdateTrigger
branches: master
userMatch: anyone
projects: tesses-framework
retryCondition: never
maxRetries: 3
retryDelay: 30
timeout: 14400

View File

@@ -2,72 +2,12 @@ cmake_minimum_required(VERSION 3.16)
set(TESSESFRAMEWORK_MAJOR_VERSION 0)
set(TESSESFRAMEWORK_MINOR_VERSION 0)
set(TESSESFRAMEWORK_PATCH_VERSION 1)
set(TESSESFRAMEWORK_PATCH_VERSION 2)
project(TessesFramework VERSION ${TESSESFRAMEWORK_MAJOR_VERSION}.${TESSESFRAMEWORK_MINOR_VERSION}.${TESSESFRAMEWORK_PATCH_VERSION})
set(CMAKE_CXX_STANDARD 17)
list(APPEND TESSESFRAMEWORK_SOURCE
src/Random.cpp
src/Date/Date.cpp
src/Http/FileServer.cpp
src/Http/MountableServer.cpp
src/Http/RouteServer.cpp
src/Http/CallbackServer.cpp
src/Http/HttpServer.cpp
src/Http/HttpUtils.cpp
src/Http/HttpClient.cpp
src/Http/HttpStream.cpp
src/Http/ContentDisposition.cpp
src/Http/WebSocket.cpp
src/Http/ChangeableServer.cpp
src/Http/BasicAuthServer.cpp
src/Http/CGIServer.cpp
src/Mail/Smtp.cpp
src/Serialization/Json.cpp
src/Serialization/SQLite.cpp
src/Serialization/BitConverter.cpp
src/Serialization/Bencode.cpp
src/Platform/Environment.cpp
src/Platform/Process.cpp
src/Streams/FileStream.cpp
src/Streams/MemoryStream.cpp
src/Streams/NetworkStream.cpp
src/Streams/Stream.cpp
src/Streams/BufferedStream.cpp
src/Streams/ByteReader.cpp
src/Streams/ByteWriter.cpp
src/Streams/PtyStream.cpp
src/Text/StringConverter.cpp
src/Text/HeaderGenerator.cpp
src/TextStreams/StreamReader.cpp
src/TextStreams/StreamWriter.cpp
src/TextStreams/TextReader.cpp
src/TextStreams/TextWriter.cpp
src/TextStreams/StdIOReader.cpp
src/TextStreams/StdIOWriter.cpp
src/TextStreams/StringReader.cpp
src/TextStreams/StringWriter.cpp
src/Threading/Thread.cpp
src/Threading/Mutex.cpp
src/Threading/ThreadPool.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/Filesystem/FSHelpers.cpp
src/Filesystem/TempFS.cpp
src/Crypto/MbedTLS/ClientTLSStream.cpp
src/Crypto/MbedTLS/Crypto.cpp
src/Args.cpp
src/TF_Init.cpp
src/HiddenField.cpp
src/BitTorrent/TorrentFile.cpp
src/BitTorrent/TorrentStream.cpp
)
include(cmake/sources.cmake)
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
@@ -149,7 +89,7 @@ FetchContent_Declare(
FetchContent_MakeAvailable(mbedtls)
else()
set(MBEDTLS_DIR "" CACHE PATH "Mbed tls directory")
find_package(MbedTLS REQUIRED)
endif()
endif()
@@ -197,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()
@@ -328,6 +263,8 @@ DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/TessesFramework)
endif()
if(TESSESFRAMEWORK_ENABLE_EXAMPLES)
add_executable(timer examples/timer.cpp)
target_link_libraries(timer PUBLIC tessesframework)
add_executable(copyfile examples/copyfile.cpp)
target_link_libraries(copyfile PUBLIC tessesframework)
@@ -350,8 +287,6 @@ if(TESSESFRAMEWORK_ENABLE_EXAMPLES)
add_executable(wsecho examples/wsecho.cpp)
target_link_libraries(wsecho PUBLIC tessesframework)
add_executable(runevent examples/runevent.cpp)
target_link_libraries(runevent PUBLIC tessesframework)
add_executable(tests examples/tests.cpp)
target_link_libraries(tests PUBLIC tessesframework)
@@ -418,6 +353,11 @@ add_executable(twatch apps/twatch.cpp)
target_link_libraries(twatch PUBLIC tessesframework)
install(TARGETS twatch DESTINATION "${CMAKE_INSTALL_BINDIR}")
add_executable(tuuid apps/tuuid.cpp)
target_link_libraries(tuuid PUBLIC tessesframework)
install(TARGETS tuuid DESTINATION "${CMAKE_INSTALL_BINDIR}")
endif()
include(InstallRequiredSystemLibraries)
@@ -428,4 +368,6 @@ set(CPACK_PACKAGE_VERSION_MINOR "${TessesFramework_VERSION_MINOR}")
set(CPACK_DEBIAN_PACKAGE_DEPENDS "libmbedtls-dev (>= 2.28.8)")
include(CPack)
if(TESSESFRAMEWORK_INSTALL_DEVELOPMENT)
add_subdirectory(pkgconfig)
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

@@ -11,22 +11,11 @@ find_package(Threads REQUIRED)
endif()
endif()
set(TESSESFRAMEWORK_ENABLE_LIBWEBCAM @TESSESFRAMEWORK_ENABLE_LIBWEBCAM@)
if(${TESSESFRAMEWORK_ENABLE_LIBWEBCAM})
find_package(libwebcam)
endif()
set(TESSESFRAMEWORK_ENABLE_SQLITE @TESSESFRAMEWORK_ENABLE_SQLITE@)
set(TESSESFRAMEWORK_ENABLE_PLATFORMFOLDERS @TESSESFRAMEWORK_ENABLE_PLATFORMFOLDERS@)
set(TESSESFRAMEWORK_ENABLE_SDL2 @TESSESFRAMEWORK_ENABLE_SDL2@)
if(${TESSESFRAMEWORK_ENABLE_SDL2})
find_package(SDL2 REQUIRED)
find_package(SDL2_ttf REQUIRED)
find_package(SDL2_image REQUIRED)
endif()
set(TESSESFRAMEWORK_ENABLE_NETWORKING @TESSESFRAMEWORK_ENABLE_NETWORKING@)
set(TESSESFRAMEWORK_ENABLE_THREADING @TESSESFRAMEWORK_ENABLE_THREADING@)
set(TESSESFRAMEWORK_ENABLE_PROCESS @TESSESFRAMEWORK_ENABLE_PROCESS@)
set(TESSESFRAMEWORK_ENABLE_RPATH @TESSESFRAMEWORK_ENABLE_RPATH@)

View File

@@ -1,5 +0,0 @@
FROM ubuntu:noble
RUN apt update && apt install -y cmake g++ gcc libmbedtls-dev build-essential git ca-certificates
RUN mkdir /src && cd /src && git clone https://onedev.site.tesses.net/tesses-framework . && mkdir build && cd build && cmake -S .. -B . && make -j12 && make install && cd / && rm -r /src

View File

@@ -1,3 +0,0 @@
FROM onedev.site.tesses.net/dependencies/dependencies:latest
COPY build/out /

View File

@@ -1,16 +1,16 @@
# Maintainer: Mike Nolan <tesses@tesses.net>
pkgname=tesses-framework # '-bzr', '-git', '-hg' or '-svn'
pkgver=0.0.1
pkgname=tessesframework # '-bzr', '-git', '-hg' or '-svn'
pkgver=0.0.3
pkgrel=1
pkgdesc=""
arch=('x86_64' 'powerpc')
url="https://onedev.site.tesses.net/tesses-framework"
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=('tesses-framework::git+https://onedev.site.tesses.net/tesses-framework')
source=('tessesframework::git+https://git.tesses.org/tesses50/tessesframework')
noextract=()
sha256sums=('SKIP')
if [[ -z "$CMAKE_TOOLCHAIN" ]]; then
@@ -22,7 +22,6 @@ fi
prepare() {
cd "$srcdir/${pkgname}"
wget https://downloads.tesses.net/ShellPackage.crvm
}
build() {
@@ -30,9 +29,9 @@ build() {
mkdir build
if [[ -z "$CMAKE_TOOLCHAIN" ]]; then
cmake -S . -B build -DCMAKE_INSTALL_PREFIX=/usr -DTESSESFRAMEWORK_VENDERCERTCHAIN=OFF -DTESSESFRAMEWORK_FETCHCONTENT=OFF -DCMAKE_BUILD_TYPE=RelWithDebInfo
cmake -S . -B build -DCMAKE_INSTALL_PREFIX=/usr -DTESSESFRAMEWORK_VENDERCERTCHAIN=OFF -DTESSESFRAMEWORK_FETCHCONTENT=OFF -DCMAKE_BUILD_TYPE=Release
else
cmake -S . -B build -DCMAKE_INSTALL_PREFIX=/usr -DTESSESFRAMEWORK_VENDERCERTCHAIN=OFF -DTESSESFRAMEWORK_FETCHCONTENT=OFF -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_TOOLCHAIN_FILE="$CMAKE_TOOLCHAIN"
cmake -S . -B build -DCMAKE_INSTALL_PREFIX=/usr -DTESSESFRAMEWORK_VENDERCERTCHAIN=OFF -DTESSESFRAMEWORK_FETCHCONTENT=OFF -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE="$CMAKE_TOOLCHAIN"
fi
cd build
@@ -47,4 +46,3 @@ package() {
cd "$srcdir/${pkgname}/build"
make install DESTDIR="$pkgdir/"
}

View File

@@ -4,14 +4,14 @@ 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.tesseslanguage.com/api/packages/tesses50/arch/core
https://git.tesses.org/api/packages/tesses50/arch/core
cd ..
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.tesseslanguage.com/api/packages/tesses50/arch/core
https://git.tesses.org/api/packages/tesses50/arch/core

View File

@@ -1,46 +0,0 @@
#!/bin/bash
source ./version.sh
mkdir -p build/jammy
cd build/jammy
mkdir build-amd64
cmake -S ../../../../ -B build-amd64 -DCMAKE_INSTALL_PREFIX=/usr -DTESSESFRAMEWORK_VENDERCERTCHAIN=OFF -DTESSESFRAMEWORK_FETCHCONTENT=OFF
cd build-amd64
make -j`nproc`
make install DESTDIR=../tessesframework_$DEB_VERSION\_amd64
mkdir -p ../tessesframework_$DEB_VERSION\_amd64/DEBIAN
bash ../../../make-control.sh ../tessesframework_$DEB_VERSION\_amd64/DEBIAN/control amd64
cd ../
dpkg-deb --build tessesframework_$DEB_VERSION\_amd64
# ARM64
mkdir build-arm64
cmake -S ../../../../ -B build-arm64 -DCMAKE_INSTALL_PREFIX=/usr -DTESSESFRAMEWORK_VENDERCERTCHAIN=OFF -DTESSESFRAMEWORK_FETCHCONTENT=OFF -DCMAKE_TOOLCHAIN_FILE=/opt/toolchains/arm64.cmake
cd build-arm64
make -j`nproc`
make install DESTDIR=../tessesframework_$DEB_VERSION\_arm64
mkdir -p ../tessesframework_$DEB_VERSION\_arm64/DEBIAN
bash ../../../make-control.sh ../tessesframework_$DEB_VERSION\_arm64/DEBIAN/control arm64
cd ../
dpkg-deb --build tessesframework_$DEB_VERSION\_arm64
# RISCV64
mkdir build-riscv64
cmake -S ../../../../ -B build-riscv64 -DCMAKE_INSTALL_PREFIX=/usr -DTESSESFRAMEWORK_VENDERCERTCHAIN=OFF -DTESSESFRAMEWORK_FETCHCONTENT=OFF -DCMAKE_TOOLCHAIN_FILE=/opt/toolchains/riscv64.cmake
cd build-riscv64
make -j`nproc`
make install DESTDIR=../tessesframework_$DEB_VERSION\_riscv64
mkdir -p ../tessesframework_$DEB_VERSION\_riscv64/DEBIAN
bash ../../../make-control.sh ../tessesframework_$DEB_VERSION\_riscv64/DEBIAN/control riscv64
cd ../
dpkg-deb --build tessesframework_$DEB_VERSION\_riscv64
# ARMHF
mkdir build-armhf
cmake -S ../../../../ -B build-armhf -DCMAKE_INSTALL_PREFIX=/usr -DTESSESFRAMEWORK_VENDERCERTCHAIN=OFF -DTESSESFRAMEWORK_FETCHCONTENT=OFF -DCMAKE_TOOLCHAIN_FILE=/opt/toolchains/armhf.cmake
cd build-armhf
make -j`nproc`
make install DESTDIR=../tessesframework_$DEB_VERSION\_armhf
mkdir -p ../tessesframework_$DEB_VERSION\_armhf/DEBIAN
bash ../../../make-control.sh ../tessesframework_$DEB_VERSION\_armhf/DEBIAN/control armhf
cd ../
dpkg-deb --build tessesframework_$DEB_VERSION\_armhf

View File

@@ -1,57 +0,0 @@
#!/bin/bash
source ./version.sh
mkdir -p build/plucky
cd build/plucky
mkdir build-amd64
cmake -S ../../../../ -B build-amd64 -DCMAKE_INSTALL_PREFIX=/usr -DTESSESFRAMEWORK_VENDERCERTCHAIN=OFF -DTESSESFRAMEWORK_FETCHCONTENT=OFF
cd build-amd64
make -j`nproc`
make install DESTDIR=../tessesframework_$DEB_VERSION\_amd64
mkdir -p ../tessesframework_$DEB_VERSION\_amd64/DEBIAN
bash ../../../make-control.sh ../tessesframework_$DEB_VERSION\_amd64/DEBIAN/control amd64
cd ../
dpkg-deb --build tessesframework_$DEB_VERSION\_amd64
# ARM64
mkdir build-arm64
cmake -S ../../../../ -B build-arm64 -DCMAKE_INSTALL_PREFIX=/usr -DTESSESFRAMEWORK_VENDERCERTCHAIN=OFF -DTESSESFRAMEWORK_FETCHCONTENT=OFF -DCMAKE_TOOLCHAIN_FILE=/opt/toolchains/arm64.cmake
cd build-arm64
make -j`nproc`
make install DESTDIR=../tessesframework_$DEB_VERSION\_arm64
mkdir -p ../tessesframework_$DEB_VERSION\_arm64/DEBIAN
bash ../../../make-control.sh ../tessesframework_$DEB_VERSION\_arm64/DEBIAN/control arm64
cd ../
dpkg-deb --build tessesframework_$DEB_VERSION\_arm64
# RISCV64
mkdir build-riscv64
cmake -S ../../../../ -B build-riscv64 -DCMAKE_INSTALL_PREFIX=/usr -DTESSESFRAMEWORK_VENDERCERTCHAIN=OFF -DTESSESFRAMEWORK_FETCHCONTENT=OFF -DCMAKE_TOOLCHAIN_FILE=/opt/toolchains/riscv64.cmake
cd build-riscv64
make -j`nproc`
make install DESTDIR=../tessesframework_$DEB_VERSION\_riscv64
mkdir -p ../tessesframework_$DEB_VERSION\_riscv64/DEBIAN
bash ../../../make-control.sh ../tessesframework_$DEB_VERSION\_riscv64/DEBIAN/control riscv64
cd ../
dpkg-deb --build tessesframework_$DEB_VERSION\_riscv64
# ARMHF
mkdir build-armhf
cmake -S ../../../../ -B build-armhf -DCMAKE_INSTALL_PREFIX=/usr -DTESSESFRAMEWORK_VENDERCERTCHAIN=OFF -DTESSESFRAMEWORK_FETCHCONTENT=OFF -DCMAKE_TOOLCHAIN_FILE=/opt/toolchains/armhf.cmake
cd build-armhf
make -j`nproc`
make install DESTDIR=../tessesframework_$DEB_VERSION\_armhf
mkdir -p ../tessesframework_$DEB_VERSION\_armhf/DEBIAN
bash ../../../make-control.sh ../tessesframework_$DEB_VERSION\_armhf/DEBIAN/control armhf
cd ../
dpkg-deb --build tessesframework_$DEB_VERSION\_armhf
# I386
mkdir build-i386
cmake -S ../../../../ -B build-i386 -DCMAKE_INSTALL_PREFIX=/usr -DTESSESFRAMEWORK_VENDERCERTCHAIN=OFF -DTESSESFRAMEWORK_FETCHCONTENT=OFF -DCMAKE_TOOLCHAIN_FILE=/opt/toolchains/i386.cmake
cd build-i386
make -j`nproc`
make install DESTDIR=../tessesframework_$DEB_VERSION\_i386
mkdir -p ../tessesframework_$DEB_VERSION\_i386/DEBIAN
bash ../../../make-control.sh ../tessesframework_$DEB_VERSION\_i386/DEBIAN/control i386
cd ../
dpkg-deb --build tessesframework_$DEB_VERSION\_i386

View File

@@ -1,8 +0,0 @@
echo "Package: tessesframework" > "$1"
echo "Version: $DEB_VERSION" >> "$1"
echo "Architecture: $2" >> "$1"
echo "Essential: no" >> "$1"
echo "Priority: optional" >> "$1"
echo "Depends: libmbedtls-dev" >> "$1"
echo "Maintainer: Mike Nolan" >> "$1"
echo "Description: A cross platform wrapper library" >> "$1"

View File

@@ -1,22 +0,0 @@
#!/bin/bash
source ./version.sh
curl --user tesses50:$GITEA_AUTH -X DELETE \
https://git.tesseslanguage.com/api/packages/tesses50/debian/pool/jammy/main/tessesframework/$DEB_VERSION/amd64
curl --user tesses50:$GITEA_AUTH -X DELETE \
https://git.tesseslanguage.com/api/packages/tesses50/debian/pool/jammy/main/tessesframework/$DEB_VERSION/arm64
curl --user tesses50:$GITEA_AUTH -X DELETE \
https://git.tesseslanguage.com/api/packages/tesses50/debian/pool/jammy/main/tessesframework/$DEB_VERSION/riscv64
curl --user tesses50:$GITEA_AUTH -X DELETE \
https://git.tesseslanguage.com/api/packages/tesses50/debian/pool/jammy/main/tessesframework/$DEB_VERSION/armhf
curl --user tesses50:$GITEA_AUTH \
--upload-file build/jammy/tessesframework_$DEB_VERSION\_amd64.deb \
https://git.tesseslanguage.com/api/packages/tesses50/debian/pool/jammy/main/upload
curl --user tesses50:$GITEA_AUTH \
--upload-file build/jammy/tessesframework_$DEB_VERSION\_arm64.deb \
https://git.tesseslanguage.com/api/packages/tesses50/debian/pool/jammy/main/upload
curl --user tesses50:$GITEA_AUTH \
--upload-file build/jammy/tessesframework_$DEB_VERSION\_riscv64.deb \
https://git.tesseslanguage.com/api/packages/tesses50/debian/pool/jammy/main/upload
curl --user tesses50:$GITEA_AUTH \
--upload-file build/jammy/tessesframework_$DEB_VERSION\_armhf.deb \
https://git.tesseslanguage.com/api/packages/tesses50/debian/pool/jammy/main/upload

View File

@@ -1,27 +0,0 @@
#!/bin/bash
source ./version.sh
curl --user tesses50:$GITEA_AUTH -X DELETE \
https://git.tesseslanguage.com/api/packages/tesses50/debian/pool/plucky/main/tessesframework/$DEB_VERSION/amd64
curl --user tesses50:$GITEA_AUTH -X DELETE \
https://git.tesseslanguage.com/api/packages/tesses50/debian/pool/plucky/main/tessesframework/$DEB_VERSION/arm64
curl --user tesses50:$GITEA_AUTH -X DELETE \
https://git.tesseslanguage.com/api/packages/tesses50/debian/pool/plucky/main/tessesframework/$DEB_VERSION/i386
curl --user tesses50:$GITEA_AUTH -X DELETE \
https://git.tesseslanguage.com/api/packages/tesses50/debian/pool/plucky/main/tessesframework/$DEB_VERSION/riscv64
curl --user tesses50:$GITEA_AUTH -X DELETE \
https://git.tesseslanguage.com/api/packages/tesses50/debian/pool/plucky/main/tessesframework/$DEB_VERSION/armhf
curl --user tesses50:$GITEA_AUTH \
--upload-file build/plucky/tessesframework_$DEB_VERSION\_amd64.deb \
https://git.tesseslanguage.com/api/packages/tesses50/debian/pool/plucky/main/upload
curl --user tesses50:$GITEA_AUTH \
--upload-file build/plucky/tessesframework_$DEB_VERSION\_arm64.deb \
https://git.tesseslanguage.com/api/packages/tesses50/debian/pool/plucky/main/upload
curl --user tesses50:$GITEA_AUTH \
--upload-file build/plucky/tessesframework_$DEB_VERSION\_i386.deb \
https://git.tesseslanguage.com/api/packages/tesses50/debian/pool/plucky/main/upload
curl --user tesses50:$GITEA_AUTH \
--upload-file build/plucky/tessesframework_$DEB_VERSION\_riscv64.deb \
https://git.tesseslanguage.com/api/packages/tesses50/debian/pool/plucky/main/upload
curl --user tesses50:$GITEA_AUTH \
--upload-file build/plucky/tessesframework_$DEB_VERSION\_armhf.deb \
https://git.tesseslanguage.com/api/packages/tesses50/debian/pool/plucky/main/upload

View File

@@ -1 +0,0 @@
export DEB_VERSION=0.0.1

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

@@ -21,9 +21,9 @@ int main(int argc, char** argv)
.SendText(
"<!DOCTYPE html>"
"<html>"
"<head><meta charset=\"UTF-8\"><title>AnonyDump</title></head>"
"<head><meta charset=\"UTF-8\"><title>AnonyDrop</title><meta name=\"color-scheme\" content=\"dark light\"></head>"
"<body>"
"<h1>AnonyDump</h1>"
"<h1>AnonyDrop</h1>"
"<a href=\"./files/\">Files</a>"
"<form action=\"./upload\" method=\"post\" enctype=\"multipart/form-data\" accept-charset=\"UTF-8\">"
"<input type=\"file\" name=\"file\" multiple>"
@@ -50,12 +50,11 @@ int main(int argc, char** argv)
.SendText(
"<!DOCTYPE html>"
"<html>"
"<head><title>AnonyDump - 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>"
"</form>"
"</body>"
"</html>"
);

24
apps/tuuid.cpp Normal file
View File

@@ -0,0 +1,24 @@
#include "TessesFramework/Uuid.hpp"
#include <iostream>
int main(int argc, char** argv)
{
//e794499c
using namespace Tesses::Framework;
Uuid uuid = Uuid::Generate();
/*uuid.time_low = 0xe794499c;
uuid.time_mid = 0x823c;
uuid.time_hi_and_version = 0x304c;
uuid.clock_seq_hi_and_reserved = 0xa4;
uuid.clock_seq_low = 0x59;
uuid.node[0] = 0x8f;
uuid.node[1] = 0xdc;
uuid.node[2] = 0xd9;
uuid.node[3] = 0x60;
uuid.node[4] = 0xb4;
uuid.node[5] = 0xac;*/
std::cout << uuid.ToString(Tesses::Framework::UuidStringifyConfig::LowercaseNoCurly) << std::endl;
}

10
changelog.md Normal file
View File

@@ -0,0 +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

61
cmake/sources.cmake Normal file
View File

@@ -0,0 +1,61 @@
list(APPEND TESSESFRAMEWORK_SOURCE
src/Random.cpp
src/Date/Date.cpp
src/Http/FileServer.cpp
src/Http/MountableServer.cpp
src/Http/RouteServer.cpp
src/Http/CallbackServer.cpp
src/Http/HttpServer.cpp
src/Http/HttpUtils.cpp
src/Http/HttpClient.cpp
src/Http/HttpStream.cpp
src/Http/ContentDisposition.cpp
src/Http/WebSocket.cpp
src/Http/ChangeableServer.cpp
src/Http/BasicAuthServer.cpp
src/Http/CGIServer.cpp
src/Mail/Smtp.cpp
src/Serialization/Json.cpp
src/Serialization/SQLite.cpp
src/Serialization/BitConverter.cpp
src/Serialization/Bencode.cpp
src/Platform/Environment.cpp
src/Platform/Process.cpp
src/Streams/FileStream.cpp
src/Streams/MemoryStream.cpp
src/Streams/NetworkStream.cpp
src/Streams/Stream.cpp
src/Streams/BufferedStream.cpp
src/Streams/ByteReader.cpp
src/Streams/ByteWriter.cpp
src/Streams/PtyStream.cpp
src/Text/StringConverter.cpp
src/Text/HeaderGenerator.cpp
src/TextStreams/StreamReader.cpp
src/TextStreams/StreamWriter.cpp
src/TextStreams/TextReader.cpp
src/TextStreams/TextWriter.cpp
src/TextStreams/StdIOReader.cpp
src/TextStreams/StdIOWriter.cpp
src/TextStreams/StringReader.cpp
src/TextStreams/StringWriter.cpp
src/Threading/Thread.cpp
src/Threading/Mutex.cpp
src/Threading/ThreadPool.cpp
src/Filesystem/VFS.cpp
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
src/Crypto/MbedTLS/Crypto.cpp
src/Args.cpp
src/TF_Init.cpp
src/HiddenField.cpp
src/Uuid.cpp
src/BitTorrent/TorrentFile.cpp
src/BitTorrent/TorrentStream.cpp
)

View File

@@ -1,5 +1,5 @@
services:
portable-json:
image: onedev.site.tesses.net/tesses-framework/portable-json-creator:latest
image: git.tesses.org/tesses50/portable-json-creator:latest
ports:
- "4999:4999"

View File

@@ -1,22 +0,0 @@
#include "TessesFramework/TessesFramework.hpp"
using namespace Tesses::Framework;
int main(int argc, char** argv)
{
TF_Init();
auto event = std::make_shared<FunctionalEvent<uint64_t>>([](uint64_t n)->void {
std::cout << n << std::endl;
});
OnItteraton += event;
auto event2 = std::make_shared<FunctionalEvent<uint64_t>>([&event](uint64_t n)->void{
if(n == 10000) OnItteraton -= event;
});
OnItteraton += event2;
TF_RunEventLoop();
return 0;
}

17
examples/timer.cpp Normal file
View File

@@ -0,0 +1,17 @@
#include "TessesFramework/Common.hpp"
#include "TessesFramework/TessesFramework.hpp"
int main(int argc, char** argv)
{
using namespace Tesses::Framework;
TF_Init();
auto timer = TF_Timer([]()->void {
std::cout << "Hi, I am a timer" << std::endl;
});
TF_RunEventLoop();
TF_Quit();
}

View File

@@ -1,10 +1,16 @@
#include "TessesFramework/TessesFramework.hpp"
#include <TessesFramework/Platform/Environment.hpp>
#include <exception>
#include <iostream>
#include <stdexcept>
using namespace Tesses::Framework;
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:
@@ -62,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>");
@@ -71,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")
{
@@ -119,6 +134,26 @@ class MyOtherWebServer : public IHttpServer
return true;
}
}
else if(ctx.path == "/status")
{
int64_t num;
if(ctx.queryParams.TryGetFirstInt("code", num))
{
ctx.statusCode = (StatusCode)num;
}
ctx.SendErrorPage(true);
return true;
}
else if(ctx.path == "/error")
{
throw std::runtime_error("This is a error");
}
else if(ctx.path == "/error-debug")
{
ctx.WithDebug(true);
throw std::runtime_error("Platform is " + Tesses::Framework::Platform::Environment::GetPlatform());
}
else if(ctx.path == "/mymount/steve")
{
Johnny* data = ctx.GetServerContentData<Johnny>("mytag");
@@ -139,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

@@ -1,8 +1,11 @@
#pragma once
#include <chrono>
#include <cstring>
#include <cstdint>
#include <cstddef>
#include <memory>
#include <ratio>
#include <string>
#include <filesystem>
#include <map>
@@ -15,83 +18,55 @@
namespace Tesses::Framework
{
template<typename...TArgs>
class Event {
public:
virtual void Invoke(TArgs... args)=0;
virtual ~Event()
{}
};
template<typename...TArgs>
class FunctionalEvent : public Event<TArgs...> {
std::function<void(TArgs...)> cb;
public:
FunctionalEvent(std::function<void(TArgs...)> cb)
{
this->cb = cb;
}
void Invoke(TArgs... args)
{
this->cb(args...);
}
};
template<typename...TArgs>
class EventList : public Event<TArgs...> {
Threading::Mutex mtx;
std::vector<std::shared_ptr<Event<TArgs...>>> items;
public:
void operator+=(std::shared_ptr<Event<TArgs...>> event)
{
mtx.Lock();
for(std::shared_ptr<Event<TArgs...>>& item : this->items)
{
if(item.get() == event.get()) {
mtx.Unlock();
return;
}
}
this->items.push_back(event);
mtx.Unlock();
}
void operator-=(std::shared_ptr<Event<TArgs...>> event)
{
mtx.Lock();
for(auto i = this->items.begin(); i != this->items.end(); i++)
{
if(i->get() == event.get())
{
this->items.erase(i);
mtx.Unlock();
return;
}
}
mtx.Unlock();
}
void Invoke(TArgs... args)
{
mtx.Lock();
for(auto& item : this->items)
{
item->Invoke(args...);
}
mtx.Unlock();
}
void Remove(std::function<bool(std::shared_ptr<Event<TArgs...>>)> cb)
{
for(auto index = this->items.begin(); index != this->items.end(); index++)
{
if(cb(*index))
{
this->items.erase(index);
index--;
}
}
}
};
extern EventList<uint64_t> OnItteraton;
std::optional<std::string> TF_GetCommandName();
class TF_Timer_Handle;
//Used for internal purposes, don't use unless you want to run timer events on another thread
class TF_Timer_Handler {
private:
std::vector<std::weak_ptr<TF_Timer_Handle>> handles;
public:
void Update();
static std::shared_ptr<TF_Timer_Handle> Make(std::shared_ptr<TF_Timer_Handler> handler);
friend class TF_Timer_Handle;
};
class TF_Timer_Handle {
private:
std::shared_ptr<TF_Timer_Handler> timerHandler;
std::function<void()> cb;
std::chrono::milliseconds interval;
std::chrono::time_point<std::chrono::steady_clock, std::chrono::milliseconds> last;
bool enabled;
TF_Timer_Handle() = delete;
TF_Timer_Handle(std::shared_ptr<TF_Timer_Handler> timerHandler);
public:
void SetCallback(std::function<void()> cb);
int64_t GetIntervalMilliseconds();
std::chrono::duration<int64_t,std::milli> GetIntervalDuration();
void SetIntervalFromMilliseconds(int64_t ms);
void SetIntervalFromDuration(std::chrono::milliseconds dur);
void SetEnabled(bool enabled);
bool GetEnabled();
friend class TF_Timer_Handler;
};
std::shared_ptr<TF_Timer_Handle> TF_Timer();
std::shared_ptr<TF_Timer_Handle> TF_Timer(std::function<void()> cb, int64_t interval=1000, bool enabled=true);
std::shared_ptr<TF_Timer_Handle> TF_Timer(std::function<void()> cb, std::chrono::milliseconds interval, bool enabled=true);
void TF_Init();
void TF_InitWithConsole();
@@ -101,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

@@ -12,13 +12,7 @@ namespace Tesses::Framework::Filesystem
void CreateDirectory(VFSPath path);
void DeleteDirectory(VFSPath path);
bool RegularFileExists(VFSPath path);
bool SymlinkExists(VFSPath path);
bool CharacterDeviceExists(VFSPath path);
bool BlockDeviceExists(VFSPath path);
bool SocketFileExists(VFSPath path);
bool FIFOFileExists(VFSPath path);
bool DirectoryExists(VFSPath path);
void DeleteFile(VFSPath path);
void CreateSymlink(VFSPath existingFile, VFSPath symlinkFile);
@@ -32,16 +26,18 @@ namespace Tesses::Framework::Filesystem
std::string VFSPathToSystem(VFSPath path);
VFSPath SystemToVFSPath(std::string path);
void GetDate(VFSPath path, Date::DateTime& lastWrite, Date::DateTime& lastAccess);
void SetDate(VFSPath path, Date::DateTime lastWrite, Date::DateTime lastAccess);
bool Stat(VFSPath path, StatData& stat);
bool StatVFS(VFSPath path, StatVFSData& vfsData);
void Chmod(VFSPath path, uint32_t mode);
void Chown(VFSPath path, uint32_t uid, uint32_t gid);
void Lock(VFSPath path);
void Unlock(VFSPath path);
FIFOCreationResult CreateFIFO(VFSPath path, uint32_t mod);
protected:
std::shared_ptr<FSWatcher> CreateWatcher(std::shared_ptr<VFS> vfs, VFSPath path);

View File

@@ -1,100 +0,0 @@
#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();
Date::DateTime 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();
Date::DateTime lastWrite;
std::vector<MemoryEntry*> entries;
~MemoryDirectory();
};
class MemorySymlink : public MemoryEntry
{
public:
Date::DateTime 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();
std::shared_ptr<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, Date::DateTime& lastWrite, Date::DateTime& lastAccess);
void SetDate(VFSPath path, Date::DateTime lastWrite, Date::DateTime lastAccess);
~MemoryFilesystem();
};
};

View File

@@ -31,15 +31,7 @@ namespace Tesses::Framework::Filesystem
std::shared_ptr<Tesses::Framework::Streams::Stream> OpenFile(VFSPath path, std::string mode);
void CreateDirectory(VFSPath path);
void DeleteDirectory(VFSPath path);
bool SpecialFileExists(VFSPath path);
bool FileExists(VFSPath path);
bool RegularFileExists(VFSPath path);
bool SymlinkExists(VFSPath path);
bool CharacterDeviceExists(VFSPath path);
bool BlockDeviceExists(VFSPath path);
bool SocketFileExists(VFSPath path);
bool FIFOFileExists(VFSPath path);
bool DirectoryExists(VFSPath path);
bool Stat(VFSPath path, StatData& data);
void DeleteFile(VFSPath path);
void CreateSymlink(VFSPath existingFile, VFSPath symlinkFile);
VFSPathEnumerator EnumeratePaths(VFSPath path);
@@ -50,14 +42,18 @@ namespace Tesses::Framework::Filesystem
std::string VFSPathToSystem(VFSPath path);
VFSPath SystemToVFSPath(std::string path);
~MountableFilesystem();
void GetDate(VFSPath path, Date::DateTime& lastWrite, Date::DateTime& lastAccess);
void SetDate(VFSPath path, Date::DateTime lastWrite, Date::DateTime lastAccess);
bool StatVFS(VFSPath path, StatVFSData& vfsData);
void Chmod(VFSPath path, uint32_t mode);
void Chown(VFSPath path, uint32_t uid, uint32_t gid);
FIFOCreationResult CreateFIFO(VFSPath path, uint32_t mode);
void Lock(VFSPath path);
void Unlock(VFSPath path);
};
}

View File

@@ -8,13 +8,8 @@ namespace Tesses::Framework::Filesystem
{
public:
std::shared_ptr<Tesses::Framework::Streams::Stream> OpenFile(VFSPath path, std::string mode);
void CreateDirectory(VFSPath path);
void DeleteDirectory(VFSPath path);
bool RegularFileExists(VFSPath path);
bool DirectoryExists(VFSPath path);
void DeleteFile(VFSPath path);
VFSPathEnumerator EnumeratePaths(VFSPath path);
void MoveFile(VFSPath src, VFSPath dest);
bool Stat(VFSPath path, StatData& data);
std::string VFSPathToSystem(VFSPath path);
VFSPath SystemToVFSPath(std::string path);
};

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

@@ -15,15 +15,6 @@ namespace Tesses::Framework::Filesystem
std::shared_ptr<Tesses::Framework::Streams::Stream> OpenFile(VFSPath path, std::string mode);
void CreateDirectory(VFSPath path);
void DeleteDirectory(VFSPath path);
bool SpecialFileExists(VFSPath path);
bool FileExists(VFSPath path);
bool RegularFileExists(VFSPath path);
bool SymlinkExists(VFSPath path);
bool CharacterDeviceExists(VFSPath path);
bool BlockDeviceExists(VFSPath path);
bool SocketFileExists(VFSPath path);
bool FIFOFileExists(VFSPath path);
bool DirectoryExists(VFSPath path);
void DeleteFile(VFSPath path);
void CreateSymlink(VFSPath existingFile, VFSPath symlinkFile);
VFSPathEnumerator EnumeratePaths(VFSPath path);
@@ -35,13 +26,28 @@ namespace Tesses::Framework::Filesystem
std::string VFSPathToSystem(VFSPath path);
VFSPath SystemToVFSPath(std::string path);
~SubdirFilesystem();
void GetDate(VFSPath path, Date::DateTime& lastWrite, Date::DateTime& lastAccess);
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<SubdirFilesystem> vfs, VFSPath path);
~Watcher();
};
};
}

View File

@@ -20,15 +20,6 @@ namespace Tesses::Framework::Filesystem
std::shared_ptr<Tesses::Framework::Streams::Stream> OpenFile(VFSPath path, std::string mode);
void CreateDirectory(VFSPath path);
void DeleteDirectory(VFSPath path);
bool SpecialFileExists(VFSPath path);
bool FileExists(VFSPath path);
bool RegularFileExists(VFSPath path);
bool SymlinkExists(VFSPath path);
bool CharacterDeviceExists(VFSPath path);
bool BlockDeviceExists(VFSPath path);
bool SocketFileExists(VFSPath path);
bool FIFOFileExists(VFSPath path);
bool DirectoryExists(VFSPath path);
void DeleteFile(VFSPath path);
void CreateSymlink(VFSPath existingFile, VFSPath symlinkFile);
VFSPathEnumerator EnumeratePaths(VFSPath path);
@@ -40,15 +31,22 @@ namespace Tesses::Framework::Filesystem
std::string VFSPathToSystem(VFSPath path);
VFSPath SystemToVFSPath(std::string path);
void GetDate(VFSPath path, Date::DateTime& lastWrite, Date::DateTime& lastAccess);
void SetDate(VFSPath path, Date::DateTime lastWrite, Date::DateTime lastAccess);
bool StatVFS(VFSPath path, StatVFSData& vfsData);
bool Stat(VFSPath path, StatData& data);
void Chmod(VFSPath path, uint32_t mode);
void Chown(VFSPath path, uint32_t uid, uint32_t gid);
FIFOCreationResult CreateFIFO(VFSPath path, uint32_t mode);
void Close();
void Lock(VFSPath path);
void Unlock(VFSPath path);
~TempFS();
protected:
std::shared_ptr<FSWatcher> CreateWatcher(std::shared_ptr<VFS> vfs, VFSPath path);
};
}

View File

@@ -1,6 +1,8 @@
#pragma once
#include "../Common.hpp"
#include "../Streams/Stream.hpp"
#include <TessesFramework/Common.hpp>
#include <TessesFramework/Date/Date.hpp>
#include <functional>
#include <memory>
#include "../Date/Date.hpp"
@@ -9,8 +11,8 @@
namespace Tesses::Framework::Filesystem
{
class StatVFSData {
public:
struct StatVFSData {
uint64_t BlockSize;
uint64_t FragmentSize;
uint64_t Blocks;
@@ -23,6 +25,88 @@ namespace Tesses::Framework::Filesystem
uint64_t Flags;
uint64_t MaxNameLength;
};
constexpr uint32_t MODE_USER_READ = 0400;
constexpr uint32_t MODE_USER_WRITE = 0200;
constexpr uint32_t MODE_USER_EXEC = 0100;
constexpr uint32_t MODE_GROUP_READ = (MODE_USER_READ >> 3);
constexpr uint32_t MODE_GROUP_WRITE = (MODE_USER_WRITE >> 3);
constexpr uint32_t MODE_GROUP_EXEC = (MODE_USER_EXEC >> 3);
constexpr uint32_t MODE_OTHER_READ = (MODE_GROUP_READ >> 3);
constexpr uint32_t MODE_OTHER_WRITE = (MODE_GROUP_WRITE >> 3);
constexpr uint32_t MODE_OTHER_EXEC = (MODE_GROUP_EXEC >> 3);
constexpr uint32_t MODE_REGULAR = 0100000;
constexpr uint32_t MODE_DIRECTORY = 0040000;
constexpr uint32_t MODE_CHAR_DEVICE = 0020000;
constexpr uint32_t MODE_BLOCK_DEVICE = 0060000;
constexpr uint32_t MODE_SOCKET = 0140000;
constexpr uint32_t MODE_FIFO = 0010000;
constexpr uint32_t MODE_SYMLINK = 0120000;
struct StatData {
uint64_t Device;
uint64_t Inode;
uint32_t Mode;
uint64_t HardLinks;
uint32_t UserId;
uint32_t GroupId;
uint64_t DeviceId;
uint64_t Size;
uint64_t BlockSize;
uint64_t BlockCount;
Date::DateTime LastAccess;
Date::DateTime LastModified;
Date::DateTime LastStatus;
bool IsRegularFile()
{
return (Mode & MODE_REGULAR) > 0;
}
bool IsDirectory()
{
return (Mode & MODE_DIRECTORY) > 0;
}
bool IsCharDevice()
{
return (Mode & MODE_CHAR_DEVICE) > 0;
}
bool IsBlockDevice()
{
return (Mode & MODE_BLOCK_DEVICE) > 0;
}
bool IsSocket()
{
return (Mode & MODE_SOCKET) > 0;
}
bool IsFIFO()
{
return (Mode & MODE_FIFO) > 0;
}
bool IsSymlink()
{
return (Mode & MODE_SYMLINK) > 0;
}
bool IsSpecial()
{
if(IsRegularFile()) return false;
if(IsDirectory()) return false;
return true;
}
std::string ToSizeString(bool usesBin=true)
{
return TF_FileSize(this->Size, usesBin);
}
};
class VFSPath {
public:
static VFSPath CurrentDirectoryAsRelative();
@@ -189,43 +273,55 @@ namespace Tesses::Framework::Filesystem
static std::shared_ptr<FSWatcher> Create(std::shared_ptr<VFS> vfs, VFSPath path);
};
enum class FIFOCreationResult {
Success=0,
Exists = 1,
ReadOnlyFS = 2,
Denied = 3,
OutOfInodes = 4,
UnknownError = 5,
Unsupported = 255
};
class VFS {
public:
virtual std::shared_ptr<Tesses::Framework::Streams::Stream> OpenFile(VFSPath path, std::string mode)=0;
virtual void CreateDirectory(VFSPath path)=0;
virtual void DeleteDirectory(VFSPath path)=0;
virtual bool RegularFileExists(VFSPath path)=0;
virtual bool SymlinkExists(VFSPath path);
virtual bool CharacterDeviceExists(VFSPath path);
virtual bool BlockDeviceExists(VFSPath path);
virtual bool SocketFileExists(VFSPath path);
virtual bool FIFOFileExists(VFSPath path);
virtual bool FileExists(VFSPath path);
virtual bool SpecialFileExists(VFSPath path);
virtual void CreateDirectory(VFSPath path);
virtual void DeleteDirectory(VFSPath path);
bool DirectoryExists(VFSPath path);
bool RegularFileExists(VFSPath path);
bool SymlinkExists(VFSPath path);
bool CharacterDeviceExists(VFSPath path);
bool BlockDeviceExists(VFSPath path);
bool SocketFileExists(VFSPath path);
bool FIFOFileExists(VFSPath path);
bool FileExists(VFSPath path);
bool SpecialFileExists(VFSPath path);
virtual void CreateSymlink(VFSPath existingFile, VFSPath symlinkFile);
virtual void CreateHardlink(VFSPath existingFile, VFSPath newName);
virtual bool DirectoryExists(VFSPath path)=0;
virtual void DeleteFile(VFSPath path)=0;
virtual void DeleteFile(VFSPath path);
virtual void DeleteDirectoryRecurse(VFSPath path);
virtual VFSPathEnumerator EnumeratePaths(VFSPath path) = 0;
virtual void MoveFile(VFSPath src, VFSPath dest)=0;
virtual void MoveFile(VFSPath src, VFSPath dest);
virtual void MoveDirectory(VFSPath src, VFSPath dest);
virtual VFSPath ReadLink(VFSPath path);
virtual std::string VFSPathToSystem(VFSPath path)=0;
virtual VFSPath SystemToVFSPath(std::string path)=0;
virtual void GetDate(VFSPath path, Date::DateTime& lastWrite, Date::DateTime& lastAccess);
void GetDate(VFSPath path, Date::DateTime& lastWrite, Date::DateTime& lastAccess);
virtual void SetDate(VFSPath path, Date::DateTime lastWrite, Date::DateTime lastAccess);
virtual bool Stat(VFSPath path, StatData& data) = 0;
virtual bool StatVFS(VFSPath path, StatVFSData& data);
virtual void Chmod(VFSPath path, uint32_t mode);
virtual void Chown(VFSPath path, uint32_t userId, uint32_t groupId);
virtual void Lock(VFSPath path);
virtual void Unlock(VFSPath path);
virtual FIFOCreationResult CreateFIFO(VFSPath path, uint32_t mode);
virtual ~VFS();
@@ -237,7 +333,6 @@ namespace Tesses::Framework::Filesystem
};
namespace Literals
{
inline VFSPath operator""_tpath(const char* path)
@@ -246,4 +341,3 @@ namespace Tesses::Framework::Filesystem
}
}
}

View File

@@ -6,19 +6,40 @@
#include "../Date/Date.hpp"
#include <unordered_map>
#include "WebSocket.hpp"
#include <queue>
namespace Tesses::Framework::Http
{
class ServerContextData {
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;
public:
HttpDictionary requestHeaders;
HttpDictionary responseHeaders;
@@ -34,7 +55,7 @@ namespace Tesses::Framework::Http
uint16_t serverPort;
std::string version;
bool encrypted;
ServerContext(std::shared_ptr<Tesses::Framework::Streams::Stream> strm);
ServerContext(std::shared_ptr<Tesses::Framework::Streams::Stream> strm, bool debug=false);
~ServerContext();
std::shared_ptr<Tesses::Framework::Streams::Stream> GetStream();
std::string GetOriginalPathWithQuery();
@@ -51,8 +72,10 @@ 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);
ServerContext& WithLastModified(Date::DateTime time);
ServerContext& WithHeader(std::string key, std::string value);
ServerContext& WithSingleHeader(std::string key, std::string value);
@@ -61,6 +84,9 @@ namespace Tesses::Framework::Http
ServerContext& WriteHeaders();
ServerContext& WithLocationHeader(std::string url);
ServerContext& WithLocationHeader(std::string url,StatusCode sc);
ServerContext& WithHeaderIntercepter(std::function<bool(ServerContext&)> cb);
ServerContext& WithDebug(bool debug=true);
bool Debug();
void StartWebSocketSession(std::function<void(std::function<void(WebSocketMessage&)>,std::function<void()>,std::function<void()>)> onOpen, std::function<void(WebSocketMessage&)> onReceive, std::function<void(bool)> onClose);
void StartWebSocketSession(std::shared_ptr<WebSocketConnection> connection);
std::string GetServerRoot();
@@ -80,6 +106,9 @@ namespace Tesses::Framework::Http
data[name] = item;
return item;
}
friend class ServerSentEvents;
};
class IHttpServer {
@@ -95,14 +124,15 @@ namespace Tesses::Framework::Http
bool showIPs;
bool showARTL;
bool debug;
public:
HttpServer(std::shared_ptr<Tesses::Framework::Streams::TcpServer> tcpServer, std::shared_ptr<IHttpServer> http, bool showIPs=true);
HttpServer(uint16_t port, std::shared_ptr<IHttpServer> http, bool showIPs=true);
HttpServer(std::string unixPath, std::shared_ptr<IHttpServer> http);
HttpServer(std::shared_ptr<Tesses::Framework::Streams::TcpServer> tcpServer, std::shared_ptr<IHttpServer> http, bool showIPs=true, bool debug=false);
HttpServer(uint16_t port, std::shared_ptr<IHttpServer> http, bool showIPs=true, bool debug=false);
HttpServer(std::string unixPath, std::shared_ptr<IHttpServer> http, bool debug=false);
uint16_t GetPort();
void StartAccepting();
static void Process(std::shared_ptr<Tesses::Framework::Streams::Stream> strm, std::shared_ptr<IHttpServer> server, std::string ip, uint16_t port,uint16_t serverPort, bool encrypted);
static void Process(std::shared_ptr<Tesses::Framework::Streams::Stream> strm, std::shared_ptr<IHttpServer> server, std::string ip, uint16_t port,uint16_t serverPort, bool encrypted, bool debug=false);
~HttpServer();
};
}

View File

@@ -143,10 +143,14 @@ struct CaseInsensitiveLess {
class HttpUtils
{
public:
static char NibbleToHex(uint8_t b, bool isUppercase);
static char NibbleToHex(uint8_t nibble);
static uint8_t HexToNibble(char c);
static std::string BytesToHex(const std::vector<uint8_t>& data);
static void BytesToHex(std::string& text,const std::vector<uint8_t>& data);
static std::string BytesToHex(const std::vector<uint8_t>& data,bool isUppercase);
static void BytesToHex(std::string& text,const std::vector<uint8_t>& data, bool isUppercase);
static std::vector<uint8_t> HexToBytes(const std::string& text);
static void HexToBytes(std::vector<uint8_t>& data,const std::string& text);
static std::string MimeType(std::filesystem::path p);

View File

@@ -1,5 +1,6 @@
#pragma once
#include "../Common.hpp"
#include "../Uuid.hpp"
namespace Tesses::Framework::Serialization
{
@@ -9,40 +10,73 @@ namespace Tesses::Framework::Serialization
*/
class BitConverter {
public:
/**
* @brief Get the bits of a double from a int64_t
*
* @param v a int64_t with double's bits
* @return double the double
*/
static double ToDoubleBits(uint64_t v);
/**
* @brief Get the bits of a int64_t from a double
*
* @param v a double with int64_t's bits
* @return uint64_t the int64_t
*/
static uint64_t ToUintBits(double v);
/**
* @brief Get big endian double from uint8_t reference of first element of 8 byte array
*
* @param b a reference to the first byte of an array
* @return double the double
*/
static float ToFloatBits(uint32_t v);
static uint32_t ToUint32Bits(float v);
static double ToDoubleBE(uint8_t& b);
/**
* @brief Get big endian uint64_t from uint8_t reference of first element of 8 byte array
*
* @param b a reference to the first byte of an array
* @return uint64_t the uint64_t
*/
static float ToFloatBE(uint8_t& b);
static uint64_t ToUint64BE(uint8_t& b);
static uint32_t ToUint32BE(uint8_t& b);
static uint16_t ToUint16BE(uint8_t& b);
static double ToDoubleLE(uint8_t& b);
static float ToFloatLE(uint8_t& b);
static uint64_t ToUint64LE(uint8_t& b);
static uint32_t ToUint32LE(uint8_t& b);
static uint16_t ToUint16LE(uint8_t& b);
static int64_t ToSint64BE(uint8_t& b);
static int32_t ToSint32BE(uint8_t& b);
static int16_t ToSint16BE(uint8_t& b);
static int64_t ToSint64LE(uint8_t& b);
static int32_t ToSint32LE(uint8_t& b);
static int16_t ToSint16LE(uint8_t& b);
static Uuid ToUuid(uint8_t& b);
static void ToUuid(uint8_t& b, Uuid& uuid);
static void FromDoubleBE(uint8_t& b, double v);
static void FromFloatBE(uint8_t& b, float v);
static void FromUint64BE(uint8_t& b, uint64_t v);
static void FromUint32BE(uint8_t& b, uint32_t v);
static void FromUint16BE(uint8_t& b, uint16_t v);
static void FromDoubleLE(uint8_t& b, double v);
static void FromFloatLE(uint8_t& b, float v);
static void FromUint64LE(uint8_t& b, uint64_t v);
static void FromUint32LE(uint8_t& b, uint32_t v);
static void FromUint16LE(uint8_t& b, uint16_t v);
static void FromSint64BE(uint8_t& b, int64_t v);
static void FromSint32BE(uint8_t& b, int32_t v);
static void FromSint16BE(uint8_t& b, int16_t v);
static void FromSint64LE(uint8_t& b, int64_t v);
static void FromSint32LE(uint8_t& b, int32_t v);
static void FromSint16LE(uint8_t& b, int16_t v);
static void FromUuid(uint8_t& b, const Uuid& uuid);
static inline bool IsLittleEndian()
{
uint8_t a[2];
a[0] = 0x01;
a[1] = 0xA4;
uint16_t num=0;
memcpy(&num,&a, 2);
return num != 420;
}
};
}

View File

@@ -1,5 +1,6 @@
#pragma once
#include "Stream.hpp"
#include "../Uuid.hpp"
namespace Tesses::Framework::Streams
{
@@ -26,5 +27,7 @@ namespace Tesses::Framework::Streams
float ReadF32LE();
double ReadF64BE();
double ReadF64LE();
Uuid ReadUuid();
void ReadUuid(Uuid& uuid);
};
}

View File

@@ -1,6 +1,6 @@
#pragma once
#include "Stream.hpp"
#include "../Uuid.hpp"
namespace Tesses::Framework::Streams
{
class ByteWriter {
@@ -27,5 +27,6 @@ namespace Tesses::Framework::Streams
void WriteF32LE(float v);
void WriteF64BE(double v);
void WriteF64LE(double v);
void WriteUuid(const Uuid& uuid);
};
}

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,7 +31,7 @@
#include "Filesystem/SubdirFilesystem.hpp"
#include "Filesystem/NullFilesystem.hpp"
#include "Filesystem/MountableFilesystem.hpp"
#include "Filesystem/MemoryFilesystem.hpp"
#include "Filesystem/RelativeFilesystem.hpp"
#include "Filesystem/FSHelpers.hpp"
#include "Crypto/ClientTLSStream.hpp"
#include "Crypto/Crypto.hpp"

View File

@@ -0,0 +1,37 @@
#pragma once
#include "Common.hpp"
namespace Tesses::Framework {
enum class UuidStringifyConfig {
IsUppercase=0b001,
HasCurly=0b010,
HasDashes=0b100,
UppercaseCompact = IsUppercase,
LowercaseCompact = 0,
UppercaseNoCurly = IsUppercase | HasDashes,
LowercaseNoCurly = HasDashes,
UppercaseCurly = IsUppercase | HasDashes | HasCurly,
LowercaseCurly = HasDashes | HasCurly
};
struct Uuid {
Uuid() = default;
uint32_t time_low = 0;
uint16_t time_mid = 0;
uint16_t time_hi_and_version = 0;
uint8_t clock_seq_hi_and_reserved = 0;
uint8_t clock_seq_low = 0;
uint8_t node[6] = {0,0,0,0,0,0};
static Uuid Generate();
static void Generate(Uuid& uuid);
static bool TryParse(std::string text, Uuid& uuid);
std::string ToString(UuidStringifyConfig cfg = UuidStringifyConfig::UppercaseCurly) const;
bool IsEmpty() const;
};
bool operator==(const Uuid& left, const Uuid& right);
bool operator!=(const Uuid& left, const Uuid& right);
}

View File

@@ -2,7 +2,7 @@ set(PKGCONFIG_INCLUDEDIR "\${prefix}/${CMAKE_INSTALL_INCLUDEDIR}")
set(PKGCONFIG_LIBDIR "\${prefix}/${CMAKE_INSTALL_LIBDIR}")
set(PKGCONFIG_PROJECT_DESCRIPTION "A cross platform wrapper library")
set(PKGCONFIG_PROJECT_HOMEPAGE_URL "https://onedev.site.tesses.net/tesses-framework")
set(PKGCONFIG_PROJECT_HOMEPAGE_URL "https://git.tesses.org/tessesframework")
if(TESSESFRAMEWORK_ENABLE_MBED)
set(PKGCONFIG_DEPS "Requires: mbedtls")

View File

@@ -1,7 +1,10 @@
#include "TessesFramework/Filesystem/LocalFS.hpp"
#include "TessesFramework/Streams/FileStream.hpp"
#include <cerrno>
#include <filesystem>
#include <iostream>
#include <sys/stat.h>
#include <sys/types.h>
#if defined(_WIN32)
#include <windows.h>
#include "TessesFramework/Filesystem/VFSFix.hpp"
@@ -9,6 +12,7 @@
#else
#include <utime.h>
#include <sys/statvfs.h>
#include <unistd.h>
#endif
#include "TessesFramework/Threading/Thread.hpp"
@@ -27,16 +31,44 @@ namespace Tesses::Framework::Filesystem
pft->dwHighDateTime = time_value.HighPart;
}
#endif
void LocalFilesystem::GetDate(VFSPath path, Date::DateTime& lastWrite, Date::DateTime& lastAccess)
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
{
lastAccess = Date::DateTime((int64_t)st.st_atime);
lastWrite = Date::DateTime((int64_t)st.st_mtime);
sfs.Device = (uint64_t)st.st_dev;
sfs.Inode = (uint64_t)st.st_ino;
sfs.Mode = (uint32_t)st.st_mode;
sfs.HardLinks = (uint64_t)st.st_nlink;
sfs.UserId = (uint32_t)st.st_uid;
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);
return true;
}
return false;
}
void LocalFilesystem::SetDate(VFSPath path, Date::DateTime lastWrite, Date::DateTime lastAccess)
{
std::string s = VFSPathToSystem(path);
@@ -96,34 +128,6 @@ namespace Tesses::Framework::Filesystem
{
std::filesystem::create_directories(VFSPathToSystem(path));
}
bool LocalFilesystem::DirectoryExists(VFSPath path)
{
return std::filesystem::is_directory(VFSPathToSystem(path));
}
bool LocalFilesystem::RegularFileExists(VFSPath path)
{
return std::filesystem::is_regular_file(VFSPathToSystem(path));
}
bool LocalFilesystem::SymlinkExists(VFSPath path)
{
return std::filesystem::is_symlink(VFSPathToSystem(path));
}
bool LocalFilesystem::BlockDeviceExists(VFSPath path)
{
return std::filesystem::is_block_file(VFSPathToSystem(path));
}
bool LocalFilesystem::CharacterDeviceExists(VFSPath path)
{
return std::filesystem::is_character_file(VFSPathToSystem(path));
}
bool LocalFilesystem::SocketFileExists(VFSPath path)
{
return std::filesystem::is_socket(VFSPathToSystem(path));
}
bool LocalFilesystem::FIFOFileExists(VFSPath path)
{
return std::filesystem::is_fifo(VFSPathToSystem(path));
}
void LocalFilesystem::CreateSymlink(VFSPath existingFile, VFSPath symlinkFile)
{
if(std::filesystem::is_directory(VFSPathToSystem(existingFile)))
@@ -185,7 +189,10 @@ namespace Tesses::Framework::Filesystem
VFSPathEnumerator LocalFilesystem::EnumeratePaths(VFSPath path)
{
auto dir = new std::filesystem::directory_iterator(VFSPathToSystem(path));
std::filesystem::path sysPath = VFSPathToSystem(path);
if(!std::filesystem::is_directory(sysPath)) return VFSPathEnumerator();
auto dir = new std::filesystem::directory_iterator(sysPath);
return VFSPathEnumerator([dir,path](VFSPath& path0)->bool {
std::filesystem::directory_iterator& ittr = *dir;
if(ittr != std::filesystem::directory_iterator())
@@ -236,6 +243,45 @@ namespace Tesses::Framework::Filesystem
chmod(pathStr.c_str(), (mode_t)mode);
#endif
}
void LocalFilesystem::Chown(VFSPath path, uint32_t uid, uint32_t gid)
{
auto pathStr = this->VFSPathToSystem(path);
#if defined(_WIN32)
#else
chown(pathStr.c_str(), (uid_t)uid, (gid_t)gid);
#endif
}
FIFOCreationResult LocalFilesystem::CreateFIFO(VFSPath path, uint32_t mod)
{
auto pathStr = this->VFSPathToSystem(path);
#if defined(_WIN32)
return FIFOCreationResult::Unsupported;
#else
int res = mkfifo(pathStr.c_str(), (mode_t)mod);
if(res == 0) return FIFOCreationResult::Success;
else if(res == -1)
{
switch(res)
{
case EEXIST:
return FIFOCreationResult::Exists;
case ENOTSUP:
return FIFOCreationResult::Unsupported;
case EACCES:
return FIFOCreationResult::Denied;
case ENOSPC:
return FIFOCreationResult::OutOfInodes;
case EROFS:
return FIFOCreationResult::ReadOnlyFS;
}
}
return FIFOCreationResult::UnknownError;
#endif
}
void LocalFilesystem::Lock(VFSPath path)

View File

@@ -1,669 +0,0 @@
#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;
}
std::shared_ptr<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 std::make_shared<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=Date::DateTime::NowUTC();}
mtx->Unlock();
return std::make_shared<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 std::make_shared<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=Date::DateTime::NowUTC();}
mtx->Unlock();
return std::make_shared<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=Date::DateTime::NowUTC();
dir->entries.push_back(dir2);
dir->lastWrite=Date::DateTime::NowUTC();
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=Date::DateTime::NowUTC();
}
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=Date::DateTime::NowUTC();
}
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 = Date::DateTime::NowUTC();
}
mtx->Unlock();
return;
}
}
MemorySymlink* symlink = new MemorySymlink();
symlink->name = fname;
symlink->linkedTo = existingFile;
symlink->lastWrite = Date::DateTime::NowUTC();
dir->entries.push_back(symlink);
dir->lastWrite = Date::DateTime::NowUTC();
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=Date::DateTime::NowUTC();
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, Date::DateTime& lastWrite, Date::DateTime& 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, Date::DateTime lastWrite, Date::DateTime 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 = Date::DateTime::NowUTC();
}
MemoryDirectory::~MemoryDirectory()
{
for(auto item : this->entries) delete item;
}
MemoryFileData::MemoryFileData()
{
this->lastWrite = Date::DateTime::NowUTC();
this->canAccess=true;
this->readers=0;
}
}

View File

@@ -102,6 +102,21 @@ namespace Tesses::Framework::Filesystem
return vfs->StatVFS(destPath,data);
return false;
}
bool MountableFilesystem::Stat(VFSPath path, StatData& data)
{
path = path.CollapseRelativeParents();
VFSPath destRoot;
VFSPath destPath = path;
std::shared_ptr<VFS> vfs = root;
GetFS(path, destRoot, destPath, vfs);
if(vfs != nullptr)
return vfs->Stat(destPath,data);
return false;
}
void MountableFilesystem::Chmod(VFSPath path, uint32_t mode)
{
path = path.CollapseRelativeParents();
@@ -114,6 +129,32 @@ namespace Tesses::Framework::Filesystem
vfs->Chmod(destPath,mode);
}
void MountableFilesystem::Chown(VFSPath path, uint32_t uid, uint32_t gid)
{
path = path.CollapseRelativeParents();
VFSPath destRoot;
VFSPath destPath = path;
std::shared_ptr<VFS> vfs = root;
GetFS(path, destRoot, destPath, vfs);
if(vfs != nullptr)
vfs->Chown(destPath,uid, gid);
}
FIFOCreationResult MountableFilesystem::CreateFIFO(VFSPath path, uint32_t mod)
{
path = path.CollapseRelativeParents();
VFSPath destRoot;
VFSPath destPath = path;
std::shared_ptr<VFS> vfs = root;
GetFS(path, destRoot, destPath, vfs);
if(vfs != nullptr)
return vfs->CreateFIFO(destPath,mod);
return FIFOCreationResult::UnknownError;
}
std::shared_ptr<Tesses::Framework::Streams::Stream> MountableFilesystem::OpenFile(VFSPath path, std::string mode)
{
@@ -163,141 +204,9 @@ namespace Tesses::Framework::Filesystem
}
bool MountableFilesystem::SpecialFileExists(VFSPath path)
{
path = path.CollapseRelativeParents();
VFSPath destRoot;
VFSPath destPath = path;
std::shared_ptr<VFS> vfs = root;
GetFS(path, destRoot, destPath, vfs);
if(vfs != nullptr)
return vfs->SpecialFileExists(destPath);
return false;
}
bool MountableFilesystem::FileExists(VFSPath path)
{
path = path.CollapseRelativeParents();
VFSPath destRoot;
VFSPath destPath = path;
std::shared_ptr<VFS> vfs = root;
GetFS(path, destRoot, destPath, vfs);
if(vfs != nullptr)
return vfs->FileExists(destPath);
return false;
}
bool MountableFilesystem::RegularFileExists(VFSPath path)
{
path = path.CollapseRelativeParents();
VFSPath destRoot;
VFSPath destPath = path;
std::shared_ptr<VFS> vfs = root;
GetFS(path, destRoot, destPath, vfs);
if(vfs != nullptr)
return vfs->RegularFileExists(destPath);
return false;
}
bool MountableFilesystem::SymlinkExists(VFSPath path)
{
path = path.CollapseRelativeParents();
VFSPath destRoot;
VFSPath destPath = path;
std::shared_ptr<VFS> vfs = root;
GetFS(path, destRoot, destPath, vfs);
if(vfs != nullptr)
return vfs->SymlinkExists(destPath);
return false;
}
bool MountableFilesystem::CharacterDeviceExists(VFSPath path)
{
path = path.CollapseRelativeParents();
VFSPath destRoot;
VFSPath destPath = path;
std::shared_ptr<VFS> vfs = root;
GetFS(path, destRoot, destPath, vfs);
if(vfs != nullptr)
return vfs->CharacterDeviceExists(destPath);
return false;
}
bool MountableFilesystem::BlockDeviceExists(VFSPath path)
{
path = path.CollapseRelativeParents();
VFSPath destRoot;
VFSPath destPath = path;
std::shared_ptr<VFS> vfs = root;
GetFS(path, destRoot, destPath, vfs);
if(vfs != nullptr)
return vfs->BlockDeviceExists(destPath);
return false;
}
bool MountableFilesystem::SocketFileExists(VFSPath path)
{
path = path.CollapseRelativeParents();
VFSPath destRoot;
VFSPath destPath = path;
std::shared_ptr<VFS> vfs = root;
GetFS(path, destRoot, destPath, vfs);
if(vfs != nullptr)
return vfs->SocketFileExists(destPath);
return false;
}
bool MountableFilesystem::FIFOFileExists(VFSPath path)
{
path = path.CollapseRelativeParents();
VFSPath destRoot;
VFSPath destPath = path;
std::shared_ptr<VFS> vfs = root;
GetFS(path, destRoot, destPath, vfs);
if(vfs != nullptr)
return vfs->FIFOFileExists(destPath);
return false;
}
bool MountableFilesystem::DirectoryExists(VFSPath path)
{
path = path.CollapseRelativeParents();
VFSPath destRoot;
VFSPath destPath = path;
std::shared_ptr<VFS> vfs = root;
GetFS(path, destRoot, destPath, vfs);
if(destPath.path.empty()) return true;
if(vfs != nullptr)
return vfs->DirectoryExists(destPath);
return false;
}
void MountableFilesystem::DeleteFile(VFSPath path)
{
path = path.CollapseRelativeParents();
@@ -339,20 +248,6 @@ namespace Tesses::Framework::Filesystem
if(vfs != nullptr)
vfs->Unlock(destPath);
}
void MountableFilesystem::GetDate(VFSPath path, Date::DateTime& lastWrite, Date::DateTime& lastAccess)
{
path = path.CollapseRelativeParents();
VFSPath destRoot;
VFSPath destPath = path;
std::shared_ptr<VFS> vfs = root;
GetFS(path, destRoot, destPath, vfs);
if(vfs != nullptr)
vfs->GetDate(destPath,lastWrite,lastAccess);
}
void MountableFilesystem::SetDate(VFSPath path, Date::DateTime lastWrite, Date::DateTime lastAccess)
{

View File

@@ -6,33 +6,11 @@ namespace Tesses::Framework::Filesystem
{
return nullptr;
}
void NullFilesystem::CreateDirectory(VFSPath path)
{
}
void NullFilesystem::DeleteDirectory(VFSPath path)
{
}
bool NullFilesystem::RegularFileExists(VFSPath path)
{
return false;
}
bool NullFilesystem::DirectoryExists(VFSPath path)
{
return false;
}
void NullFilesystem::DeleteFile(VFSPath path)
{
}
VFSPathEnumerator NullFilesystem::EnumeratePaths(VFSPath path)
{
return VFSPathEnumerator();
}
void NullFilesystem::MoveFile(VFSPath src, VFSPath dest)
{
}
std::string NullFilesystem::VFSPathToSystem(VFSPath path)
{
@@ -42,4 +20,9 @@ namespace Tesses::Framework::Filesystem
{
return VFSPath(path);
}
bool NullFilesystem::Stat(VFSPath path, StatData& data)
{
return false;
}
}

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

@@ -55,34 +55,6 @@ namespace Tesses::Framework::Filesystem
{
this->parent->DeleteDirectory(ToParent(path));
}
bool SubdirFilesystem::RegularFileExists(VFSPath path)
{
return this->parent->RegularFileExists(ToParent(path));
}
bool SubdirFilesystem::SymlinkExists(VFSPath path)
{
return this->parent->SymlinkExists(ToParent(path));
}
bool SubdirFilesystem::CharacterDeviceExists(VFSPath path)
{
return this->parent->CharacterDeviceExists(ToParent(path));
}
bool SubdirFilesystem::BlockDeviceExists(VFSPath path)
{
return this->parent->BlockDeviceExists(ToParent(path));
}
bool SubdirFilesystem::SocketFileExists(VFSPath path)
{
return this->parent->SocketFileExists(ToParent(path));
}
bool SubdirFilesystem::FIFOFileExists(VFSPath path)
{
return this->parent->FIFOFileExists(ToParent(path));
}
bool SubdirFilesystem::DirectoryExists(VFSPath path)
{
return this->parent->DirectoryExists(ToParent(path));
}
void SubdirFilesystem::DeleteFile(VFSPath path)
{
this->parent->DeleteFile(ToParent(path));
@@ -105,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);
@@ -116,10 +88,7 @@ namespace Tesses::Framework::Filesystem
delete enumerator;
});
}
void SubdirFilesystem::GetDate(VFSPath path, Date::DateTime& lastWrite, Date::DateTime& lastAccess)
{
this->parent->GetDate(ToParent(path),lastWrite,lastAccess);
}
void SubdirFilesystem::SetDate(VFSPath path, Date::DateTime lastWrite, Date::DateTime lastAccess)
{
this->parent->SetDate(ToParent(path),lastWrite,lastAccess);
@@ -149,14 +118,7 @@ namespace Tesses::Framework::Filesystem
{
this->parent->DeleteDirectoryRecurse(ToParent(path));
}
bool SubdirFilesystem::SpecialFileExists(VFSPath path)
{
return this->parent->SpecialFileExists(ToParent(path));
}
bool SubdirFilesystem::FileExists(VFSPath path)
{
return this->parent->FileExists(ToParent(path));
}
SubdirFilesystem::~SubdirFilesystem()
{
@@ -166,10 +128,58 @@ namespace Tesses::Framework::Filesystem
{
return this->parent->StatVFS(ToParent(path), vfsData);
}
bool SubdirFilesystem::Stat(VFSPath path, StatData& data)
{
return this->parent->Stat(ToParent(path), data);
}
void SubdirFilesystem::Chmod(VFSPath path, uint32_t mode)
{
return this->parent->Chmod(ToParent(path), mode);
}
void SubdirFilesystem::Chown(VFSPath path, uint32_t uid, uint32_t gid)
{
return this->parent->Chown(ToParent(path), uid, gid);
}
FIFOCreationResult SubdirFilesystem::CreateFIFO(VFSPath path, uint32_t mod)
{
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

@@ -54,56 +54,7 @@ namespace Tesses::Framework::Filesystem {
if(this->vfs == nullptr) return;
this->vfs->DeleteDirectory(path);
}
bool TempFS::SpecialFileExists(VFSPath path)
{
if(this->vfs == nullptr) return false;
return this->vfs->SpecialFileExists(path);
}
bool TempFS::FileExists(VFSPath path)
{
if(this->vfs == nullptr) return false;
return this->vfs->FileExists(path);
}
bool TempFS::RegularFileExists(VFSPath path)
{
if(this->vfs == nullptr) return false;
return this->vfs->RegularFileExists(path);
}
bool TempFS::SymlinkExists(VFSPath path)
{
if(this->vfs == nullptr) return false;
return this->vfs->SymlinkExists(path);
}
bool TempFS::CharacterDeviceExists(VFSPath path)
{
if(this->vfs == nullptr) return false;
return this->vfs->CharacterDeviceExists(path);
}
bool TempFS::BlockDeviceExists(VFSPath path)
{
if(this->vfs == nullptr) return false;
return this->vfs->BlockDeviceExists(path);
}
bool TempFS::SocketFileExists(VFSPath path)
{
if(this->vfs == nullptr) return false;
return this->vfs->SocketFileExists(path);
}
bool TempFS::FIFOFileExists(VFSPath path)
{
if(this->vfs == nullptr) return false;
return this->vfs->FIFOFileExists(path);
}
bool TempFS::DirectoryExists(VFSPath path)
{
if(this->vfs == nullptr) return false;
return this->vfs->DirectoryExists(path);
}
void TempFS::DeleteFile(VFSPath path)
{
if(this->vfs == nullptr) return;
@@ -173,12 +124,6 @@ namespace Tesses::Framework::Filesystem {
return this->vfs->SystemToVFSPath(path);
}
void TempFS::GetDate(VFSPath path, Date::DateTime& lastWrite, Date::DateTime& lastAccess)
{
if(this->vfs == nullptr) return;
this->vfs->GetDate(path,lastWrite,lastAccess);
}
void TempFS::SetDate(VFSPath path, Date::DateTime lastWrite, Date::DateTime lastAccess)
{
@@ -191,6 +136,12 @@ namespace Tesses::Framework::Filesystem {
if(this->vfs == nullptr) return false;
return this->vfs->StatVFS(path, vfsData);
}
bool TempFS::Stat(VFSPath path, StatData& data)
{
if(this->vfs == nullptr) return false;
return this->vfs->Stat(path, data);
}
void TempFS::Chmod(VFSPath path, uint32_t mode)
{
@@ -198,6 +149,17 @@ namespace Tesses::Framework::Filesystem {
if(this->vfs == nullptr) return;
this->vfs->Chmod(path,mode);
}
void TempFS::Chown(VFSPath path, uint32_t uid, uint32_t gid)
{
if(this->vfs == nullptr) return;
this->vfs->Chown(path,uid, gid);
}
FIFOCreationResult TempFS::CreateFIFO(VFSPath path, uint32_t mod)
{
if(this->vfs == nullptr) return FIFOCreationResult::UnknownError;
return this->vfs->CreateFIFO(path, mod);
}
void TempFS::Close()
{
@@ -208,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

@@ -1,6 +1,7 @@
#include "TessesFramework/Filesystem/VFS.hpp"
#include "TessesFramework/Http/HttpUtils.hpp"
#include "TessesFramework/Filesystem/LocalFS.hpp"
#include <TessesFramework/Filesystem/FSHelpers.hpp>
namespace Tesses::Framework::Filesystem
{
VFSPathEnumeratorItterator::VFSPathEnumeratorItterator()
@@ -216,6 +217,91 @@ namespace Tesses::Framework::Filesystem
{
return MakeRelative(GetAbsoluteCurrentDirectory());
}
FIFOCreationResult VFS::CreateFIFO(VFSPath path, uint32_t mode)
{
return FIFOCreationResult::Unsupported;
}
bool VFS::DirectoryExists(VFSPath path)
{
StatData data;
if(this->Stat(path, data))
{
return data.IsDirectory();
}
return false;
}
bool VFS::RegularFileExists(VFSPath path)
{
StatData data;
if(this->Stat(path, data))
{
return data.IsRegularFile();
}
return false;
}
bool VFS::SymlinkExists(VFSPath path)
{
StatData data;
if(this->Stat(path, data))
{
return data.IsSymlink();
}
return false;
}
bool VFS::CharacterDeviceExists(VFSPath path)
{
StatData data;
if(this->Stat(path, data))
{
return data.IsCharDevice();
}
return false;
}
bool VFS::BlockDeviceExists(VFSPath path)
{
StatData data;
if(this->Stat(path, data))
{
return data.IsBlockDevice();
}
return false;
}
bool VFS::SocketFileExists(VFSPath path)
{
StatData data;
if(this->Stat(path, data))
{
return data.IsSocket();
}
return false;
}
bool VFS::FIFOFileExists(VFSPath path)
{
StatData data;
if(this->Stat(path, data))
{
return data.IsFIFO();
}
return false;
}
bool VFS::FileExists(VFSPath path)
{
StatData data;
if(this->Stat(path, data))
{
return !data.IsDirectory();
}
return false;
}
bool VFS::SpecialFileExists(VFSPath path)
{
StatData data;
if(this->Stat(path, data))
{
return data.IsSpecial();
}
return false;
}
VFSPath VFSPath::MakeRelative(VFSPath toMakeRelativeTo) const
{
@@ -418,6 +504,14 @@ namespace Tesses::Framework::Filesystem
if(!firstPartPath.empty() && firstPartPath.back() == ':') this->relative=false;
}
}
}
void VFS::CreateDirectory(VFSPath path)
{
}
void VFS::DeleteDirectory(VFSPath path)
{
}
VFSPath::VFSPath(VFSPath p1, VFSPath p2)
{
@@ -462,17 +556,27 @@ namespace Tesses::Framework::Filesystem
}
return p;
}
void VFS::DeleteFile(VFSPath path)
{
}
void VFS::MoveFile(VFSPath src, VFSPath dest)
{
{
auto srcStrm = this->OpenFile(src, "rb");
if(!srcStrm->CanRead()) return;
auto destStrm = this->OpenFile(dest, "wb");
if(!destStrm->CanWrite()) return;
srcStrm->CopyTo(destStrm);
}
VFS::DeleteFile(src);
}
VFS::~VFS()
{
}
bool VFS::FIFOFileExists(VFSPath path) {return false;}
bool VFS::SocketFileExists(VFSPath path) {return false;}
bool VFS::CharacterDeviceExists(VFSPath path) {return false;}
bool VFS::BlockDeviceExists(VFSPath path) {return false;}
bool VFS::SymlinkExists(VFSPath path) {return false;}
void VFS::MoveDirectory(VFSPath src, VFSPath dest)
{
@@ -499,14 +603,6 @@ namespace Tesses::Framework::Filesystem
}
bool VFS::SpecialFileExists(VFSPath path)
{
return SymlinkExists(path) || BlockDeviceExists(path) || CharacterDeviceExists(path) || SocketFileExists(path) || FIFOFileExists(path);
}
bool VFS::FileExists(VFSPath path)
{
return RegularFileExists(path) || SpecialFileExists(path);
}
void VFS::DeleteDirectoryRecurse(VFSPath path)
{
@@ -527,7 +623,12 @@ namespace Tesses::Framework::Filesystem
}
void VFS::GetDate(VFSPath path, Date::DateTime& lastWrite, Date::DateTime& lastAccess)
{
StatData data;
if(Stat(path, data))
{
lastWrite = data.LastModified;
lastAccess = data.LastAccess;
}
}
void VFS::SetDate(VFSPath path, Date::DateTime lastWrite, Date::DateTime lastAccess)
{
@@ -550,6 +651,9 @@ namespace Tesses::Framework::Filesystem
}
void VFS::Chmod(VFSPath path, uint32_t mode) {
}
void VFS::Chown(VFSPath path, uint32_t uid, uint32_t gid) {
}
void VFS::Close() {

View File

@@ -73,7 +73,7 @@ namespace Tesses::Framework::Http
std::string p = HttpUtils::HtmlEncode(ctx.originalPath);
std::string html = "<!DOCTYPE html><html><head><meta charset=\"UTF-8\"><title>Index of ";
html.append(p);
html.append("</title></head><body><h1>Index of ");
html.append("</title><meta name=\"color-scheme\" content=\"dark light\"></head><body><h1>Index of ");
html.append(p);
html.append("</h1><hr><pre><a href=\"../\">../</a>\r\n");

View File

@@ -13,6 +13,7 @@
#include "TessesFramework/Filesystem/VFSFix.hpp"
#include "TessesFramework/Filesystem/VFS.hpp"
#include <TessesFramework/Http/HttpUtils.hpp>
#include <iostream>
using FileStream = Tesses::Framework::Streams::FileStream;
using Stream = Tesses::Framework::Streams::Stream;
@@ -26,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:
@@ -281,6 +355,7 @@ namespace Tesses::Framework::Http
this->conn->OnClose(false);
}
};
/*
static int _header_field(multipart_parser* p, const char *at, size_t length)
{
@@ -343,6 +418,7 @@ namespace Tesses::Framework::Http
data->currentHeaders.Clear();
return 0;
}*/
std::string ServerContext::GetUrlWithQuery()
{
if(this->queryParams.kvp.empty()) return this->path;
@@ -363,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 {};
@@ -389,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;
@@ -454,8 +558,6 @@ namespace Tesses::Framework::Http
{
dest->Write(buffer,offsetInMem);
}
delete[] checkBuffer;
return hasMore;
}
@@ -523,7 +625,7 @@ namespace Tesses::Framework::Http
while(parseSection(this, ct, cb));
}
HttpServer::HttpServer(std::shared_ptr<Tesses::Framework::Streams::TcpServer> tcpServer, std::shared_ptr<IHttpServer> http, bool showIPs)
HttpServer::HttpServer(std::shared_ptr<Tesses::Framework::Streams::TcpServer> tcpServer, std::shared_ptr<IHttpServer> http, bool showIPs, bool debug)
{
this->server = tcpServer;
this->http = http;
@@ -531,15 +633,16 @@ namespace Tesses::Framework::Http
this->showIPs = showIPs;
this->thrd=nullptr;
this->showARTL = showIPs;
this->debug = debug;
}
HttpServer::HttpServer(uint16_t port, std::shared_ptr<IHttpServer> http, bool showIPs) : HttpServer(std::make_shared<TcpServer>(port,10),http,showIPs)
HttpServer::HttpServer(uint16_t port, std::shared_ptr<IHttpServer> http, bool showIPs, bool debug) : HttpServer(std::make_shared<TcpServer>(port,10),http,showIPs, debug)
{
}
HttpServer::HttpServer(std::string unixPath, std::shared_ptr<IHttpServer> http) : HttpServer(std::make_shared<TcpServer>(unixPath,10),http,false)
HttpServer::HttpServer(std::string unixPath, std::shared_ptr<IHttpServer> http, bool debug) : HttpServer(std::make_shared<TcpServer>(unixPath,10),http,false, debug)
{
this->showARTL=true;
}
@@ -584,7 +687,8 @@ namespace Tesses::Framework::Http
auto serverPort = this->server->GetPort();
auto http = this->http;
TF_LOG("Before Creating Thread");
thrd = new Threading::Thread([svr,http,serverPort]()->void {
bool debug = this->debug;
thrd = new Threading::Thread([svr,http,serverPort,debug]()->void {
while(TF_IsRunning())
{
TF_LOG("after TF_IsRunning");
@@ -600,9 +704,10 @@ namespace Tesses::Framework::Http
return;
}
TF_LOG("Before entering socket thread");
Threading::Thread thrd2([sock,http,ip,port,serverPort]()->void {
Threading::Thread thrd2([sock,http,ip,port,serverPort,debug]()->void {
TF_LOG("In thread to process");
HttpServer::Process(sock,http,ip,port,serverPort,false);
HttpServer::Process(sock,http,ip,port,serverPort,false, debug);
TF_LOG("In thread after process");
});
@@ -650,12 +755,14 @@ namespace Tesses::Framework::Http
{
}
ServerContext::ServerContext(std::shared_ptr<Stream> strm)
ServerContext::ServerContext(std::shared_ptr<Stream> strm, bool debug)
{
this->statusCode = OK;
this->strm = strm;
this->debug = debug;
this->sent = false;
this->queryParams.SetCaseSensitive(true);
this->pathArguments.SetCaseSensitive(true);
this->responseHeaders.AddValue("Server","TessesFrameworkWebServer");
}
std::shared_ptr<Stream> ServerContext::GetStream()
@@ -685,7 +792,9 @@ namespace Tesses::Framework::Http
void ServerContext::SendErrorPage(bool showPath)
{
if(sent) return;
std::string errorHtml = showPath ? ("<html><head><title>File " + HttpUtils::HtmlEncode(this->originalPath) + " " + HttpUtils::StatusCodeString(this->statusCode) + "</title></head><body><h1>" + std::to_string((int)this->statusCode) + " " + HttpUtils::StatusCodeString(this->statusCode) + "</h1><h4>" + HttpUtils::HtmlEncode(this->originalPath) + "</h4></body></html>") : "";
std::string errorHtml = showPath ? ("<html><head><title>File " + HttpUtils::HtmlEncode(this->originalPath) + " " + HttpUtils::StatusCodeString(this->statusCode) + "</title><meta name=\"color-scheme\" content=\"dark light\"></head><body><h1>" + std::to_string((int)this->statusCode) + " " + HttpUtils::StatusCodeString(this->statusCode) + "</h1><h4>" + HttpUtils::HtmlEncode(this->originalPath) + "</h4></body></html>") : (
"<html><head><title>" + std::to_string(this->statusCode) + " " + HttpUtils::StatusCodeString(this->statusCode) + "</title><meta name=\"color-scheme\" content=\"dark light\"></head><body><h1>" + std::to_string((int)this->statusCode) + " " + HttpUtils::StatusCodeString(this->statusCode) + "</h1></body></html>"
);
WithMimeType("text/html").SendText(errorHtml);
}
@@ -900,24 +1009,40 @@ namespace Tesses::Framework::Http
statusCode = StatusCode::BadRequest;
SendErrorPage(false);
}
ServerContext& ServerContext::WithStatusCode(StatusCode code)
{
this->statusCode = code;
return *this;
}
void ServerContext::SendException(std::exception& ex)
{
/*<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Internal Server Error at /</title>
</head>
<body>
<h1>Internal Server Error at /</h1>
<p>what(): std::exception</p>
</body>
</html>*/
this->WithMimeType("text/html").SendText("<!DOCTYPE html><html lang=\"en\"><head><meta charset=\"UTF-8\"> <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"><title>Internal Server Error at " + HttpUtils::HtmlEncode(this->originalPath) + "</title></head><body><h1>Internal Server Error at " + HttpUtils::HtmlEncode(this->originalPath) + "</h1><p>what(): " + HttpUtils::HtmlEncode(ex.what()) + "</p></body></html>");
if(this->debug)
{
this->WithMimeType("text/html").WithStatusCode(StatusCode::InternalServerError).SendText("<!DOCTYPE html><html lang=\"en\"><head><meta charset=\"UTF-8\"> <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"><title>Internal Server Error at " + HttpUtils::HtmlEncode(this->originalPath) + "</title><meta name=\"color-scheme\" content=\"dark light\"></head><body><h1>Internal Server Error at " + HttpUtils::HtmlEncode(this->originalPath) + "</h1><p>what(): " + HttpUtils::HtmlEncode(ex.what()) + "</p></body></html>");
}
else {
this->WithStatusCode(StatusCode::InternalServerError).SendErrorPage(true);
}
}
ServerContext& ServerContext::WithHeaderIntercepter(std::function<bool(ServerContext&)> cb)
{
this->headerhandlers.push(cb);
return *this;
}
ServerContext& ServerContext::WriteHeaders()
{
if(this->sent) return *this;
while(!this->headerhandlers.empty())
{
auto header = this->headerhandlers.front();
this->headerhandlers.pop();
if(header(*this)) {
break;
}
}
if(this->sent) return *this;
this->sent = true;
@@ -936,11 +1061,9 @@ namespace Tesses::Framework::Http
return *this;
}
void HttpServer::Process(std::shared_ptr<Stream> strm, std::shared_ptr<IHttpServer> server, std::string ip, uint16_t port,uint16_t serverPort, bool encrypted)
void HttpServer::Process(std::shared_ptr<Stream> strm, std::shared_ptr<IHttpServer> server, std::string ip, uint16_t port,uint16_t serverPort, bool encrypted, bool debug)
{
TF_LOG("In process");
while(true)
{
std::shared_ptr<BufferedStream> bStrm = std::make_shared<BufferedStream>(strm);
StreamReader reader(bStrm);
ServerContext ctx(bStrm);
@@ -1003,16 +1126,18 @@ 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);
}
if(!server->Handle(ctx))
{
if((int)ctx.statusCode < 400)
ctx.SendNotFound();
else
ctx.SendErrorPage(true);
}
}
@@ -1036,23 +1161,20 @@ namespace Tesses::Framework::Http
ctx.SendException(ex);
}
if(ctx.version != "HTTP/1.1" ) return;
std::string connection;
if(ctx.requestHeaders.TryGetFirst("Connection", connection))
}
bool ServerContext::Debug()
{
if(HttpUtils::ToLower(connection) != "keep-alive") return;
return this->debug;
}
if(ctx.responseHeaders.TryGetFirst("Connection", connection))
ServerContext& ServerContext::WithDebug(bool debug)
{
if(HttpUtils::ToLower(connection) != "keep-alive") return;
}
if(bStrm->EndOfStream()) {
return;
}
}
this->debug = debug;
return *this;
}
WebSocketConnection::~WebSocketConnection()
@@ -1105,4 +1227,3 @@ namespace Tesses::Framework::Http
}

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

@@ -198,6 +198,19 @@ namespace Tesses::Framework::Http {
strm << std::setfill(c) << std::setw(count) << text;
return strm.str();
}
char HttpUtils::NibbleToHex(uint8_t b, bool isUppercase)
{
if(isUppercase)
{
b %= 16;
if(b >= 0 && b <= 9)
return b + '0';
if(b >= 10 && b <= 15)
return b + ('A' - 10);
return 0;
}
return NibbleToHex(b);
}
char HttpUtils::NibbleToHex(uint8_t b)
{
b %= 16;
@@ -971,6 +984,12 @@ namespace Tesses::Framework::Http {
BytesToHex(text,data);
return text;
}
std::string HttpUtils::BytesToHex(const std::vector<uint8_t>& data, bool isUpper)
{
std::string text;
BytesToHex(text,data, isUpper);
return text;
}
void HttpUtils::BytesToHex(std::string& text,const std::vector<uint8_t>& data)
{
if(data.empty()) {
@@ -984,6 +1003,20 @@ namespace Tesses::Framework::Http {
text[i*2+1] += NibbleToHex(data[i]);
}
}
void HttpUtils::BytesToHex(std::string& text,const std::vector<uint8_t>& data, bool isUpper)
{
if(data.empty()) {
text.clear();
return;
}
text.resize(data.size()*2);
for(size_t i = 0; i < data.size(); i++)
{
text[i*2] = NibbleToHex(data[i] >> 4, isUpper);
text[i*2+1] += NibbleToHex(data[i], isUpper);
}
}
std::vector<uint8_t> HttpUtils::HexToBytes(const std::string& text)
{
std::vector<uint8_t> data;

View File

@@ -4,16 +4,40 @@ namespace Tesses::Framework::Serialization
{
double BitConverter::ToDoubleBits(uint64_t v)
{
return *(double*)&v;
static_assert(sizeof(double) == sizeof(uint64_t), "double is not the same size as uint64_t");
double dest=0;
memcpy(&dest,&v, sizeof(uint64_t));
return dest;
}
uint64_t BitConverter::ToUintBits(double v)
{
return *(uint64_t*)&v;
//as static_assert is compile time we don't need it here
uint64_t dest = 0;
memcpy(&dest,&v, sizeof(uint64_t));
return dest;
}
float BitConverter::ToFloatBits(uint32_t v)
{
static_assert(sizeof(float) == sizeof(uint32_t), "float is not the same size as uint32_t");
float dest=0;
memcpy(&dest,&v, sizeof(uint32_t));
return dest;
}
uint32_t BitConverter::ToUint32Bits(float v)
{
//as static_assert is compile time we don't need it here
uint32_t dest = 0;
memcpy(&dest,&v, sizeof(uint32_t));
return dest;
}
double BitConverter::ToDoubleBE(uint8_t& b)
{
return ToDoubleBits(ToUint64BE(b));
}
float BitConverter::ToFloatBE(uint8_t& b)
{
return ToFloatBits(ToUint32BE(b));
}
uint64_t BitConverter::ToUint64BE(uint8_t& b)
{
uint8_t* b2 = &b;
@@ -49,6 +73,50 @@ namespace Tesses::Framework::Serialization
v |= (uint16_t)b2[1];
return v;
}
double BitConverter::ToDoubleLE(uint8_t& b)
{
return ToDoubleBits(ToUint64LE(b));
}
float BitConverter::ToFloatLE(uint8_t& b)
{
return ToFloatBits(ToUint32LE(b));
}
uint64_t BitConverter::ToUint64LE(uint8_t& b)
{
uint8_t* b2 = &b;
uint64_t v = 0;
v |= (uint64_t)b2[0];
v |= ((uint64_t)b2[1] << 8);
v |= ((uint64_t)b2[2] << 16);
v |= ((uint64_t)b2[3] << 24);
v |= ((uint64_t)b2[4] << 32);
v |= ((uint64_t)b2[5] << 40);
v |= ((uint64_t)b2[6] << 48);
v |= ((uint64_t)b2[7] << 56);
return v;
}
uint32_t BitConverter::ToUint32LE(uint8_t& b)
{
uint8_t* b2 = &b;
uint32_t v = 0;
v |= (uint32_t)b2[0];
v |= ((uint32_t)b2[1] << 8);
v |= ((uint32_t)b2[2] << 16);
v |= ((uint32_t)b2[3] << 24);
return v;
}
uint16_t BitConverter::ToUint16LE(uint8_t& b)
{
uint8_t* b2 = &b;
uint16_t v = 0;
v |= (uint16_t)b2[0];
v |= ((uint16_t)b2[1] << 8);
return v;
}
void BitConverter::FromDoubleBE(uint8_t& b, double v)
{
FromUint64BE(b,ToUintBits(v));
@@ -82,4 +150,170 @@ namespace Tesses::Framework::Serialization
b2[1] = (uint8_t)v;
}
};
void BitConverter::FromDoubleLE(uint8_t& b, double v)
{
FromUint64BE(b,ToUintBits(v));
}
void BitConverter::FromFloatLE(uint8_t& b, float v)
{
FromUint32LE(b,ToUint32Bits(v));
}
void BitConverter::FromFloatBE(uint8_t& b, float v)
{
FromUint32BE(b,ToUint32Bits(v));
}
void BitConverter::FromUint64LE(uint8_t& b, uint64_t v)
{
uint8_t* b2 = &b;
b2[0] = (uint8_t)v;
b2[1] = (uint8_t)(v >> 8);
b2[2] = (uint8_t)(v >> 16);
b2[3] = (uint8_t)(v >> 24);
b2[4] = (uint8_t)(v >> 32);
b2[5] = (uint8_t)(v >> 40);
b2[6] = (uint8_t)(v >> 48);
b2[7] = (uint8_t)(v >> 56);
}
void BitConverter::FromUint32LE(uint8_t& b, uint32_t v)
{
uint8_t* b2 = &b;
b2[0] = (uint8_t)v;
b2[1] = (uint8_t)(v >> 8);
b2[2] = (uint8_t)(v >> 16);
b2[3] = (uint8_t)(v >> 24);
}
void BitConverter::FromUint16LE(uint8_t& b, uint16_t v)
{
uint8_t* b2 = &b;
b2[0] = (uint8_t)v;
b2[1] = (uint8_t)(v >> 8);
}
void BitConverter::FromUuid(uint8_t& b, const Uuid& uuid)
{
uint8_t* b2 = &b;
FromUint32BE(b2[0], uuid.time_low);
FromUint16BE(b2[4], uuid.time_mid);
FromUint16BE(b2[6], uuid.time_hi_and_version);
b2[8] = uuid.clock_seq_hi_and_reserved;
b2[9] = uuid.clock_seq_low;
for(size_t i = 0; i < 6; i++)
b2[i+10] = uuid.node[i];
}
Uuid BitConverter::ToUuid(uint8_t& b)
{
Uuid uuid;
BitConverter::ToUuid(b,uuid);
return uuid;
}
void BitConverter::ToUuid(uint8_t& b, Uuid& uuid)
{
uint8_t* b2 = &b;
uuid.time_low = ToUint32BE(b2[0]);
uuid.time_mid = ToUint16BE(b2[4]);
uuid.time_hi_and_version = ToUint16BE(b2[6]);
uuid.clock_seq_hi_and_reserved = b2[8];
uuid.clock_seq_low = b2[9];
for(size_t i = 0; i < 6; i++)
uuid.node[i]= b2[i+10];
}
int64_t BitConverter::ToSint64BE(uint8_t& b)
{
uint64_t src = ToUint64BE(b);
int64_t dest = 0;
memcpy(&dest,&src,sizeof(uint64_t));
return dest;
}
int64_t BitConverter::ToSint64LE(uint8_t& b)
{
uint64_t src = ToUint64LE(b);
int64_t dest = 0;
memcpy(&dest,&src,sizeof(uint64_t));
return dest;
}
int32_t BitConverter::ToSint32BE(uint8_t& b)
{
uint32_t src = ToUint32BE(b);
int32_t dest = 0;
memcpy(&dest,&src,sizeof(uint32_t));
return dest;
}
int32_t BitConverter::ToSint32LE(uint8_t& b)
{
uint32_t src = ToUint32LE(b);
int32_t dest = 0;
memcpy(&dest,&src,sizeof(uint32_t));
return dest;
}
int16_t BitConverter::ToSint16BE(uint8_t& b)
{
uint16_t src = ToUint16BE(b);
int16_t dest = 0;
memcpy(&dest,&src,sizeof(uint16_t));
return dest;
}
int16_t BitConverter::ToSint16LE(uint8_t& b)
{
uint16_t src = ToUint16LE(b);
int16_t dest = 0;
memcpy(&dest,&src,sizeof(uint16_t));
return dest;
}
void BitConverter::FromSint64BE(uint8_t& b, int64_t v)
{
uint64_t dest = 0;
memcpy(&dest,&v,sizeof(uint64_t));
FromUint64BE(b, dest);
}
void BitConverter::FromSint32BE(uint8_t& b, int32_t v)
{
uint32_t dest = 0;
memcpy(&dest,&v,sizeof(uint32_t));
FromUint32BE(b, dest);
}
void BitConverter::FromSint16BE(uint8_t& b, int16_t v)
{
uint16_t dest = 0;
memcpy(&dest,&v,sizeof(uint16_t));
FromUint16BE(b, dest);
}
void BitConverter::FromSint64LE(uint8_t& b, int64_t v)
{
uint64_t dest = 0;
memcpy(&dest,&v,sizeof(uint64_t));
FromUint64LE(b, dest);
}
void BitConverter::FromSint32LE(uint8_t& b, int32_t v)
{
uint32_t dest = 0;
memcpy(&dest,&v,sizeof(uint32_t));
FromUint32LE(b, dest);
}
void BitConverter::FromSint16LE(uint8_t& b, int16_t v)
{
uint16_t dest = 0;
memcpy(&dest,&v,sizeof(uint16_t));
FromUint16LE(b, dest);
}
}

View File

@@ -1,4 +1,5 @@
#include "TessesFramework/Streams/ByteReader.hpp"
#include "TessesFramework/Serialization/BitConverter.hpp"
namespace Tesses::Framework::Streams
{
std::shared_ptr<Stream> ByteReader::GetStream()
@@ -150,4 +151,19 @@ namespace Tesses::Framework::Streams
return *(double*)&v;
}
Uuid ByteReader::ReadUuid()
{
uint8_t data[16];
if(this->strm->ReadBlock(data, 16) != 16)
throw std::runtime_error("End of file");
return Serialization::BitConverter::ToUuid(data[0]);
}
void ByteReader::ReadUuid(Uuid& uuid)
{
uint8_t data[16];
if(this->strm->ReadBlock(data, 16) != 16)
throw std::runtime_error("End of file");
Serialization::BitConverter::ToUuid(data[0],uuid);
}
}

View File

@@ -1,4 +1,5 @@
#include "TessesFramework/Streams/ByteWriter.hpp"
#include "TessesFramework/Serialization/BitConverter.hpp"
namespace Tesses::Framework::Streams
{
std::shared_ptr<Stream> ByteWriter::GetStream()
@@ -129,5 +130,11 @@ namespace Tesses::Framework::Streams
uint64_t data = *(uint64_t*)&v;
WriteU64LE(data);
}
void ByteWriter::WriteUuid(const Uuid& uuid)
{
uint8_t data[16];
Serialization::BitConverter::FromUuid(data[0], uuid);
this->strm->WriteBlock(data, 16);
}
}

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

@@ -6,9 +6,13 @@
#include "TessesFramework/Filesystem/FSHelpers.hpp"
#include "TessesFramework/Serialization/Json.hpp"
#include <atomic>
#include <chrono>
#include <csignal>
#include <functional>
#include <iostream>
#include <memory>
#include <queue>
#include <ratio>
#if defined(TESSESFRAMEWORK_ENABLE_SQLITE)
extern "C" {
@@ -49,11 +53,13 @@ static GXRModeObj *rmode = NULL;
#endif
#if !defined(_WIN32)
#include <unistd.h>
#endif
namespace Tesses::Framework
{
EventList<uint64_t> OnItteraton;
#if defined(TESSESFRAMEWORK_ENABLE_THREADING) && (defined(GEKKO) || defined(__SWITCH__))
namespace Threading
{
@@ -66,6 +72,7 @@ namespace Tesses::Framework
volatile static std::atomic<bool> gaming_console_events=true;
#if defined(TESSESFRAMEWORK_ENABLE_THREADING)
Threading::Mutex timers_mtx;
Threading::Mutex invokings_mtx;
std::queue<std::function<void()>> invokings;
@@ -82,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);
@@ -109,10 +128,136 @@ namespace Tesses::Framework
PadState default_pad;
#endif
uint64_t ittr=0;
void TF_RunEventLoopItteration()
static std::shared_ptr<TF_Timer_Handler> timer_handler = std::make_shared<TF_Timer_Handler>();
std::shared_ptr<TF_Timer_Handle> TF_Timer_Handler::Make(std::shared_ptr<TF_Timer_Handler> handler)
{
auto timer = new TF_Timer_Handle(handler);
std::shared_ptr<TF_Timer_Handle> handle(timer);
#if defined(TESSESFRAMEWORK_ENABLE_THREADING)
timers_mtx.Lock();
#endif
handler->handles.push_back(handle);
#if defined(TESSESFRAMEWORK_ENABLE_THREADING)
timers_mtx.Unlock();
#endif
return handle;
}
std::shared_ptr<TF_Timer_Handle> TF_Timer()
{
return TF_Timer_Handler::Make(timer_handler);
}
std::shared_ptr<TF_Timer_Handle> TF_Timer(std::function<void()> cb, int64_t interval, bool enabled)
{
auto handle = TF_Timer();
handle->SetCallback(cb);
handle->SetIntervalFromMilliseconds(interval);
handle->SetEnabled(enabled);
return handle;
}
std::shared_ptr<TF_Timer_Handle> TF_Timer(std::function<void()> cb, std::chrono::duration<int64_t,std::milli> interval, bool enabled)
{
auto handle = TF_Timer();
handle->SetCallback(cb);
handle->SetIntervalFromDuration(interval);
handle->SetEnabled(enabled);
return handle;
}
void TF_Timer_Handler::Update()
{
std::chrono::time_point<std::chrono::steady_clock,std::chrono::milliseconds> cur = std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now());
std::vector<std::function<void()>> cbs;
#if defined(TESSESFRAMEWORK_ENABLE_THREADING)
timers_mtx.Lock();
#endif
for(auto index = this->handles.begin(); index != this->handles.end(); index++)
{
if(index->expired())
{
this->handles.erase(index);
index--;
}
else {
auto handle = index->lock();
if(handle && handle->enabled && (handle->last + handle->interval) <= cur && handle->cb)
{
handle->last = cur;
cbs.push_back(handle->cb);
}
}
}
#if defined(TESSESFRAMEWORK_ENABLE_THREADING)
timers_mtx.Unlock();
#endif
for(auto item : cbs)
{
item();
}
}
void TF_Timer_Handle::SetCallback(std::function<void()> cb)
{
#if defined(TESSESFRAMEWORK_ENABLE_THREADING)
timers_mtx.Lock();
#endif
this->cb = cb;
#if defined(TESSESFRAMEWORK_ENABLE_THREADING)
timers_mtx.Unlock();
#endif
}
TF_Timer_Handle::TF_Timer_Handle(std::shared_ptr<TF_Timer_Handler> handler) : timerHandler(handler)
{
OnItteraton.Invoke(ittr++);
}
void TF_Timer_Handle::SetEnabled(bool enabled)
{
#if defined(TESSESFRAMEWORK_ENABLE_THREADING)
timers_mtx.Lock();
#endif
this->enabled = enabled;
#if defined(TESSESFRAMEWORK_ENABLE_THREADING)
timers_mtx.Unlock();
#endif
}
bool TF_Timer_Handle::GetEnabled()
{
return this->enabled;
}
void TF_Timer_Handle::SetIntervalFromDuration(std::chrono::milliseconds ms)
{
#if defined(TESSESFRAMEWORK_ENABLE_THREADING)
timers_mtx.Lock();
#endif
this->interval = ms;
#if defined(TESSESFRAMEWORK_ENABLE_THREADING)
timers_mtx.Unlock();
#endif
}
void TF_Timer_Handle::SetIntervalFromMilliseconds(int64_t ms)
{
SetIntervalFromDuration(std::chrono::milliseconds(ms));
}
std::chrono::duration<int64_t,std::milli> TF_Timer_Handle::GetIntervalDuration()
{
return this->interval;
}
int64_t TF_Timer_Handle::GetIntervalMilliseconds()
{
return this->interval.count();
}
void TF_RunEventLoopItteration()
{
#if defined(TESSESFRAMEWORK_ENABLE_THREADING) && (defined(GEKKO) || defined(__SWITCH__))
Tesses::Framework::Threading::LookForFinishedThreads();
@@ -165,6 +310,8 @@ namespace Tesses::Framework
#endif
timer_handler->Update();
}
void TF_SetIsRunning(bool _isRunning)
{

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

214
src/Uuid.cpp Normal file
View File

@@ -0,0 +1,214 @@
#include "TessesFramework/Uuid.hpp"
#include "TessesFramework/Http/HttpUtils.hpp"
#include "TessesFramework/Crypto/Crypto.hpp"
namespace Tesses::Framework {
Uuid Uuid::Generate()
{
//xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx
Uuid uuid;
Uuid::Generate(uuid);
return uuid;
}
void Uuid::Generate(Uuid& uuid)
{
std::vector<uint8_t> bytes(16);
Crypto::RandomBytes(bytes, "TF_UUID");
uuid.time_low = (uint32_t)bytes[0];
uuid.time_low |= (uint32_t)bytes[1] << 8;
uuid.time_low |= (uint32_t)bytes[2] << 16;
uuid.time_low |= (uint32_t)bytes[3] << 24;
uuid.time_mid = (uint16_t)bytes[4];
uuid.time_mid |= (uint16_t)bytes[5] << 8;
uuid.time_hi_and_version = (uint16_t)bytes[6];
uuid.time_hi_and_version |= (uint16_t)bytes[7] << 8;
uuid.clock_seq_hi_and_reserved = bytes[8];
uuid.clock_seq_low = bytes[9];
for(size_t i = 0; i < 6; i++)
{
uuid.node[i] = bytes[i+10];
}
uuid.time_hi_and_version &= ~0x00F0;
uuid.time_hi_and_version |= 0x0040;
uuid.clock_seq_hi_and_reserved &= ~0b11000000;
uuid.clock_seq_hi_and_reserved |= 0b10000000;
}
bool Uuid::TryParse(std::string text, Uuid& uuid)
{
std::array<uint8_t,32> hex_digits;
size_t hex_offset = 0;
size_t text_offset = 0;
for(; text_offset < text.size(); text_offset++)
{
if(text[text_offset] == '{' && (text_offset != 0 || hex_offset != 0))
return false;
if(text[text_offset] == '}' && hex_offset < 32)
return false;
if(text[text_offset] == '-' && hex_offset != 8 && hex_offset != 12 && hex_offset != 16 && hex_offset != 20)
return false;
if((text[text_offset] >= 'A' && text[text_offset] <= 'F') || (text[text_offset] >= 'a' && text[text_offset] <= 'f') || text[text_offset] >= '0' && text[text_offset] <= '9')
{
if(hex_offset >= 32) return false;
hex_digits[hex_offset] = Http::HttpUtils::HexToNibble(text[text_offset]);
hex_offset++;
}
else return false;
}
uint8_t b = hex_digits[0] << 4 | hex_digits[1];
uuid.time_low = (uint32_t)b;
b = hex_digits[2] << 4 | hex_digits[3];
uuid.time_low |= (uint32_t)b << 8;
b = hex_digits[4] << 4 | hex_digits[5];
uuid.time_low |= (uint32_t)b << 16;
b = hex_digits[6] << 4 | hex_digits[7];
uuid.time_low |= (uint32_t)b << 24;
b = hex_digits[8] << 4 | hex_digits[9];
uuid.time_mid = (uint16_t)b;
b = hex_digits[10] << 4 | hex_digits[11];
uuid.time_mid |= (uint16_t)b << 8;
b = hex_digits[12] << 4 | hex_digits[13];
uuid.time_hi_and_version = (uint16_t)b;
b = hex_digits[14] << 4 | hex_digits[15];
uuid.time_hi_and_version |= (uint16_t)b << 8;
uuid.clock_seq_hi_and_reserved = hex_digits[16] << 4 | hex_digits[17];
uuid.clock_seq_low = hex_digits[18] << 4 | hex_digits[19];
for(size_t i = 0; i < 6; i++)
{
uuid.node[i] = hex_digits[20+(i*2)] << 4 | hex_digits[21+(i*2)];
}
return true;
}
//9c4994e7-3c82-4c30-a459-8fdcd960b4ac
std::string Uuid::ToString(UuidStringifyConfig cfg) const
{
bool hasCurly = ((int)cfg & (int)UuidStringifyConfig::HasCurly) != 0;
bool isUppercase = ((int)cfg & (int)UuidStringifyConfig::IsUppercase) != 0;
bool hasDash = ((int)cfg & (int)UuidStringifyConfig::HasDashes) != 0;
std::string uuid_str = "";
if(hasCurly)
uuid_str += "{";
uint8_t byte = (uint8_t)(this->time_low & 0xFF);
uuid_str += Http::HttpUtils::NibbleToHex(byte>>4,isUppercase);
uuid_str += Http::HttpUtils::NibbleToHex(byte,isUppercase);
byte = (uint8_t)((this->time_low >> 8) & 0xFF);
uuid_str += Http::HttpUtils::NibbleToHex(byte>>4,isUppercase);
uuid_str += Http::HttpUtils::NibbleToHex(byte,isUppercase);
byte = (uint8_t)((this->time_low >> 16) & 0xFF);
uuid_str += Http::HttpUtils::NibbleToHex(byte>>4,isUppercase);
uuid_str += Http::HttpUtils::NibbleToHex(byte,isUppercase);
byte = (uint8_t)((this->time_low >> 24) & 0xFF);
uuid_str += Http::HttpUtils::NibbleToHex(byte>>4,isUppercase);
uuid_str += Http::HttpUtils::NibbleToHex(byte,isUppercase);
if(hasDash)
uuid_str += "-";
byte = (uint8_t)(this->time_mid & 0xFF);
uuid_str += Http::HttpUtils::NibbleToHex(byte>>4,isUppercase);
uuid_str += Http::HttpUtils::NibbleToHex(byte,isUppercase);
byte = (uint8_t)((this->time_mid >> 8) & 0xFF);
uuid_str += Http::HttpUtils::NibbleToHex(byte>>4,isUppercase);
uuid_str += Http::HttpUtils::NibbleToHex(byte,isUppercase);
if(hasDash)
uuid_str += "-";
byte = (uint8_t)(this->time_hi_and_version & 0xFF);
uuid_str += Http::HttpUtils::NibbleToHex(byte>>4,isUppercase);
uuid_str += Http::HttpUtils::NibbleToHex(byte,isUppercase);
byte = (uint8_t)((this->time_hi_and_version >> 8) & 0xFF);
uuid_str += Http::HttpUtils::NibbleToHex(byte>>4,isUppercase);
uuid_str += Http::HttpUtils::NibbleToHex(byte,isUppercase);
if(hasDash)
uuid_str += "-";
uuid_str += Http::HttpUtils::NibbleToHex(this->clock_seq_hi_and_reserved>>4,isUppercase);
uuid_str += Http::HttpUtils::NibbleToHex(this->clock_seq_hi_and_reserved,isUppercase);
uuid_str += Http::HttpUtils::NibbleToHex(this->clock_seq_low>>4,isUppercase);
uuid_str += Http::HttpUtils::NibbleToHex(this->clock_seq_low,isUppercase);
if(hasDash)
uuid_str += "-";
for(size_t i = 0; i < 6; i++)
{
byte = this->node[i];
uuid_str += Http::HttpUtils::NibbleToHex(byte>>4,isUppercase);
uuid_str += Http::HttpUtils::NibbleToHex(byte,isUppercase);
}
if(hasCurly)
uuid_str += "}";
return uuid_str;
}
bool Uuid::IsEmpty() const
{
return this->time_low == 0 &&
this->time_mid == 0 &&
this->time_hi_and_version == 0 &&
this->clock_seq_hi_and_reserved == 0 &&
this->clock_seq_low == 0 &&
this->node[0] == 0 &&
this->node[1] == 0 &&
this->node[2] == 0 &&
this->node[3] == 0 &&
this->node[4] == 0 &&
this->node[5] == 0;
}
bool operator==(const Uuid& left, const Uuid& right)
{
return left.time_low == right.time_low &&
left.time_mid == right.time_mid &&
left.time_hi_and_version == right.time_hi_and_version &&
left.clock_seq_hi_and_reserved == right.clock_seq_hi_and_reserved &&
left.clock_seq_low == right.clock_seq_low &&
left.node[0] == right.node[0] &&
left.node[1] == right.node[1] &&
left.node[2] == right.node[2] &&
left.node[3] == right.node[3] &&
left.node[4] == right.node[4] &&
left.node[5] == right.node[5];
}
bool operator!=(const Uuid& left, const Uuid& right)
{
return left.time_low != right.time_low &&
left.time_mid != right.time_mid &&
left.time_hi_and_version != right.time_hi_and_version &&
left.clock_seq_hi_and_reserved != right.clock_seq_hi_and_reserved &&
left.clock_seq_low != right.clock_seq_low &&
left.node[0] != right.node[0] &&
left.node[1] != right.node[1] &&
left.node[2] != right.node[2] &&
left.node[3] != right.node[3] &&
left.node[4] != right.node[4] &&
left.node[5] != right.node[5];
}
}