Skip to content
/ paozhu Public

Paozhu🧨 C++ Web Framework,(Based on C++20) Support HTTP/1 HTTP/2, Rapid development of CRUD web applications, Include modules HttpServer HttpClient WebSocket ORM

License

Notifications You must be signed in to change notification settings

hggq/paozhu

Repository files navigation

English | 简体中文

Paozhu(炮竹🧨) is a comprehensive and fast C++ web framework that integrates C++ ORM. The development speed is as fast as script languages. The framework integrates a webserver, which can natively parse HTTP/1.1 HTTP/2 JSON WebSocket protocols and GET and POST requests. The framework also distinguishes between different methods of POST requests. The framework comes with a built-in OBJ micro-object that can store data such as char, int, string, float, etc. The framework automatically parses URL and POST parameters into the micro-object, and uses URL path mapping to function mounting points. It also uses coroutines, thread pools, and database connection pools.

QQ GROUP 668296235

Discussing the joy of C++ web development with community developers.

1.Features🔥🔥🔥🔥🔥

✅ 1. Support json decode encode, not use thirdparty, support json standard
✅ 2. Support multiple domain name websites
✅ 3. Support multiple domain name ssl server
✅ 4. Support http/1.1 and http/2 protocols
✅ 5. Support WebSocket server
✅ 6. The framework comes with websocket push, which supports regular push to websocket client
✅ 7. Support httpclient get or post
✅ 8. Built in ORM, currently only supports MySQL, providing coroutine and connection pooling functionality
✅ 9. Framework has two thread pool,framework thread pool,user program runing thread pool
✅10. The framework uses asio Coroutines
✅11. The framework features that I/O uses the coroutine pool to run and thread pool to run
✅12. The framework supports compress gzip br out files
✅13. URL POST Upload Files. use client.get[] client.post[] client.files[] get
✅14. Integrated sendmail
✅15. Generating QR code requires gd and qrencode libraries
✅16. Plugin module,Hot Module Replacement
✅17. The framework supports cache Module,ORM supports Result save to cache
✅18. The controller directory cpp files annotation auto pick to url mapping
✅19. Struct or class annotation to JSON Object, json_encode json_decode function
✅20. Support full demo admin backend, visit url /admin/main
✅21. Support PHP-FPM fastcgi running, which can replace Apache, allowing PHP programmers to smoothly transition to C++development mode

2.Runtime environment

C++ standard request c++20
asio openssl zlib brotli [options](gd qrencode)

3.environment configuration

3.1 MacOS

  • system requirements
>= BigSur
  • Install necessary dependencies
brew install asio
brew install mysql
brew install openssl
brew install zlib
brew install brotli

[options] brew install gd
[options] brew install qrencode

3.2 Ubuntu && Fedora

  • system requirements
Ubuntu>= 20.04 , test on Fedora38, need install asan(sudo yum install libasan)
sudo apt-get install cmake
sudo apt-get install -y brotli  libbrotli-dev zlib1g-dev
sudo apt-get install libgd-dev
sudo apt-get install qrencode libqrencode-dev
sudo apt-get install openssl libssl-dev
sudo apt-get install mysql-server
 

Notice: Requires gcc11 support. For more installation details, please see

3.3 Windows

Supports install methods vcpkg and xmake

  • xmake install Execute at the root directory of the project
    Config conf/server.conf replace /Users/hzq/paozhu path to your project path
paozhu-main> xmake
paozhu-main> .\build\windows\x64\release\paozhu.exe
  • vcpkg install
Invoke-WebRequest -OutFile vcpkg2023.zip https://github.com/microsoft/vcpkg/archive/refs/tags/2023.12.12.zip
            unzip vcpkg2023.zip
            cd vcpkg-2023.12.12
            bootstrap-vcpkg.bat
            vcpkg integrate install
            vcpkg integrate project
            vcpkg install

Install ninja https://github.com/ninja-build/ninja/releases

Compile project CMAKE_TOOLCHAIN_FILE is vcpkg install localtion path

