From cc6743520a475079e95385a423aebb961fd40459 Mon Sep 17 00:00:00 2001 From: Ralph Date: Fri, 6 Feb 2026 14:23:40 +0000 Subject: [PATCH] Initial import of scratchpad software --- .gitattributes | 3 + .gitignore | 561 +++++++++++++++++++++++++++++++++++++ CMakeLists.txt | 75 +++++ config.json | 350 +++++++++++++++++++++++ config.yaml | 313 +++++++++++++++++++++ controllers/Scratchpad.cpp | 106 +++++++ controllers/Scratchpad.h | 25 ++ main.cpp | 15 + models/model.json | 104 +++++++ test/CMakeLists.txt | 14 + test/test_main.cc | 32 +++ 11 files changed, 1598 insertions(+) create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 CMakeLists.txt create mode 100644 config.json create mode 100644 config.yaml create mode 100644 controllers/Scratchpad.cpp create mode 100644 controllers/Scratchpad.h create mode 100644 main.cpp create mode 100644 models/model.json create mode 100644 test/CMakeLists.txt create mode 100644 test/test_main.cc diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..5230a4d --- /dev/null +++ b/.gitattributes @@ -0,0 +1,3 @@ +*.h language=cpp +*.cc language=cpp +*.hpp language=cpp diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a44a147 --- /dev/null +++ b/.gitignore @@ -0,0 +1,561 @@ +# Created by https://www.toptal.com/developers/gitignore/api/intellij+all,visualstudio,visualstudiocode,cmake,c,c++ +# Edit at https://www.toptal.com/developers/gitignore?templates=intellij+all,visualstudio,visualstudiocode,cmake,c,c++ + +### C ### +# Prerequisites +*.d + +# Object files +*.o +*.ko +*.obj +*.elf + +# Linker output +*.ilk +*.map +*.exp + +# Precompiled Headers +*.gch +*.pch + +# Libraries +*.lib +*.a +*.la +*.lo + +# Shared objects (inc. Windows DLLs) +*.dll +*.so +*.so.* +*.dylib + +# Executables +*.exe +*.out +*.app +*.i*86 +*.x86_64 +*.hex + +# Debug files +*.dSYM/ +*.su +*.idb +*.pdb + +# Kernel Module Compile Results +*.mod* +*.cmd +.tmp_versions/ +modules.order +Module.symvers +Mkfile.old +dkms.conf + +### C++ ### +# Prerequisites + +# Compiled Object files +*.slo + +# Precompiled Headers + +# Linker files + +# Debugger Files + +# Compiled Dynamic libraries + +# Fortran module files +*.mod +*.smod + +# Compiled Static libraries +*.lai + +# Executables + +### CMake ### +CMakeLists.txt.user +CMakeCache.txt +CMakeFiles +CMakeScripts +Testing +Makefile +cmake_install.cmake +install_manifest.txt +compile_commands.json +CTestTestfile.cmake +_deps +CMakeUserPresets.json + +### CMake Patch ### +# External projects +*-prefix/ + +### Intellij+all ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +### Intellij+all Patch ### +# Ignores the whole .idea folder and all .iml files +# See https://github.com/joeblau/gitignore.io/issues/186 and https://github.com/joeblau/gitignore.io/issues/360 + +.idea/ + +# Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-249601023 + +*.iml +modules.xml +.idea/misc.xml +*.ipr + +# Sonarlint plugin +.idea/sonarlint + +### VisualStudioCode ### +.vscode/* +!.vscode/tasks.json +!.vscode/launch.json +*.code-workspace + +### VisualStudioCode Patch ### +# Ignore all local history of files +.history +.ionide + +### VisualStudio ### +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ +[Ll]ogs/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.meta +*.iobj +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*[.json, .xml, .info] + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd + +### VisualStudio Patch ### +# Additional files built by Visual Studio +*.tlog + +# End of https://www.toptal.com/developers/gitignore/api/intellij+all,visualstudio,visualstudiocode,cmake,c,c++ diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..df4ef27 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,75 @@ +cmake_minimum_required(VERSION 3.5) +project(ralph-rewrite CXX) + +include(CheckIncludeFileCXX) + +check_include_file_cxx(any HAS_ANY) +check_include_file_cxx(string_view HAS_STRING_VIEW) +check_include_file_cxx(coroutine HAS_COROUTINE) +if (NOT "${CMAKE_CXX_STANDARD}" STREQUAL "") + # Do nothing +elseif (HAS_ANY AND HAS_STRING_VIEW AND HAS_COROUTINE) + set(CMAKE_CXX_STANDARD 20) +elseif (HAS_ANY AND HAS_STRING_VIEW) + set(CMAKE_CXX_STANDARD 17) +else () + set(CMAKE_CXX_STANDARD 14) +endif () + +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) + +add_executable(${PROJECT_NAME} main.cpp) + +# ############################################################################## +# If you include the drogon source code locally in your project, use this method +# to add drogon +# add_subdirectory(drogon) +# target_link_libraries(${PROJECT_NAME} PRIVATE drogon) +# +# and comment out the following lines +find_package(Drogon CONFIG REQUIRED) +target_link_libraries(${PROJECT_NAME} PRIVATE Drogon::Drogon) + +# ############################################################################## + +if (CMAKE_CXX_STANDARD LESS 17) + message(FATAL_ERROR "c++17 or higher is required") +elseif (CMAKE_CXX_STANDARD LESS 20) + message(STATUS "use c++17") +else () + message(STATUS "use c++20") +endif () + +aux_source_directory(controllers CTL_SRC) +aux_source_directory(filters FILTER_SRC) +aux_source_directory(plugins PLUGIN_SRC) +aux_source_directory(models MODEL_SRC) + +drogon_create_views(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/views + ${CMAKE_CURRENT_BINARY_DIR}) +# use the following line to create views with namespaces. +# drogon_create_views(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/views +# ${CMAKE_CURRENT_BINARY_DIR} TRUE) +# use the following line to create views with namespace CHANGE_ME prefixed +# and path namespaces. +# drogon_create_views(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/views +# ${CMAKE_CURRENT_BINARY_DIR} TRUE CHANGE_ME) + +target_include_directories(${PROJECT_NAME} + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/models) +target_sources(${PROJECT_NAME} + PRIVATE + ${SRC_DIR} + ${CTL_SRC} + ${FILTER_SRC} + ${PLUGIN_SRC} + ${MODEL_SRC}) +# ############################################################################## +# uncomment the following line for dynamically loading views +# set_property(TARGET ${PROJECT_NAME} PROPERTY ENABLE_EXPORTS ON) + +# ############################################################################## + +add_subdirectory(test) diff --git a/config.json b/config.json new file mode 100644 index 0000000..a02bba1 --- /dev/null +++ b/config.json @@ -0,0 +1,350 @@ +/* This is a JSON format configuration file + */ +{ + /* + //ssl:The global SSL settings. "key" and "cert" are the path to the SSL key and certificate. While + // "conf" is an array of 1 or 2-element tuples that supplies file style options for `SSL_CONF_cmd`. + "ssl": { + "cert": "../../trantor/trantor/tests/server.crt", + "key": "../../trantor/trantor/tests/server.key", + "conf": [ + //["Options", "-SessionTicket"], + //["Options", "Compression"] + ] + }, + "listeners": [ + { + //address: Ip address,0.0.0.0 by default + "address": "0.0.0.0", + //port: Port number + "port": 80, + //https: If true, use https for security,false by default + "https": false + }, + { + "address": "0.0.0.0", + "port": 443, + "https": true, + //cert,key: Cert file path and key file path, empty by default, + //if empty, use the global setting + "cert": "", + "key": "", + //use_old_tls: enable the TLS1.0/1.1, false by default + "use_old_tls": false, + "ssl_conf": [ + //["MinProtocol", "TLSv1.3"] + ] + } + ], + "db_clients": [ + { + //name: Name of the client,'default' by default + "name": "default", + //rdbms: Server type, postgresql,mysql or sqlite3, "postgresql" by default + "rdbms": "postgresql", + //filename: Sqlite3 db file name + //"filename":"", + //host: Server address,localhost by default + "host": "127.0.0.1", + //port: Server port, 5432 by default + "port": 5432, + //dbname: Database name + "dbname": "test", + //user: 'postgres' by default + "user": "", + //passwd: '' by default + "passwd": "", + //is_fast: false by default, if it is true, the client is faster but user can't call + //any synchronous interface of it. + "is_fast": false, + //client_encoding: The character set used by the client. it is empty string by default which + //means use the default character set. + //"client_encoding": "", + //number_of_connections: 1 by default, if the 'is_fast' is true, the number is the number of + //connections per IO thread, otherwise it is the total number of all connections. + "number_of_connections": 1, + //timeout: -1.0 by default, in seconds, the timeout for executing a SQL query. + //zero or negative value means no timeout. + "timeout": -1.0, + //auto_batch: this feature is only available for the PostgreSQL driver(version >= 14.0), see + //the wiki for more details. + "auto_batch": false + //connect_options: extra options for the connection. Only works for PostgreSQL now. + //For more information, see https://www.postgresql.org/docs/16/libpq-connect.html#LIBPQ-CONNECT-OPTIONS + //"connect_options": { "statement_timeout": "1s" } + } + ], + "redis_clients": [ + { + //name: Name of the client,'default' by default + "name": "default", + //host: Server IP, 127.0.0.1 by default + "host": "127.0.0.1", + //port: Server port, 6379 by default + "port": 6379, + //username: '' by default which means 'default' in redis ACL + "username": "", + //passwd: '' by default + "passwd": "", + //db index: 0 by default + "db": 0, + //is_fast: false by default, if it is true, the client is faster but user can't call + //any synchronous interface of it. + "is_fast": false, + //number_of_connections: 1 by default, if the 'is_fast' is true, the number is the number of + //connections per IO thread, otherwise it is the total number of all connections. + "number_of_connections": 1, + //timeout: -1.0 by default, in seconds, the timeout for executing a command. + //zero or negative value means no timeout. + "timeout": -1.0 + } + ],*/ + "app": { + //number_of_threads: The number of IO threads, 1 by default, if the value is set to 0, the number of threads + //is the number of CPU cores + "number_of_threads": 1, + //enable_session: False by default + "enable_session": false, + "session_timeout": 0, + //string value of SameSite attribute of the Set-Cookie HTTP response header + //valid value is either 'Null' (default), 'Lax', 'Strict' or 'None' + "session_same_site" : "Null", + //session_cookie_key: The cookie key of the session, "JSESSIONID" by default + "session_cookie_key": "JSESSIONID", + //session_max_age: The max age of the session cookie, -1 by default + "session_max_age": -1, + //document_root: Root path of HTTP document, default path is ./ + "document_root": "./", + //home_page: Set the HTML file of the home page, the default value is "index.html" + //If there isn't any handler registered to the path "/", the home page file in the "document_root" is send to clients as a response + //to the request for "/". + "home_page": "index.html", + //use_implicit_page: enable implicit pages if true, true by default + "use_implicit_page": true, + //implicit_page: Set the file which would the server access in a directory that a user accessed. + //For example, by default, http://localhost/a-directory resolves to http://localhost/a-directory/index.html. + "implicit_page": "index.html", + //static_file_headers: Headers for static files + /*"static_file_headers": [ + { + "name": "field-name", + "value": "field-value" + } + ],*/ + //upload_path: The path to save the uploaded file. "uploads" by default. + //If the path isn't prefixed with /, ./ or ../, + //it is relative path of document_root path + "upload_path": "uploads", + /* file_types: + * HTTP download file types,The file types supported by drogon + * by default are "html", "js", "css", "xml", "xsl", "txt", "svg", + * "ttf", "otf", "woff2", "woff" , "eot", "png", "jpg", "jpeg", + * "gif", "bmp", "ico", "icns", etc. */ + "file_types": [ + "gif", + "png", + "jpg", + "js", + "css", + "html", + "ico", + "swf", + "xap", + "apk", + "cur", + "xml", + "webp", + "svg" + ], + // mime: A dictionary that extends the internal MIME type support. Maps extensions into new MIME types + // note: This option only adds MIME to the sever. `file_types` above have to be set for the server to serve them. + "mime": { + // "text/markdown": "md", + // "text/gemini": ["gmi", "gemini"] + }, + //locations: An array of locations of static files for GET requests. + "locations": [ + { + //uri_prefix: The URI prefix of the location prefixed with "/", the default value is "" that disables the location. + //"uri_prefix": "/.well-known/acme-challenge/", + //default_content_type: The default content type of the static files without + //an extension. empty string by default. + "default_content_type": "text/plain", + //alias: The location in file system, if it is prefixed with "/", it + //presents an absolute path, otherwise it presents a relative path to + //the document_root path. + //The default value is "" which means use the document root path as the location base path. + "alias": "", + //is_case_sensitive: indicates whether the URI prefix is case sensitive. + "is_case_sensitive": false, + //allow_all: true by default. If it is set to false, only static files with a valid extension can be accessed. + "allow_all": true, + //is_recursive: true by default. If it is set to false, files in sub directories can't be accessed. + "is_recursive": true, + //filters: string array, the filters applied to the location. + "filters": [] + } + ], + //max_connections: maximum number of connections, 100000 by default + "max_connections": 100000, + //max_connections_per_ip: maximum number of connections per client, 0 by default which means no limit + "max_connections_per_ip": 0, + //Load_dynamic_views: False by default, when set to true, drogon + //compiles and loads dynamically "CSP View Files" in directories defined + //by "dynamic_views_path" + "load_dynamic_views": false, + //dynamic_views_path: If the path isn't prefixed with /, ./ or ../, + //it is relative path of document_root path + "dynamic_views_path": [ + "./views" + ], + //dynamic_views_output_path: Default by an empty string which means the output path of source + //files is the path where the csp files locate. If the path isn't prefixed with /, it is relative + //path of the current working directory. + "dynamic_views_output_path": "", + //json_parser_stack_limit: 1000 by default, the maximum number of stack depth when reading a json string by the jsoncpp library. + "json_parser_stack_limit": 1000, + //enable_unicode_escaping_in_json: true by default, enable unicode escaping in json. + "enable_unicode_escaping_in_json": true, + //float_precision_in_json: set precision of float number in json. + "float_precision_in_json": { + //precision: 0 by default, 0 means use the default precision of the jsoncpp lib. + "precision": 0, + //precision_type: must be "significant" or "decimal", defaults to "significant" that means + //setting max number of significant digits in string, "decimal" means setting max number of + //digits after "." in string + "precision_type": "significant" + }, + //log: Set log output, drogon output logs to stdout by default + "log": { + //use_spdlog: Use spdlog library to log + "use_spdlog": false, + //log_path: Log file path,empty by default,in which case,logs are output to the stdout + //"log_path": "./", + //logfile_base_name: Log file base name,empty by default which means drogon names logfile as + //drogon.log ... + "logfile_base_name": "", + //log_size_limit: 100000000 bytes by default, + //When the log file size reaches "log_size_limit", the log file is switched. + "log_size_limit": 100000000, + //max_files: 0 by default, + //When the number of old log files exceeds "max_files", the oldest file will be deleted. 0 means never delete. + "max_files": 0, + //log_level: "DEBUG" by default,options:"TRACE","DEBUG","INFO","WARN" + //The TRACE level is only valid when built in DEBUG mode. + "log_level": "DEBUG", + //display_local_time: false by default, if true, the log time is displayed in local time + "display_local_time": false + }, + //run_as_daemon: False by default + "run_as_daemon": false, + //handle_sig_term: True by default + "handle_sig_term": true, + //relaunch_on_error: False by default, if true, the program will be restart by the parent after exiting; + "relaunch_on_error": false, + //use_sendfile: True by default, if true, the program + //uses sendfile() system-call to send static files to clients; + "use_sendfile": true, + //use_gzip: True by default, use gzip to compress the response body's content; + "use_gzip": true, + //use_brotli: False by default, use brotli to compress the response body's content; + "use_brotli": false, + //static_files_cache_time: 5 (seconds) by default, the time in which the static file response is cached, + //0 means cache forever, the negative value means no cache + "static_files_cache_time": 5, + //simple_controllers_map: Used to configure mapping from path to simple controller + //"simple_controllers_map": [ + // { + // "path": "/path/name", + // "controller": "controllerClassName", + // "http_methods": [ + // "get", + // "post" + // ], + // "filters": [ + // "FilterClassName" + // ] + // } + //], + //idle_connection_timeout: Defaults to 60 seconds, the lifetime + //of the connection without read or write + "idle_connection_timeout": 60, + //server_header_field: Set the 'Server' header field in each response sent by drogon, + //empty string by default with which the 'Server' header field is set to "Server: drogon/version string\r\n" + "server_header_field": "", + //enable_server_header: Set true to force drogon to add a 'Server' header to each HTTP response. The default + //value is true. + "enable_server_header": true, + //enable_date_header: Set true to force drogon to add a 'Date' header to each HTTP response. The default + //value is true. + "enable_date_header": true, + //keepalive_requests: Set the maximum number of requests that can be served through one keep-alive connection. + //After the maximum number of requests are made, the connection is closed. + //The default value of 0 means no limit. + "keepalive_requests": 0, + //pipelining_requests: Set the maximum number of unhandled requests that can be cached in pipelining buffer. + //After the maximum number of requests are made, the connection is closed. + //The default value of 0 means no limit. + "pipelining_requests": 0, + //gzip_static: If it is set to true, when the client requests a static file, drogon first finds the compressed + //file with the extension ".gz" in the same path and send the compressed file to the client. + //The default value of gzip_static is true. + "gzip_static": true, + //br_static: If it is set to true, when the client requests a static file, drogon first finds the compressed + //file with the extension ".br" in the same path and send the compressed file to the client. + //The default value of br_static is true. + "br_static": true, + //client_max_body_size: Set the maximum body size of HTTP requests received by drogon. The default value is "1M". + //One can set it to "1024", "1k", "10M", "1G", etc. Setting it to "" means no limit. + "client_max_body_size": "1M", + //max_memory_body_size: Set the maximum body size in memory of HTTP requests received by drogon. The default value is "64K" bytes. + //If the body size of a HTTP request exceeds this limit, the body is stored to a temporary file for processing. + //Setting it to "" means no limit. + "client_max_memory_body_size": "64K", + //client_max_websocket_message_size: Set the maximum size of messages sent by WebSocket client. The default value is "128K". + //One can set it to "1024", "1k", "10M", "1G", etc. Setting it to "" means no limit. + "client_max_websocket_message_size": "128K", + //reuse_port: Defaults to false, users can run multiple processes listening on the same port at the same time. + "reuse_port": false, + // enabled_compressed_request: Defaults to false. If true the server will automatically decompress compressed request bodies. + // Currently only gzip and br are supported. Note: max_memory_body_size and max_body_size applies twice for compressed requests. + // Once when receiving and once when decompressing. i.e. if the decompressed body is larger than max_body_size, the request + // will be rejected. + "enabled_compressed_request": false, + // enable_request_stream: Defaults to false. If true the server will enable stream mode for http requests. + // See the wiki for more details. + "enable_request_stream": false, + }, + //plugins: Define all plugins running in the application + "plugins": [ + { + //name: The class name of the plugin + "name": "drogon::plugin::PromExporter", + //dependencies: Plugins that the plugin depends on. It can be commented out + "dependencies": [], + //config: The configuration of the plugin. This json object is the parameter to initialize the plugin. + //It can be commented out + "config": { + "path": "/metrics" + } + }, + { + "name": "drogon::plugin::AccessLogger", + "dependencies": [], + "config": { + "use_spdlog": false, + "log_path": "", + "log_format": "", + "log_file": "access.log", + "log_size_limit": 0, + "use_local_time": true, + "log_index": 0, + // "show_microseconds": true, + // "custom_time_format": "", + // "use_real_ip": false + } + } + ], + //custom_config: custom configuration for users. This object can be get by the app().getCustomConfig() method. + "custom_config": {} +} diff --git a/config.yaml b/config.yaml new file mode 100644 index 0000000..d83304b --- /dev/null +++ b/config.yaml @@ -0,0 +1,313 @@ +# This is a YAML format configuration file + +# ssl:The global SSL settings. "key" and "cert" are the path to the SSL key and certificate. While +# "conf" is an array of 1 or 2-element tuples that supplies file style options for `SSL_CONF_cmd`. +# ssl: +# cert: ../../trantor/trantor/tests/server.crt +# key: ../../trantor/trantor/tests/server.key +# conf: [ +# # [Options, -SessionTicket], +# # [Options, Compression] +# ] +# listeners: +# # address: Ip address,0.0.0.0 by default +# - address: 0.0.0.0 +# # port: Port number +# port: 80 +# # https: If true, use https for security,false by default +# https: false +# - address: 0.0.0.0 +# port: 443 +# https: true +# # cert,key: Cert file path and key file path, empty by default, +# # if empty, use the global setting +# cert: '' +# key: '' +# # use_old_tls: enable the TLS1.0/1.1, false by default +# use_old_tls: false +# ssl_conf: [ +# # [MinProtocol, TLSv1.3] +# ] +# db_clients: +# # name: Name of the client,'default' by default +# - name: default +# # rdbms: Server type, postgresql,mysql or sqlite3, "postgresql" by default +# rdbms: postgresql +# # filename: Sqlite3 db file name +# # filename: '' +# # host: Server address,localhost by default +# host: 127.0.0.1 +# # port: Server port, 5432 by default +# port: 5432 +# # dbname: Database name +# dbname: test +# # user: 'postgres' by default +# user: '' +# # passwd: '' by default +# passwd: '' +# # is_fast: false by default, if it is true, the client is faster but user can't call +# # any synchronous interface of it. +# is_fast: false +# # client_encoding: The character set used by the client. it is empty string by default which +# # means use the default character set. +# # client_encoding: '' +# # number_of_connections: 1 by default, if the 'is_fast' is true, the number is the number of +# # connections per IO thread, otherwise it is the total number of all connections. +# number_of_connections: 1 +# # timeout: -1 by default, in seconds, the timeout for executing a SQL query. +# # zero or negative value means no timeout. +# timeout: -1 +# # auto_batch: this feature is only available for the PostgreSQL driver(version >= 14.0), see +# # the wiki for more details. +# auto_batch: false +# # connect_options: extra options for the connection. Only works for PostgreSQL now. +# # For more information, see https://www.postgresql.org/docs/16/libpq-connect.html#LIBPQ-CONNECT-OPTIONS +# # connect_options: +# # statement_timeout: '1s' +# redis_clients: +# # name: Name of the client,'default' by default +# - name: default +# # host: Server IP, 127.0.0.1 by default +# host: 127.0.0.1 +# # port: Server port, 6379 by default +# port: 6379 +# # username: '' by default which means 'default' in redis ACL +# username: '' +# # passwd: '' by default +# passwd: '' +# # db index: 0 by default +# db: 0 +# # is_fast: false by default, if it is true, the client is faster but user can't call +# # any synchronous interface of it. +# is_fast: false +# # number_of_connections: 1 by default, if the 'is_fast' is true, the number is the number of +# # connections per IO thread, otherwise it is the total number of all connections. +# number_of_connections: 1 +# # timeout: -1.0 by default, in seconds, the timeout for executing a command. +# # zero or negative value means no timeout. +# timeout: -1 +app: + # number_of_threads: The number of IO threads, 1 by default, if the value is set to 0, the number of threads + # is the number of CPU cores + number_of_threads: 1 + # enable_session: False by default + enable_session: false + session_timeout: 0 + # string value of SameSite attribute of the Set-Cookie HTTP response header + # valid value is either 'Null' (default), 'Lax', 'Strict' or 'None' + session_same_site: 'Null' + # session_cookie_key: The cookie key of the session, "JSESSIONID" by default + session_cookie_key: 'JSESSIONID' + # session_max_age: The max age of the session cookie, -1 by default + session_max_age: -1 + # document_root: Root path of HTTP document, default path is ./ + document_root: ./ + # home_page: Set the HTML file of the home page, the default value is "index.html" + # If there isn't any handler registered to the path "/", the home page file in the "document_root" is send to clients as a response + # to the request for "/". + home_page: index.html + # use_implicit_page: enable implicit pages if true, true by default + use_implicit_page: true + # implicit_page: Set the file which would the server access in a directory that a user accessed. + # For example, by default, http://localhost/a-directory resolves to http://localhost/a-directory/index.html. + implicit_page: index.html + # static_file_headers: Headers for static files + # static_file_headers: + # - name: field-name + # value: field-value + # upload_path: The path to save the uploaded file. "uploads" by default. + # If the path isn't prefixed with /, ./ or ../, + # it is relative path of document_root path + upload_path: uploads + # file_types: + # HTTP download file types,The file types supported by drogon + # by default are "html", "js", "css", "xml", "xsl", "txt", "svg", + # "ttf", "otf", "woff2", "woff" , "eot", "png", "jpg", "jpeg", + # "gif", "bmp", "ico", "icns", etc. + file_types: + - gif + - png + - jpg + - js + - css + - html + - ico + - swf + - xap + - apk + - cur + - xml + # mime: A dictionary that extends the internal MIME type support. Maps extensions into new MIME types + # note: This option only adds MIME to the sever. `file_types` above have to be set for the server to serve them. + mime: { + # text/markdown: md + # text/gemini: + # - gmi + # - gemini + } + # locations: An array of locations of static files for GET requests. + locations: + # uri_prefix: The URI prefix of the location prefixed with "/", the default value is "" that disables the location. + - uri_prefix: '' # /.well-known/acme-challenge/ + # default_content_type: The default content type of the static files without + # an extension. empty string by default. + default_content_type: text/plain + # alias: The location in file system, if it is prefixed with "/", it + # presents an absolute path, otherwise it presents a relative path to + # the document_root path. + # The default value is "" which means use the document root path as the location base path. + alias: '' + # is_case_sensitive: indicates whether the URI prefix is case sensitive. + is_case_sensitive: false + # allow_all: true by default. If it is set to false, only static files with a valid extension can be accessed. + allow_all: true + # is_recursive: true by default. If it is set to false, files in sub directories can't be accessed. + is_recursive: true + # filters: string array, the filters applied to the location. + filters: [] + # max_connections: maximum number of connections, 100000 by default + max_connections: 100000 + # max_connections_per_ip: maximum number of connections per client, 0 by default which means no limit + max_connections_per_ip: 0 + # Load_dynamic_views: False by default, when set to true, drogon + # compiles and loads dynamically "CSP View Files" in directories defined + # by "dynamic_views_path" + load_dynamic_views: false + # dynamic_views_path: If the path isn't prefixed with /, ./ or ../, + # it is relative path of document_root path + dynamic_views_path: + - ./views + # dynamic_views_output_path: Default by an empty string which means the output path of source + # files is the path where the csp files locate. If the path isn't prefixed with /, it is relative + # path of the current working directory. + dynamic_views_output_path: '' + # json_parser_stack_limit: 1000 by default, the maximum number of stack depth when reading a json string by the jsoncpp library. + json_parser_stack_limit: 1000 + # enable_unicode_escaping_in_json: true by default, enable unicode escaping in json. + enable_unicode_escaping_in_json: true + # float_precision_in_json: set precision of float number in json. + float_precision_in_json: + # precision: 0 by default, 0 means use the default precision of the jsoncpp lib. + precision: 0 + # precision_type: must be "significant" or "decimal", defaults to "significant" that means + # setting max number of significant digits in string, "decimal" means setting max number of + # digits after "." in string + precision_type: significant + # log: Set log output, drogon output logs to stdout by default + log: + # use_spdlog: Use spdlog library to log + use_spdlog: false + # log_path: Log file path,empty by default,in which case,logs are output to the stdout + # log_path: ./ + # logfile_base_name: Log file base name,empty by default which means drogon names logfile as + # drogon.log ... + logfile_base_name: '' + # log_size_limit: 100000000 bytes by default, + # When the log file size reaches "log_size_limit", the log file is switched. + log_size_limit: 100000000 + # max_files: 0 by default, + # When the number of old log files exceeds "max_files", the oldest file will be deleted. 0 means never delete. + max_files: 0 + # log_level: "DEBUG" by default,options:"TRACE","DEBUG","INFO","WARN" + # The TRACE level is only valid when built in DEBUG mode. + log_level: DEBUG + # display_local_time: false by default, if true, the log time is displayed in local time + display_local_time: false + # run_as_daemon: False by default + run_as_daemon: false + # handle_sig_term: True by default + handle_sig_term: true + # relaunch_on_error: False by default, if true, the program will be restart by the parent after exiting; + relaunch_on_error: false + # use_sendfile: True by default, if true, the program + # uses sendfile() system-call to send static files to clients; + use_sendfile: true + # use_gzip: True by default, use gzip to compress the response body's content; + use_gzip: true + # use_brotli: False by default, use brotli to compress the response body's content; + use_brotli: false + # static_files_cache_time: 5 (seconds) by default, the time in which the static file response is cached, + # 0 means cache forever, the negative value means no cache + static_files_cache_time: 5 + # simple_controllers_map: Used to configure mapping from path to simple controller + # simple_controllers_map: + # - path: /path/name + # controller: controllerClassName + # http_methods: + # - get + # - post + # filters: + # - FilterClassName + # idle_connection_timeout: Defaults to 60 seconds, the lifetime + # of the connection without read or write + idle_connection_timeout: 60 + # server_header_field: Set the 'Server' header field in each response sent by drogon, + # empty string by default with which the 'Server' header field is set to "Server: drogon/version string\r\n" + server_header_field: '' + # enable_server_header: Set true to force drogon to add a 'Server' header to each HTTP response. The default + # value is true. + enable_server_header: true + # enable_date_header: Set true to force drogon to add a 'Date' header to each HTTP response. The default + # value is true. + enable_date_header: true + # keepalive_requests: Set the maximum number of requests that can be served through one keep-alive connection. + # After the maximum number of requests are made, the connection is closed. + # The default value of 0 means no limit. + keepalive_requests: 0 + # pipelining_requests: Set the maximum number of unhandled requests that can be cached in pipelining buffer. + # After the maximum number of requests are made, the connection is closed. + # The default value of 0 means no limit. + pipelining_requests: 0 + # gzip_static: If it is set to true, when the client requests a static file, drogon first finds the compressed + # file with the extension ".gz" in the same path and send the compressed file to the client. + # The default value of gzip_static is true. + gzip_static: true + # br_static: If it is set to true, when the client requests a static file, drogon first finds the compressed + # file with the extension ".br" in the same path and send the compressed file to the client. + # The default value of br_static is true. + br_static: true + # client_max_body_size: Set the maximum body size of HTTP requests received by drogon. The default value is "1M". + # One can set it to "1024", "1k", "10M", "1G", etc. Setting it to "" means no limit. + client_max_body_size: 1M + # max_memory_body_size: Set the maximum body size in memory of HTTP requests received by drogon. The default value is "64K" bytes. + # If the body size of a HTTP request exceeds this limit, the body is stored to a temporary file for processing. + # Setting it to "" means no limit. + client_max_memory_body_size: 64K + # client_max_websocket_message_size: Set the maximum size of messages sent by WebSocket client. The default value is "128K". + # One can set it to "1024", "1k", "10M", "1G", etc. Setting it to "" means no limit. + client_max_websocket_message_size: 128K + # reuse_port: Defaults to false, users can run multiple processes listening on the same port at the same time. + reuse_port: false + # enabled_compressed_request: Defaults to false. If true the server will automatically decompress compressed request bodies. + # Currently only gzip and br are supported. Note: max_memory_body_size and max_body_size applies twice for compressed requests. + # Once when receiving and once when decompressing. i.e. if the decompressed body is larger than max_body_size, the request + # will be rejected. + enabled_compressed_request: false + # enable_request_stream: Defaults to false. If true the server will enable stream mode for http requests. + # See the wiki for more details. + enable_request_stream: false +# plugins: Define all plugins running in the application +plugins: + # name: The class name of the plugin + - name: drogon::plugin::PromExporter + # dependencies: Plugins that the plugin depends on. It can be commented out + dependencies: [] + # config: The configuration of the plugin. This json object is the parameter to initialize the plugin. + # It can be commented out + config: + path: /metrics + - name: drogon::plugin::AccessLogger + dependencies: [] + config: + use_spdlog: false + log_path: '' + log_format: '' + log_file: access.log + log_size_limit: 0 + use_local_time: true + log_index: 0 + # show_microseconds: true + # custom_time_format: '' + # use_real_ip: false +# custom_config: custom configuration for users. This object can be get by the app().getCustomConfig() method. +custom_config: {} diff --git a/controllers/Scratchpad.cpp b/controllers/Scratchpad.cpp new file mode 100644 index 0000000..1fb92c4 --- /dev/null +++ b/controllers/Scratchpad.cpp @@ -0,0 +1,106 @@ +#include "Scratchpad.h" +#include +#include +#include +#include +#include + +// Helper: Execute shell command and capture output +std::string exec(const char* cmd) { + std::array buffer; + std::string result; + std::unique_ptr pipe(popen(cmd, "r"), pclose); + if (!pipe) { + throw std::runtime_error("popen() failed!"); + } + while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) { + result += buffer.data(); + } + return result; +} + +void Scratchpad::runCode(const HttpRequestPtr& req, std::function &&callback) +{ + // 1. Auth Check + auto authHeader = req->getHeader("X-API-Key"); + if (authHeader != API_KEY) + { + Json::Value error; + error["error"] = "Unauthorized. Invalid API Key."; + auto resp = HttpResponse::newHttpJsonResponse(error); + resp->setStatusCode(k401Unauthorized); + callback(resp); + return; + } + + // 2. Get Code from Body + auto json = req->getJsonObject(); + if (!json || !(*json)["code"].isString()) + { + Json::Value error; + error["error"] = "Invalid JSON. 'code' field required."; + auto resp = HttpResponse::newHttpJsonResponse(error); + resp->setStatusCode(k400BadRequest); + callback(resp); + return; + } + + std::string userCode = (*json)["code"].asString(); + + // 3. Compile and Run + Json::Value ret; + try { + std::string output = compileAndRun(userCode); + ret["status"] = "success"; + ret["output"] = output; + } catch (const std::exception& e) { + ret["status"] = "error"; + ret["error"] = e.what(); + } + + auto resp = HttpResponse::newHttpJsonResponse(ret); + callback(resp); +} + +std::string Scratchpad::compileAndRun(const std::string& code) +{ + // A. Write to temp file + std::string filename = "temp_scratchpad.cpp"; + std::string binary = "./temp_scratchpad"; + + std::ofstream out(filename); + out << code; + out.close(); + + // B. Compile (Clang++) + // Using -std=c++20 and linking nothing extra for now + std::string compileCmd = "clang++ -std=c++20 " + filename + " -o " + binary + " 2>&1"; + std::string compileOut = exec(compileCmd.c_str()); + + // Check if compilation failed (binary doesn't exist) + if (!std::filesystem::exists(binary)) { + return "Compilation Error:\n" + compileOut; + } + + // C. Execute + // Timeout logic should be added here later (e.g., using 'timeout' cmd) + std::string runCmd = binary + " 2>&1"; + std::string runOut = exec(runCmd.c_str()); + + // Cleanup + std::filesystem::remove(filename); + std::filesystem::remove(binary); + + return runOut; +} + +void Scratchpad::status(const HttpRequestPtr& req, std::function &&callback) +{ + Json::Value ret; + ret["status"] = "online"; + ret["version"] = "2.1 (Execution Engine)"; + ret["compiler"] = "Clang 19.1.7"; + ret["note"] = "Send POST to /scratchpad/run with header 'X-API-Key'"; + auto resp = HttpResponse::newHttpJsonResponse(ret); + callback(resp); +} diff --git a/controllers/Scratchpad.h b/controllers/Scratchpad.h new file mode 100644 index 0000000..ba1f6c8 --- /dev/null +++ b/controllers/Scratchpad.h @@ -0,0 +1,25 @@ +#pragma once + +#include + +using namespace drogon; + +class Scratchpad : public drogon::HttpController +{ + public: + METHOD_LIST_BEGIN + // POST /scratchpad/run -> Protected (API Key required) + METHOD_ADD(Scratchpad::runCode, "/run", Post); + + // GET /scratchpad/status -> Public + METHOD_ADD(Scratchpad::status, "/status", Get); + METHOD_LIST_END + + void runCode(const HttpRequestPtr& req, std::function &&callback); + void status(const HttpRequestPtr& req, std::function &&callback); + + private: + // Helper to compile and execute C++ code + std::string compileAndRun(const std::string& code); + const std::string API_KEY = "SixBabiesShittingPoutine!!"; // Protected access +}; diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..b47e4ae --- /dev/null +++ b/main.cpp @@ -0,0 +1,15 @@ +#include +#include + +using namespace drogon; + +int main() { + std::cout << "🚀 Ralph is starting on port 8080..." << std::endl; + // Set HTTP listener address and port + app().addListener("0.0.0.0", 8080); + // Load config file + // app().loadConfigFile("../config.json"); + // Run HTTP framework,the method will block in the internal event loop + app().run(); + return 0; +} diff --git a/models/model.json b/models/model.json new file mode 100644 index 0000000..c5045ae --- /dev/null +++ b/models/model.json @@ -0,0 +1,104 @@ +{ + //rdbms: server type, postgresql,mysql or sqlite3 + "rdbms": "postgresql", + //filename: sqlite3 db file name + //"filename":"", + //host: server address,localhost by default; + "host": "127.0.0.1", + //port: server port, 5432 by default; + "port": 5432, + //dbname: Database name; + "dbname": "", + //schema: valid for postgreSQL, "public" by default; + "schema": "public", + //user: User name + "user": "", + //password or passwd: Password + "password": "", + //client_encoding: The character set used by drogon_ctl. it is empty string by default which + //means use the default character set. + //"client_encoding": "", + //table: An array of tables to be modelized. if the array is empty, all revealed tables are modelized. + "tables": [], + //convert: the value can be changed by a function call before it is stored into database or + //after it is read from database + "convert": { + "enabled": false, + "items":[{ + "table": "user", + "column": "password", + "method": { + //after_db_read: name of the method which is called after reading from database, signature: void([const] std::shared_ptr [&]) + "after_db_read": "decrypt_password", + //before_db_write: name of the method which is called before writing to database, signature: void([const] std::shared_ptr [&]) + "before_db_write": "encrypt_password" + }, + "includes": [ + "\"file_local_search_path.h\"","" + ] + }] + }, + "relationships": { + "enabled": false, + "items": [{ + "type": "has one", + "original_table_name": "products", + "original_table_alias": "product", + "original_key": "id", + "target_table_name": "skus", + "target_table_alias": "SKU", + "target_key": "product_id", + "enable_reverse": true + }, + { + "type": "has many", + "original_table_name": "products", + "original_table_alias": "product", + "original_key": "id", + "target_table_name": "reviews", + "target_table_alias": "", + "target_key": "product_id", + "enable_reverse": true + }, + { + "type": "many to many", + "original_table_name": "products", + "original_table_alias": "", + "original_key": "id", + "pivot_table": { + "table_name": "carts_products", + "original_key": "product_id", + "target_key": "cart_id" + }, + "target_table_name": "carts", + "target_table_alias": "", + "target_key": "id", + "enable_reverse": true + } + ] + }, + "restful_api_controllers": { + "enabled": false, + // resource_uri: The URI to access the resource, the default value + // is '/*' in which the asterisk represents the table name. + // If this option is set to a empty string, the URI is composed of the namespaces and the class name. + "resource_uri": "/*", + // class_name: "Restful*Ctrl" by default, the asterisk represents the table name. + // This option can contain namespaces. + "class_name": "Restful*Ctrl", + // filters: an array of filter names. + "filters": [], + // db_client: the database client used by the controller. this option must be consistent with + // the configuration of the application. + "db_client": { + //name: Name of the client,'default' by default + "name": "default", + //is_fast: + "is_fast": false + }, + // directory: The directory where the controller source files are stored. + "directory": "controllers", + // generate_base_only: false by default. Set to true to avoid overwriting custom subclasses. + "generate_base_only": false + } +} diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100644 index 0000000..cf94832 --- /dev/null +++ b/test/CMakeLists.txt @@ -0,0 +1,14 @@ +cmake_minimum_required(VERSION 3.5) +project(ralph-rewrite_test CXX) + +add_executable(${PROJECT_NAME} test_main.cc) + +# ############################################################################## +# If you include the drogon source code locally in your project, use this method +# to add drogon +# target_link_libraries(${PROJECT_NAME} PRIVATE drogon) +# +# and comment out the following lines +target_link_libraries(${PROJECT_NAME} PRIVATE Drogon::Drogon) + +ParseAndAddDrogonTests(${PROJECT_NAME}) diff --git a/test/test_main.cc b/test/test_main.cc new file mode 100644 index 0000000..7370b29 --- /dev/null +++ b/test/test_main.cc @@ -0,0 +1,32 @@ +#define DROGON_TEST_MAIN +#include +#include + +DROGON_TEST(BasicTest) +{ + // Add your tests here +} + +int main(int argc, char** argv) +{ + using namespace drogon; + + std::promise p1; + std::future f1 = p1.get_future(); + + // Start the main loop on another thread + std::thread thr([&]() { + // Queues the promise to be fulfilled after starting the loop + app().getLoop()->queueInLoop([&p1]() { p1.set_value(); }); + app().run(); + }); + + // The future is only satisfied after the event loop started + f1.get(); + int status = test::run(argc, argv); + + // Ask the event loop to shutdown and wait + app().getLoop()->queueInLoop([]() { app().quit(); }); + thr.join(); + return status; +}