{"id":18048308,"url":"https://github.com/relintai/rcpp_framework","last_synced_at":"2025-04-05T05:16:34.026Z","repository":{"id":107318792,"uuid":"315956950","full_name":"Relintai/rcpp_framework","owner":"Relintai","description":"An experimental c++ app/http framework","archived":false,"fork":false,"pushed_at":"2022-08-21T22:11:40.000Z","size":5598,"stargazers_count":1,"open_issues_count":0,"forks_count":1,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-02-10T13:14:09.274Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Relintai.png","metadata":{"files":{"readme":"Readme.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-11-25T14:03:37.000Z","updated_at":"2022-01-09T17:35:17.000Z","dependencies_parsed_at":null,"dependency_job_id":"a8482d5a-8246-418d-8e0f-4394b95c44c8","html_url":"https://github.com/Relintai/rcpp_framework","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Relintai%2Frcpp_framework","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Relintai%2Frcpp_framework/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Relintai%2Frcpp_framework/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Relintai%2Frcpp_framework/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Relintai","download_url":"https://codeload.github.com/Relintai/rcpp_framework/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247289433,"owners_count":20914464,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-30T20:12:24.352Z","updated_at":"2025-04-05T05:16:33.988Z","avatar_url":"https://github.com/Relintai.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"# rcpp framework\n\n## State\n\nI consider this deprecated, as I ended up merging all of it's functionality into the [Pandemonium Engine](https://github.com/Relintai/pandemonium_engine).\n\nThe web classes ended up in the [web module](https://github.com/Relintai/pandemonium_engine/tree/master/modules/web), and the database classes in the [database module](https://github.com/Relintai/pandemonium_engine/tree/master/modules/database).\n\nFurther development will happen there.\n\n## Intro\n\nThis is a c++ html framework, with a different core design than the current mainstream html frameworks.\n\nIt's more similar to Codeigniter 3, but of course it's still different, because it's a c++ app.\n\nSince it's a normal c++ app, lots of things can be implemented in an unusual (compared to how html frameworks work) \nalbeit lot more efficient way. Also standard app/game like optimizations can be implemented.\nFor example it's possible to load and cache users, and only save them in a \ndifferent thread when necessary (they get dirty).\n\nI consider it's design mostly stable, it needs cleanups, and some features, but it shouldn't change that much anymore fundamentally.\n\nFor the time being I recommend looking at my other projects that use this for usage examples.\n\nIf you want to try it clone https://github.com/Relintai/rcpp_cms_project instead, it will set this up for you.\nNote that this needs to be updated aswell, will be done eventually.\n\nOnly works on linux for now. Eventually I'll reimplement compile on windows.\n\nSupports SQlite (built in), MySQL, and PostgreSQL databases.\n\n## Compiling\n\nThe framework itself doesn't contains a main, and an application implementation.\n\nYou will need to provide these in order to compile the project.\n\nYou can add these as command line parameters like:\n\n` scons main_file=\"../main.cpp\" folders=\"../app/;../app_folder_2\" `\n\nThis should be handled by the project's build script though.\n\nCheck the https://github.com/Relintai/rcpp_cms_project for actual compilation instructions.\n\n## Core\n\nContains core classes.\n\n### HTTPServer\n\nA simple HTTP server class. Create one in your `main()`, set up it's `application` pointer, to\nactually point to a proper application instance, then you can call `main_loop()`.\n\n`main_loop()` runs on the main thread, so this will be the main loop in your app.\n\nNote: I'll add an async version later.\n\nYou can override `virtual void configure()` and `virtual void initialize();` to customize\nthe server's settings.\n\n### Database\n\nThe core Database class contains the api for querying database backends.\n\nThese are the methods that backends implement right now:\n\n```\n    virtual void connect(const std::string \u0026connection_str);\n    virtual QueryResult *query(const std::string \u0026query);\n    virtual void query_run(const std::string \u0026query);\n```\n\nUse these to set up database connections, and also to query the database.\n\nYou can also grab a proper `QueryBuilder` or `TableBuilder` instance for the backend using:\n\n```\n    virtual QueryBuilder *get_query_builder();\n    virtual TableBuilder *get_table_builder();\n```\n\n### DatabaseManager\n\nCan contain the active database backends. You should create one in your main, and set up\nany active database backends with it.\n\nIt can instance database backends, so you don't need to include them. This is so later\nthese can be created from config files.\n\nIf you want to create an sqlite database, do it like:\n\n```\n    DatabaseManager *dbm = DatabaseManager::get_singleton();\n\n    uint32_t index = dbm-\u003ecreate_database(\"sqlite\");\n    Database *db = dbm-\u003edatabases[index];\n    db-\u003econnect(\"database.sqlite\");\n```\n\nThe first created database will be set as default. This can be accesses using the `DatabaseManager`'s `ddb`\nmember variable. Like: DatabaseManager::get_singleton()-\u003eddb;\n\n### QueryBuilder\n\nWIP, not yet finished. Will be used to provide an abstraction layer for the different database engines.\n\nSimilar to CodeIgniter 3's query builders.\n\n### QueryResult\n\nThis is the base class for getting results from your database backend. The backends contain\nthe actual implementation for this. They'll also instance the proper one for themselves.\n\n### TableBuilder\n\nWIP, not yet finished. Will be used to provide an abstraction layer for the different database engines, \nbut this one will help with table creation / manipulation.\n\nSimilar to how CodeIgniter 3 handles this.\n\n### Utils\n\nCommon static utilities.\n\n### Request\n\nAn HTTP request. It contains every information for http sessions.\n\nRequests are pooled by default, you should now allocate them directly, instead\nyou should grab one from the `RequestPool` like: `Request *request = RequestPool::get_request();`.\n\n#### Sending Data\n\nIt has these methods for sending data:\n\n```\n    void send();\n    void send_file(const std::string \u0026p_file_path);\n    void send_error(int error_code);\n```\n\n`send()` will send the string that's set into `response`'s body.\nIf you want to set this directly do it like this: `request-\u003eresponse-\u003esetBody(\"\u003chtml\u003e...etc\u003c/html\u003e\");`\n\nAfter sending a request, it will automatically return to the pool.\n\nNote: Later they'll probably be refcounted, but right now you need to make sure to call\none of the send() like methods, as without it, the connection will be kept alive for quite awhile.\nAlso it will lead to memory leaks.\n\n#### HTTP Helpers\n\nIt also contains a few strings to help with the handling of http pages:\n\n```\n    std::string head;\n    std::string body;\n    std::string footer;\n```\n\nThese can be compiled into `std::string compiled_body;` with using `void compile_body();`.\n\n```\nvoid Request::compile_body() {\n\tcompiled_body.reserve(body.size() + head.size() + 13 + 14 + 15);\n\n\t//13\n\tcompiled_body += \"\u003chtml\u003e\"\n\t\t\t\t\t \"\u003chead\u003e\";\n\n\tcompiled_body += head;\n\n\t//14\n\tcompiled_body += \"\u003c/head\u003e\"\n\t\t\t\t\t \"\u003cbody\u003e\";\n\n\tcompiled_body += body;\n\tcompiled_body += footer;\n\n\t//15\n\tcompiled_body += \"\u003c/body\u003e\"\n\t\t\t\t\t \"\u003c/html\u003e\";\n\n\tresponse-\u003esetBody(compiled_body);\n}\n```\n\nYou can also use `void compile_and_send_body();` to both compile, and send the html.\n\n#### URI stacks.\n\nA Request contains a few helper methods to help with URI handling. These are:\n\n```\n    void setup_url_stack();\n    std::string get_path() const;\n    const std::string \u0026get_path_full() const;\n    const std::string \u0026get_path_segment(const uint32_t i) const;\n    const std::string \u0026get_current_path_segment() const;\n    uint32_t get_path_segment_count() const;\n    uint32_t get_current_segment_index() const;\n    uint32_t get_remaining_segment_count() const;\n    void pop_path();\n    void push_path();\n```\n\nWith this URI's can be thought as a stack. You can push and pop path segments.\n\nFor example let's take this path: 'Test/Data/Id/2'.\n\nBy default `get_path()` will return the full string, and `get_current_path_segment()` will return `Test`.\n\nHowever if we now use `push_path();` `get_path()` will return 'Data/Id/2', and `get_current_path_segment()` will return `Data`.\n\n`pop_path();` is the opposite of `push_path();`.\n\n\n### Settings\n\nWIP, not yet finished.\n\n### FileCahce\n\nWill store all existing files from a directory, so you don't have to constantly check the existence\nof files using the kernel.\n\nIf you pass true to it's constructor like `FileCache(true);` that instance will get set as a singleton.\n\nYou can evaluate a directory structure using `void wwwroot_evaluate_dir(const char *path, const bool should_exist = true);`.\n\n### Form Validator\n\nIt's a wip class. Doesn't work yet.\n\n### HTMLBuilder\n\nHelps with creating htmls.\n\nIt has methods for all standard html tags, and has methods for all closing tags aswell.\n\nA little example:\n\n```\n    HTMLBuilder b;\n\n    //Add a div, with the class content: \u003cdiv class=\"content\"\u003e\n    b.div()-\u003ecls(\"content\");\n\n    //header html tag: \u003cheader\u003e\n    b.header();\n\n    //just write the string \"My webpage\"\n    b.w(\"My webpage\");\n\n    //Add a span tag, with the class header_link: \u003cspan class=\"header_link\"\u003e\n    b.span()-\u003ecls(\"header_link\");\n\n    //Add a [ into the html: [\n    b.w(\" [ \");\n\n    //Add a link: \u003ca href=\"https://github.com/Relintai\"\u003e\n    b.a()-\u003ehref(\"https://github.com/Relintai\");\n\n    //just write the Github string: Github\n    b.w(\"Github\");\n\n    //Close the a tag: \u003c/a\u003e\n    b.ca();\n\n    //Add a ] into the html: ]\n    b.w(\" ]\");\n\n    //close the header tag \u003c/header\u003e\n    b.cheader();\n\n    //close the content div: \u003c/div\u003e\n    b.cdiv();\n\n    //Finish the currently open tag:\n    b.write_tag();\n\n    //print the resulting string\n    printf(\"%s\\n\", b.result.c_str());\n```\n\nThe resulting html should look like this:\n(Note that the generated string doesn't actually have newlines!)\n\n```\n\u003cdiv class=\"content\"\u003e\n    \u003cheader\u003e \n        My webpage\u003cspan class=\"header_link\"\u003e [ \u003ca href=\"https://github.com/Relintai\"\u003eGithub\u003c/a\u003e ]\n    \u003c/header\u003e\n\u003c/div\u003e\n```\n\n### Application\n\nThink about this class as a complete web application.\n\nIt contains helpers for basic routing, and has support for middlewares.\n\nInherit from this, and create one in your main.cpp.\n\nThe virtual methods should be called in this order after creation:\n\n```\n    app-\u003eload_settings();\n    app-\u003esetup_routes();\n    app-\u003esetup_middleware();\n```\n\n#### Overview\n\nThe HTTP server will turn an http request into a `Request`, then it will call the\n\n`void handle_request(Request *request);` of it's set `Application` instance.\n\nThe `handle_request` method will set up request's middleware stack, and then\nit will call `request-\u003enext_stage();`.\n\nNote: the middleware stack might be removed later, as Request now contains a pointer\nto it's owner application.\n\n#### Middlewares\n\nSet up your middlewares in the `setup_middleware` method.\n\nA middleware can be any method with this signature: `void middleware(Object *instance, Request *request);`.\n\nAny methods added to the `middlewares` vector is considered a middleware.\n\nEvery request will go through all middlewares in order, until they gets sent. For example with the `send()` method.\n\nIf a request doesn't gets sent, that connection will remain open, until a timeout occurs!\n\nExample middleware addition using a lambda:\n\n```\nvoid Application::setup_middleware() {\n\tmiddlewares.push_back(HandlerInstance([this](Object *instance, Request *request){ this-\u003edefault_routing_middleware(instance, request); }));\n}\n```\n\n#### Routing\n\nSet up your routes in the `setup_routes` method.\n\nBy default routing is handled by the `default_routing_middleware` method in `Application`.\n\nIt will look if a file exists in the main wwwroot first using the current path. If found it will send back that file.\n\nThen it checks if it just needs to call the index method. If so it will just call that.\n\nIf there are multiple segments in the uri, it will grab the first, check if there is a handler\nfor that segment, if so it will call that handler, after a `request-\u003epush_path();`.\n\nAs you can see this middleware is simple, it will not handle slugs, and complex url patterns.\nThis is by design, you should implement those by hand in the actual handlers.\n\n#### Error Handlers\n\nSet up your error handlers in the `setup_routes` method.\n\nSet your default fallback error handler method into the `default_error_handler_func` like:\n\n``` default_error_handler_func = Application::default_fallback_error_handler; ```\n\nWith the `error_handler_map` you can set different error handler methods for different\nerror codes like:\n\n``` error_handler_map[404] = Application::default_404_error_handler; ```\n\n#### Updates\n\nSometimes `Request`s need updates, for example while sending big files. As files gets sent in chunks.\nThis is necessary, because loading lots big files into the memory is probably not a good idea.\n\nSo when a request needs to get updated from time to time like this, they can be registered into\nthe `Application` instance using `void register_request_update(Request *request);`.\nWhen finished they can be removed with `void unregister_request_update(Request *request);`.\n\nNote `Application::update();` will get called by the http server.\n\n## Databases\n\nNote: Eventually you will be able to disable these one by one even if they can be compiled.\n\n### Sqlite3\n\nThe framework contains an sqlite implementation, so you should always have this available.\n\n### MySQL\n\nInstall MySQL or MariaDB for your linux distro, you should also get a package which contains the development headers.\n\nIt should be picked up by default if present.\n\n### PostgreSQL\n\nInstall PostgreSQL for your linux distro, you should also get a package which contains the development headers.\n\nIt should be picked up by default if present.\n\nNote that helper classes are not yet implemented for this backend right now.\n\n## Libs\n\nDon't forget to check the libraries in the libs folder, they can be directly included and used.\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frelintai%2Frcpp_framework","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frelintai%2Frcpp_framework","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frelintai%2Frcpp_framework/lists"}