unzip asio.zip
cmake . -B ${{github.workspace}} -DENABLE_WIN_VCPKG=ON -DENABLE_VCPKG=ON -DCMAKE_TOOLCHAIN_FILE=vcpkg-2023.12.12/scripts/buildsystems/vcpkg.cmake -DVCPKG_TARGET_TRIPLET=x64-windows -DCMAKE_BUILD_TYPE=Debug -G Ninja
cmake --build . --config Debug

4.Install

Project root unzip asio.zip or Download asio new version to project root part

|-vendor
|-CMakeLists.txt
|-asio
  |-asio
  |-asio.hpp

Directory like this

mkdir build
cd build
cmake ..
make

Use in production environment,Compile as daemon

cmake .. -DCMAKE_BUILD_TYPE=Release
make -j8

5.hosts configuration

  • viewconf/server.conffile and getmainhostvalue
  • replace /Users/hzq/paozhu path to your project path
  • open host file
sudo vim /etc/hosts

Add to the last line of the hosts file (if it is www.869869.com)

127.0.0.1 www.869869.com

6.https test

run

sudo ./bin/paozhu 

open the browser and enter http://localhost or http://www.869869.com in the address bar

for more details, please see the source code under the controller directory, which includes CRUD examples.

7.Stress testing

Use h2load and ab testing

 ab -n 120000 -c 20 http://www.xxx.com  
 h2load -n 12000 -c 100 -m 10 https://www.xxx.com  
 ./webbench -c 300 -t 59 http://www.xxx.com/cms/list  

8.1 Sample Hello world

On controller directory ,testhello.cpp file

#include "orm.h"
#include "httppeer.h"
#include "testhello.h"
namespace http
{
//@urlpath(null,hello)
std::string testhello(std::shared_ptr<httppeer> peer)
{
  httppeer &client = peer->get_peer();
  client << " Hello world! 🧨 Paozhu c++ web framework ";
	
  auto users = orm::cms::User();
  try
  {
    users.where("name","admin").fetch_one();
    if (users.getUserid() > 0)
    {
      client<<"<p>found:"<<users.data.name<<"</p>";
      return "";
    }
  }
  catch (std::exception &e)
  {
    client << "<p>" << e.what() << "</p>";
    return "";
  }
  return "";
}

}// namespace http

Open the browser and enter http://localhost/hello

//@urlpath(null,hello) is annotation

8.2 Sample Article list,search,pagebar

From admin demo file controller/src/admin/articles.cpp

#include "orm.h"
#include <chrono>
#include <thread>
#include "httppeer.h"
#include "func.h"
#include "articles.h"
#include "json_reflect_headers.h"
#include "array_to_tree.h"

//@urlpath(admin_islogin,admin/listarticle)
std::string admin_listarticle(std::shared_ptr<httppeer> peer)
{
    httppeer &client = peer->get_peer();
    try
    {
        auto topicm = orm::cms::Topic();
        topicm.where("userid", client.session["userid"].to_int()).asc("parentid").fetch();

        unsigned int topicid   = client.get["topicid"].to_int();
        unsigned int page      = client.get["page"].to_int();
        std::string searchword = client.get["searchword"].to_string();
        searchword             = mb_substr(searchword, 0, 15);
        client.val["topicid"]  = topicid;

        client.val["list"].set_array();
        OBJ_ARRAY temp;

        std::map<unsigned int, std::string> topickv;
        std::vector<unsigned int> topic_id_array;//articles under this topic and sub topics

        if (topicid > 0)
        {
            topic_id_array.push_back(topicid);
        }

        for (unsigned int i = 0; i < topicm.record.size(); i++)
        {
            temp["id"]       = topicm.record[i].topicid;
            temp["parentid"] = topicm.record[i].parentid;
            temp["value"]    = topicm.record[i].title;
            client.val["list"].push(temp);

            topickv[topicm.record[i].topicid] = topicm.record[i].title;
            if (topicid > 0)
            {
                for (unsigned int j = 0; j < topic_id_array.size(); j++)
                {
                    if (topicm.record[i].parentid == topic_id_array[j])
                    {
                        topic_id_array.push_back(topicm.record[i].topicid);
                        break;
                    }
                }
            }
        }

        auto artmodel = orm::cms::Article();
        artmodel.where("userid", client.session["userid"].to_int());
        if (topicid > 0)
        {
            std::string topicid_sql_str = array_to_sql(topic_id_array);
            if (topicid_sql_str.size() > 0)
            {
                artmodel.whereIn("topicid", topicid_sql_str);
            }
        }
        if (searchword.size() > 0)
        {
            artmodel.andsub().whereLike("title", str_addslash(searchword));
            artmodel.whereOrLike("content", str_addslash(searchword)).andsub();
            client.val["searchword"] = searchword;
        }
        auto [bar_min, bar_max, current_page, total_page] = artmodel.page(page, 10, 5);

        client.val["pageinfo"].set_array();
        client.val["pageinfo"]["min"]     = bar_min;
        client.val["pageinfo"]["max"]     = bar_max;
        client.val["pageinfo"]["current"] = current_page;
        client.val["pageinfo"]["total"]   = total_page;

        artmodel.select("aid,topicid,title,createtime,sortid,isopen").desc("aid").fetch();
        client.val["alist"].set_array();
        OBJ_ARRAY tempa;

        if (artmodel.size() > 0)
        {
            for (auto &item : artmodel)
            {
                tempa["title"]     = item.title;
                tempa["aid"]       = item.aid;
                tempa["date"]      = item.createtime.substr(0, 10);
                tempa["topicname"] = topickv[item.topicid];
                tempa["sortid"]    = item.sortid;
                tempa["isopen"]    = item.isopen;
                client.val["alist"].push(tempa);
            }
        }
    }
    catch (std::exception &e)
    {
        client.val["code"] = 1;
    }
    peer->view("admin/listarticle");
    return "";
}

C++ ORM Coroutines,Only supports MySQL,URL request is completed throughout the entire coroutine function
From admin demo file controller/src/techempower.cpp

//@urlpath(null,updates)
asio::awaitable<std::string> techempowerupdates(std::shared_ptr<httppeer> peer)
{
    peer->type("application/json; charset=UTF-8");
    peer->set_header("Date", get_gmttime());
    unsigned int get_num = peer->get["queries"].to_int();

    if (get_num == 0)
    {
        get_num = 1;
    }
    else if (get_num > 500)
    {
        get_num = 500;
    }
    auto myworld = orm::World();
    myworld.record.clear();
    myworld.record.reserve(get_num);
    for (unsigned int i = 0; i < get_num; i++)
    {
        myworld.wheresql.clear();
        myworld.where("id", rand_range(1, 10000));
        co_await myworld.async_fetch_append();
        if (myworld.effect() > 0)
        {
            unsigned int j                 = myworld.record.size() - 1;
            myworld.data.randomnumber      = rand_range(1, 10000);
            myworld.record[j].randomnumber = myworld.data.randomnumber;
            co_await myworld.async_update("randomnumber");
        }
    }
    peer->output = myworld.to_json();
    co_return "";
}

9.Related tutorial

  1. paozhu Principle

  2. paozhu hello world

  3. paozhu ORM

  4. paozhu view

  5. paozhu CRUD

10.Roadmap

  • 1.Improved HTTP features
  • 2.Use C++ parse JSX file , Server Side Rendering
  • 3.Httpclient Improved,Support Protocol forwarding
  • 4.Websocket client
  • 5.HTTP/2 client
  • 6.Postgres,sqlite ORM

11.Contribute👏👋

welcome to raise issues for mutual communication, and of course, we also welcome your active PR.

12.LICENSE

Paozhu is provided under the MIT License

About

Paozhu🧨 C++ Web Framework,(Based on C++20) Support HTTP/1 HTTP/2, Rapid development of CRUD web applications, Include modules HttpServer HttpClient WebSocket ORM

Topics

Resources

License

Stars

Watchers

Forks

Contributors 4

  •  
  •  
  •  
  •