### Build benchmarks using setup script Source: https://github.com/okyfirmansyah/libasyik/blob/master/docs/benchmarking.md Executes the automated setup script to install dependencies and compile all benchmark binaries. ```bash bash benchmarks/setup.sh ``` -------------------------------- ### Basic CMake Project Setup Source: https://github.com/okyfirmansyah/libasyik/blob/master/CMakeLists.txt Initializes the CMake build system for the libasyik project and sets the minimum required version. This is a standard starting point for any CMake project. ```cmake cmake_minimum_required(VERSION 3.14) project(libasyik) ``` -------------------------------- ### Basic HTTP Server Setup Source: https://github.com/okyfirmansyah/libasyik/blob/master/README.md Initializes a service and an HTTP server to handle requests on a specific route. ```c++ #include "libasyik/service.hpp" #include "libasyik/http.hpp" void main() { auto as = asyik::make_service(); auto server = asyik::make_http_server(as, "127.0.0.1", 8080); // serve http request server->on_http_request("/hello", "GET", [](auto req, auto args) { req->response.body = "Hello world!"; req->response.result(200); }); as->run(); } ``` -------------------------------- ### Build and Install Libasyik Source: https://github.com/okyfirmansyah/libasyik/blob/master/README.md Steps to clone the repository, update submodules, build, and install Libasyik using CMake and Make. Ensure all build requirements are met beforehand. ```bash cd ~ git clone https://github.com/okyfirmansyah/libasyik cd ~/libasyik git submodule update --init --recursive mkdir build cd build cmake .. make -j4 make install ``` -------------------------------- ### Install Project Target and Headers Source: https://github.com/okyfirmansyah/libasyik/blob/master/CMakeLists.txt Defines installation rules for the main project target and its header files. This command specifies the destination directories for libraries and include files. ```cmake install( TARGETS ${PROJECT_NAME} EXPORT ${PROJECT_NAME} DESTINATION "${CMAKE_INSTALL_LIBDIR}" ) install( DIRECTORY ${PROJECT_SOURCE_DIR}/include/ DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" ) ``` -------------------------------- ### PostgreSQL SQL Connection Setup Source: https://github.com/okyfirmansyah/libasyik/blob/master/docs/sql.md Shows how to configure the SQL connection pool for PostgreSQL. Adjust connection parameters as needed for your environment. ```c++ #include "libasyik/service.hpp" #include "libasyik/sql.hpp" void some_handler(asyik::service_ptr as) { auto pool = make_sql_pool(asyik::sql_backend_postgresql, "host=localhost dbname=postgres password=test user=postgres", 4 // use 4 connection pooling ); auto ses = pool->get_session(as); ses->query(R"(CREATE TABLE IF NOT EXISTS persons (id int, name varchar(255)));"); int id=1; int out_id; std::string name; ses->query("select * from persons where id=:id", soci::use(id), soci::into(out_id), soci::into(name)); ... } ``` -------------------------------- ### Install CMake Configuration Files Source: https://github.com/okyfirmansyah/libasyik/blob/master/CMakeLists.txt Installs the CMake configuration files for the project. These files are used by other projects to find and link against the installed libasyik library. ```cmake install( FILES ${PROJECT_NAME}-config.cmake DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}" ) install( EXPORT ${PROJECT_NAME} DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}" ) ``` -------------------------------- ### Example: Multiple Channels and Threads Source: https://github.com/okyfirmansyah/libasyik/blob/master/docs/sql.md Illustrates listening on multiple channels concurrently and handling notifications from multiple threads. ```APIDOC ## Example: Multiple Channels and Threads ### Description This example demonstrates listening to multiple channels simultaneously and handling notifications originating from different threads, showcasing thread-safety and asynchronous handling. ### Code ```c++ auto listener = pool->get_session(as); std::atomic received{0}; std::mutex mtx; std::condition_variable cv; for (const auto &ch : {"chan1","chan2","chan3"}) { listener->listen(ch, [&](const std::string& channel, const std::string& payload){ { std::lock_guard g(mtx); ++received; } cv.notify_one(); }); } // spawn multiple threads that notify different channels std::vector threads; for (int i = 0; i < 4; ++i) { threads.emplace_back([pool, as, i]() { auto s = pool->get_session(as); std::string ch = (i % 2 == 0) ? "chan1" : "chan2"; s->query(std::string("NOTIFY ") + ch + ", 'p" + std::to_string(i) + "';"); }); } // wait for notifications (simple timeout) { std::unique_lock lk(mtx); cv.wait_for(lk, std::chrono::seconds(5), [&]{ return received.load() >= 4; }); } for (auto &t : threads) t.join(); listener->unlisten_all(); ``` ``` -------------------------------- ### HTTP Client Requests Source: https://github.com/okyfirmansyah/libasyik/blob/master/AGENT.md Demonstrates making various HTTP requests (GET, POST) using a simplified client interface, including support for timeouts and HTTPS. ```cpp #include "libasyik/http.hpp" // Simple GET auto req = asyik::http_easy_request(as, "GET", "http://example.com/api"); if (req->response.result() == 200) { std::string body = req->response.body; } // POST with body and headers auto req = asyik::http_easy_request(as, "POST", "http://example.com/api", "payload", {{"content-type", "application/json"}, {"authorization", "Bearer xyz"}}); // With timeout in milliseconds auto req = asyik::http_easy_request(as, 5000, "GET", "http://example.com/slow"); // HTTPS works transparently auto req = asyik::http_easy_request(as, "GET", "https://example.com/secure"); ``` -------------------------------- ### Example: Single Channel Notification Source: https://github.com/okyfirmansyah/libasyik/blob/master/docs/sql.md Demonstrates how to listen to a single PostgreSQL channel, send a notification, and then stop listening. ```APIDOC ## Example: Single Channel Notification ### Description This example shows a basic usage pattern for listening to a single channel, receiving a notification, and then unsubscribing. ### Code ```c++ // assume `as` is a service_ptr and `pool` is a sql_pool_ptr auto ses = pool->get_session(as); ses->listen("my_channel", [](const std::string& channel, const std::string& payload) { // runs on the service worker std::cout << "got notify on " << channel << ": " << payload << "\n"; }); // send a notification from another session auto sender = pool->get_session(as); sender->query("NOTIFY my_channel, 'hello_world';"); // later, stop listening ses->unlisten("my_channel"); ``` ``` -------------------------------- ### Build Beast with io_uring Backend Source: https://github.com/okyfirmansyah/libasyik/blob/master/benchmarks/CMakeLists.txt Configures the 'bench_beast_iouring' executable to use Boost.Beast with io_uring. This requires the same io_uring and Boost setup as the Asio variant. Compile definitions BOOST_ASIO_HAS_IO_URING and BOOST_ASIO_DISABLE_EPOLL are essential. ```cmake # Beast-over-io_uring variant add_executable(bench_beast_iouring beast/bench_beast.cpp) target_compile_features(bench_beast_iouring PRIVATE cxx_std_17) target_compile_options(bench_beast_iouring PRIVATE ${BENCH_COMPILE_FLAGS}) target_include_directories(bench_beast_iouring PRIVATE ${Boost_INCLUDE_DIR} ${URING_INCLUDE_DIR}) target_compile_definitions(bench_beast_iouring PRIVATE BOOST_ASIO_HAS_IO_URING=1 BOOST_ASIO_DISABLE_EPOLL=1 ) target_link_libraries(bench_beast_iouring PRIVATE Threads::Threads ${URING_LIB}) message(STATUS "Benchmark target: bench_beast_iouring (Beast + io_uring backend, port 8089 by default)") ``` -------------------------------- ### Create and Use Single-Threaded Memcache Source: https://github.com/okyfirmansyah/libasyik/blob/master/docs/cache.md Demonstrates creating a single-threaded memcache with a 1-second expiration and 50 segments. Use `get()` to prolong TTL and `at()` which does not prolong TTL. Items expired when `at()` is called. ```c++ #include "catch2/catch.hpp" #include "libasyik/error.hpp" #include "libasyik/service.hpp" #include "libasyik/memcache.hpp" auto as = asyik::make_service(); // create cache with expiration 1s, with 50segments auto cache = asyik::make_memcache(as); as->execute([cache, as]() { // insert few datas cache->put("1", 1); cache->put("2", 2); cache->put("3", 3); asyik::sleep_for(std::chrono::milliseconds(960)); REQUIRE(cache->get("1")==1); // should be there, get() will prolong the TTL REQUIRE(cache->at("2")==2); // should be there, but at() will not prolong the TTL cache->put("3", 3); // update and prolong "3" item's TTL asyik::sleep_for(std::chrono::milliseconds(960)); REQUIRE(cache->get("1")==1); // "1" will stil valid, as it prolonged by get() REQUIRE(cache->get("3")==3); // "3" will still valid too auto i = cache->at("2"); // expired, will throw std::out_of_range exception }); as->run(); ``` -------------------------------- ### Build Raw io_uring Benchmark Source: https://github.com/okyfirmansyah/libasyik/blob/master/benchmarks/CMakeLists.txt Configures the 'bench_io_uring' executable to use raw liburing without Boost. This setup focuses solely on the io_uring interface. It requires liburing to be found and linked. ```cmake # Raw io_uring (liburing only, no Boost) add_executable(bench_io_uring io_uring/bench_io_uring.cpp) target_compile_features(bench_io_uring PRIVATE cxx_std_17) target_compile_options(bench_io_uring PRIVATE ${BENCH_COMPILE_FLAGS}) target_include_directories(bench_io_uring PRIVATE ${URING_INCLUDE_DIR}) target_link_libraries(bench_io_uring PRIVATE Threads::Threads ${URING_LIB}) message(STATUS "Benchmark target: bench_io_uring (raw liburing, port 8087 by default)") ``` -------------------------------- ### Create HTTP Server with Route Matching Source: https://context7.com/okyfirmansyah/libasyik/llms.txt Demonstrates creating an HTTP server and defining routes with typed arguments like string, int, and path. ```cpp #include "libasyik/service.hpp" #include "libasyik/http.hpp" int main() { auto as = asyik::make_service(); auto server = asyik::make_http_server(as, "127.0.0.1", 8080); // Basic route server->on_http_request("/hello", "GET", [](auto req, auto args) { req->response.body = "Hello World!"; req->response.result(200); }); // Route with string argument - args[1] contains the captured value server->on_http_request("/users/", "GET", [](auto req, auto args) { req->response.body = "User: " + args[1]; req->response.result(200); }); // Route with multiple typed arguments server->on_http_request("/users//posts/", "GET", [](auto req, auto args) { std::string user = args[1]; std::string post_id = args[2]; req->response.body = "User " + user + ", Post ID: " + post_id; req->response.result(200); }); // Catch-all path argument server->on_http_request("/files/", "GET", [](auto req, auto args) { req->response.body = "File path: " + args[1]; req->response.result(200); }); as->run(); } ``` -------------------------------- ### Install External Library Headers Source: https://github.com/okyfirmansyah/libasyik/blob/master/CMakeLists.txt Installs header files from external dependencies into the project's include directory structure. This makes them available for users of the installed library. ```cmake install( DIRECTORY ${PROJECT_SOURCE_DIR}/external/aixlog/include/ DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}/external/" ) install( DIRECTORY ${PROJECT_SOURCE_DIR}/external/cppcodec/ DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}/external/" ) ``` -------------------------------- ### Basic HTTP Server with Arguments Source: https://github.com/okyfirmansyah/libasyik/blob/master/docs/http.md Set up an HTTP server to handle requests with string and integer arguments captured from the URL path. Ensure arguments are accessed from index 1 onwards in the `args` vector. ```c++ #include "libasyik/service.hpp" #include "libasyik/http.hpp" void main() { auto as = asyik::make_service(); auto server = asyik::make_http_server(as, "127.0.0.1", 4004); // accept string argument server->on_http_request("/name/", "GET", [](auto req, auto args) { req->response.body = "Hello " + args[1] + "!"; req->response.result(200); }); // accept string and int arguments server->on_http_request("/name//", "GET", [](auto req, auto args) { req->response.body = "Hello " + args[1] + "! " + "int=" + args[2]; req->response.result(200); }); as->run(); } ``` -------------------------------- ### Get Remote Endpoint Source: https://context7.com/okyfirmansyah/libasyik/llms.txt Retrieves the client's IP address and port from an active connection handle. ```cpp #include "libasyik/service.hpp" #include "libasyik/http.hpp" int main() { auto as = asyik::make_service(); auto server = asyik::make_http_server(as, "127.0.0.1", 8080); server->on_http_request("/whoami", "GET", [server](auto req, auto args) { auto connection = req->get_connection_handle(server); auto ep = connection->get_remote_endpoint(); req->response.body = "Your IP: " + ep.address().to_string() + ":" + std::to_string(ep.port()); req->response.result(200); }); as->run(); } // curl http://127.0.0.1:8080/whoami // Output: Your IP: 127.0.0.1:54321 ``` -------------------------------- ### Async Write with Boost.Asio and Libasyik Source: https://github.com/okyfirmansyah/libasyik/blob/master/docs/integration.md Demonstrates using `asyik::use_fiber_future` with `asio::async_write_some` for server-sent events. Ensure the server is set up before this operation. ```c++ int main() { auto as = asyik::make_service(); auto server = asyik::make_http_server(as, "127.0.0.1", 4004); server->on_http_request("/sse", "GET", [server](auto req, auto args) { auto connection = req->get_connection_handle(server); auto &stream = connection->get_stream(); req->activate_direct_response_handling(); // at this point we own connection/stream directly.. std::string s= "HTTP/1.1 200 OK\r\n" "Connection: keep-alive\r\n" "Content-type: text/event-stream\r\n\r\n" "retry: 5000\r\n\r\n"; // note: libasyik provide asyik::use_fiber_future to turn // any boost asio's API into yield-enable fiber future stream.async_write_some(asio::buffer(s.data(), s.length()), asyik::use_fiber_future).get(); // now sending stream of events indefinitely int i=0; for(;;) { std::string body="event: foo\r\n" "data: halo "+std::to_string(i++)+"\r\n" "\r\n"; stream.async_write_some(asio::buffer(body.data(), body.length()), asyik::use_fiber_future).get(); asyik::sleep_for(std::chrono::seconds(1)); } }); as->run(); } ``` -------------------------------- ### Serve Static Files Source: https://github.com/okyfirmansyah/libasyik/blob/master/docs/http.md Map URL prefixes to local directory paths to serve static assets automatically. ```c++ #include "libasyik/service.hpp" #include "libasyik/http.hpp" int main() { auto as = asyik::make_service(); auto server = asyik::make_http_server(as, "127.0.0.1", 8080); // All GET /static/* requests are served from /var/www/html server->serve_static("/static", "/var/www/html"); as->run(); } ``` -------------------------------- ### Initialize Libasyik HTTP and WebSocket Server Source: https://github.com/okyfirmansyah/libasyik/blob/master/docs/designs.md Sets up a basic server handling HTTP requests and WebSocket connections within a single-threaded fiber environment. ```c++ void main() { auto as = asyik::make_service(); auto server = asyik::make_http_server(as, "127.0.0.1", 4004); // serve http request(can coexists with websocker endpoints) server->on_http_request("/hello", "GET", [](auto req, auto args) { req->response.body = "Hello world!"; req->response.result(200); }); // serve websocket server->on_websocket("/websocket", [](auto ws, auto args) { // executed as lightweight process/fiber while(1) { auto s = ws->get_string(); ws->send_string(s); //echo } ws->close(asyik::websocket_close_code::normal, "closed normally"); }); as->run(); } ``` -------------------------------- ### Create In-Memory TTL Cache Source: https://context7.com/okyfirmansyah/libasyik/llms.txt Initializes a segmented cache with automatic expiration. Note that 'get' extends the TTL while 'at' does not. ```cpp #include "libasyik/service.hpp" #include "libasyik/memcache.hpp" int main() { auto as = asyik::make_service(); // Cache // 60 second TTL, 10 segments = ~6 second accuracy auto cache = asyik::make_memcache(as); as->execute([cache, as]() { // Store values cache->put("user:123", R"({"name": "John", "role": "admin"})"); cache->put("config:app", R"({"theme": "dark", "lang": "en"})"); // Retrieve with TTL extension try { std::string user = cache->get("user:123"); // Extends TTL LOG(INFO) << "User data: " << user << "\n"; std::string config = cache->at("config:app"); // Does NOT extend TTL LOG(INFO) << "Config: " << config << "\n"; } catch (const std::out_of_range& e) { LOG(WARNING) << "Cache miss\n"; } // Remove entry cache->erase("user:123"); as->stop(); }); as->run(); } ``` -------------------------------- ### Map multiple prefixes and HTTPS static serving Source: https://github.com/okyfirmansyah/libasyik/blob/master/docs/http.md Demonstrates mapping multiple URL prefixes to directories and applying static serving to HTTPS servers. ```c++ server->serve_static("/static", "/var/www/html"); server->serve_static("/downloads", "/srv/files"); // Works the same way on an HTTPS server auto https_server = asyik::make_https_server(as, std::move(ssl_ctx), "0.0.0.0", 443); https_server->serve_static("/static", "/var/www/html"); ``` -------------------------------- ### Link Libraries Source: https://github.com/okyfirmansyah/libasyik/blob/master/tests/CMakeLists.txt Links the project executable against the libasyik library and the Catch2 testing framework. Ensure Catch2 is installed or available in the CMake environment. ```cmake target_link_libraries(${PROJECT_NAME} libasyik Catch2::Catch2) ``` -------------------------------- ### HTTP Routing with Arguments Source: https://github.com/okyfirmansyah/libasyik/blob/master/README.md Demonstrates pattern matching in HTTP routes to extract string and integer parameters. ```c++ void main() { auto as = asyik::make_service(); auto server = asyik::make_http_server(as, "127.0.0.1", 4004); // accept string argument server->on_http_request("/name/", "GET", [](auto req, auto args) { req->response.body = "Hello " + args[1] + "!"; req->response.result(200); }); // accept string and int arguments server->on_http_request("/name//", "GET", [](auto req, auto args) { req->response.body = "Hello " + args[1] + "! " + "int=" + args[2]; req->response.result(200); }); as->run(); } ``` -------------------------------- ### Multiple Static File Prefixes and HTTPS Source: https://github.com/okyfirmansyah/libasyik/blob/master/docs/http.md Demonstrates how to serve static files from different directories using multiple `serve_static` calls and how this applies to HTTPS servers. ```APIDOC ## GET /api/users/{userId} ### Description Retrieves the details of a specific user. ### Method GET ### Endpoint /api/users/{userId} ### Parameters #### Path Parameters - **userId** (string) - Required - The unique identifier of the user to retrieve. ### Response #### Success Response (200 OK) - **userId** (string) - The unique identifier of the user. - **username** (string) - The username of the user. - **email** (string) - The email address of the user. #### Response Example ```json { "userId": "user-12345", "username": "johndoe", "email": "john.doe@example.com" } ``` ``` -------------------------------- ### Configure libasyik benchmark target Source: https://github.com/okyfirmansyah/libasyik/blob/master/benchmarks/CMakeLists.txt Sets up the bench_server executable with necessary include directories and links against the libasyik library. ```cmake cmake_minimum_required(VERSION 3.14) project(libasyik_bench) # ── Release build with full optimizations ───────────────────────────────── # Always build benchmarks in Release mode regardless of parent build type set(BENCH_COMPILE_FLAGS -O3 -DNDEBUG -march=native) add_executable(bench_server libasyik/bench_server.cpp) target_compile_options(bench_server PRIVATE ${BENCH_COMPILE_FLAGS}) # Inherit include paths that libasyik sources use target_include_directories(bench_server PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../external/aixlog/include ${CMAKE_CURRENT_SOURCE_DIR}/../external/cppcodec ) # Link against the libasyik target defined by the parent CMakeLists.txt target_link_libraries(bench_server PRIVATE libasyik) ``` -------------------------------- ### Blocking Operations to Avoid in Fibers Source: https://github.com/okyfirmansyah/libasyik/blob/master/docs/service.md Examples of synchronous I/O or CPU-intensive tasks that will block the entire asyik::service scheduler if called directly within a fiber. ```c++ as->execute( []() { ... // synchronois I/O function, will block entire scheduler! boost::asio::connect(...); ... } ); ``` ```c++ as->execute( []() { ... // This indeed gives up thread execution, // but the entire scheduler in the same thread will be blocked! // Use dedicated fiber's API for this kind of functions usleep(1000); ... } ); ``` ```c++ as->execute( []() { ... // intensive CPU, will blocks scheduler/other fibers do_some_AI_deep_learning_sync_process(); ... } ); ``` -------------------------------- ### Listen to a Single PostgreSQL Channel Source: https://github.com/okyfirmansyah/libasyik/blob/master/docs/sql.md Starts listening on a specified channel and defines a handler for incoming notifications. Send a notification from another session and then stop listening. ```c++ // assume `as` is a service_ptr and `pool` is a sql_pool_ptr auto ses = pool->get_session(as); ses->listen("my_channel", [](const std::string& channel, const std::string& payload) { // runs on the service worker std::cout << "got notify on " << channel << ": " << payload << "\n"; }); // send a notification from another session auto sender = pool->get_session(as); sender->query("NOTIFY my_channel, 'hello_world';"); // later, stop listening ses->unlisten("my_channel"); ``` -------------------------------- ### Spawn Concurrent Fibers Source: https://github.com/okyfirmansyah/libasyik/blob/master/docs/service.md Shows how to use asyik::service to execute multiple fibers concurrently. ```c++ #include "libasyik/service.hpp" int main() { auto as = asyik::make_service(); as->execute( // spawn fiber concurrently []() { while(1) { asyik::sleep_for(std::chrono::seconds(1)); LOG(INFO)<<"Fiber A!\n"; } } ); as->execute( // spawn fiber concurrently []() { while(1) { asyik::sleep_for(std::chrono::seconds(2)); LOG(INFO)<<"Fiber B!\n"; } } ); // start service and fiber scheduler as->run(); } ``` -------------------------------- ### Propagate Exceptions Through Fibers::Future Source: https://github.com/okyfirmansyah/libasyik/blob/master/AGENT.md Shows how exceptions thrown within a fiber can be caught outside by using `fibers::future.get()`. This example catches a custom `asyik::not_found_error`. ```cpp try { int result = as->execute([]() -> int { throw asyik::not_found_error("missing item"); }).get(); } catch (asyik::not_found_error& e) { // handle error } ``` -------------------------------- ### Set Minimum CMake Version and Project Name Source: https://github.com/okyfirmansyah/libasyik/blob/master/tests/CMakeLists.txt Specifies the minimum required CMake version and defines the project name. This is a standard starting point for any CMake project. ```cmake cmake_minimum_required(VERSION 3.14) project(libasyik_test) ``` -------------------------------- ### Create HTTPS Server with WebSocket and HTTP Handlers Source: https://github.com/okyfirmansyah/libasyik/blob/master/docs/http.md Sets up an HTTPS server using SSL context, loads a server certificate, and registers handlers for both WebSocket connections and HTTP requests. Ensure SSL context creation and certificate loading are handled correctly. ```c++ #include "libasyik/service.hpp" #include "libasyik/http.hpp" int main() { auto as = asyik::make_service(); // The SSL context is required, and holds certificates ssl::context ctx{ssl::context::tlsv12}; // This holds the self-signed certificate used by the server load_server_certificate(ctx); auto server = asyik::make_https_server(as, std::move(ctx), "127.0.0.1", 443); server->on_websocket("/ws", [](auto ws, auto args) { auto s = ws->get_string(); ws->send_string(s); ws->close(websocket_close_code::normal, "closed normally"); }); server->on_http_request("/", "GET", [](auto req, auto args) { req->response.body = "hello world"; req->response.result(200); }); as->run(); } ``` -------------------------------- ### Basic SQL Usage with SQLite Source: https://github.com/okyfirmansyah/libasyik/blob/master/docs/sql.md Demonstrates basic SQL operations using SQLite with Libasyik. Ensure to set pool size to 1 for SQLite due to concurrency limitations. ```c++ #include "libasyik/service.hpp" #include "libasyik/sql.hpp" void some_handler(asyik::service_ptr as) { // SQlite3 doesn't really support concurrent access, so we set pool=1 auto pool = make_sql_pool(asyik::sql_backend_sqlite3, "test.db", 1); auto ses = pool->get_session(as); ses->query(R"(CREATE TABLE IF NOT EXISTS persons (id int, name varchar(255)));"); int id=1; int out_id; std::string name; ses->query("select * from persons where id=:id", soci::use(id), soci::into(out_id), soci::into(name)); ... } ``` -------------------------------- ### Expected Logging Output Source: https://github.com/okyfirmansyah/libasyik/blob/master/docs/logging.md This is the expected console output when the C++ logging example is executed. It shows messages from DEBUG, INFO, WARNING, and ERROR levels, with timestamps and source information. ```text root@desktop:/workspaces/test/build# ./test 2020-06-21 04-33-50.930 [Debug] (main) This is DEBUG log(shown) 2020-06-21 04-33-50.930 [Info] (main) This is INFO log 2020-06-21 04-33-50.930 [Warn] (main) This is WARNING log 2020-06-21 04-33-50.930 [Error] (main) This is ERROR log ``` -------------------------------- ### Configure libasyik raw benchmark target Source: https://github.com/okyfirmansyah/libasyik/blob/master/benchmarks/CMakeLists.txt Builds the bench_libasyik_raw target using asyik::service for fiber scheduling with raw Asio TCP. ```cmake add_executable(bench_libasyik_raw libasyik_raw/bench_libasyik_raw.cpp) target_compile_features(bench_libasyik_raw PRIVATE cxx_std_17) target_compile_options(bench_libasyik_raw PRIVATE ${BENCH_COMPILE_FLAGS}) target_include_directories(bench_libasyik_raw PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../external/aixlog/include ${CMAKE_CURRENT_SOURCE_DIR}/../external/cppcodec ) target_link_libraries(bench_libasyik_raw PRIVATE libasyik) ``` -------------------------------- ### Create Service Instance with make_service Source: https://context7.com/okyfirmansyah/libasyik/llms.txt Initializes the main service instance to manage the event loop and fiber scheduler. One instance corresponds to a single thread. ```cpp #include "libasyik/service.hpp" int main() { auto as = asyik::make_service(); as->execute([]() { LOG(INFO) << "Fiber A running\n"; asyik::sleep_for(std::chrono::seconds(1)); LOG(INFO) << "Fiber A done\n"; }); as->execute([]() { LOG(INFO) << "Fiber B running\n"; asyik::sleep_for(std::chrono::milliseconds(500)); LOG(INFO) << "Fiber B done\n"; }); // Start the event loop - blocks until as->stop() is called as->run(); // Or auto-stop when all fibers complete: // as->run(true); } ``` -------------------------------- ### Create an In-Memory Cache Source: https://github.com/okyfirmansyah/libasyik/blob/master/AGENT.md Initializes an in-memory cache with a specified Time-To-Live (TTL) and number of segments. Supports basic put, get, and erase operations. A thread-safe variant is also available. ```cpp #include "libasyik/memcache.hpp" // TTL = 60 seconds, 4 segments auto cache = asyik::make_memcache(as); cache->put("key", "value"); auto val = cache->get("key"); // extends TTL cache->erase("key"); // Thread-safe variant (uses fibers::mutex internally) auto mt_cache = asyik::make_memcache_mt(as); ``` -------------------------------- ### HTTP Client Requests Source: https://github.com/okyfirmansyah/libasyik/blob/master/docs/http.md Perform HTTP GET and POST requests using `http_easy_request`. Supports custom payloads, headers, and configurable timeouts. Ensure the service is run to process asynchronous requests. ```c++ #include "libasyik/service.hpp" #include "libasyik/http.hpp" int main() { auto as = asyik::make_service(); // spawn new fiber as->execute( [&completed, as]() { auto req = asyik::http_easy_request(as, "GET", "https://tls-v1-2.badssl.com:1012/"); if(req->response.result()==200) { LOG(INFO)<<"Body= extvariable="<response.body<<"\n"; LOG(INFO)<<"request success!\n"; } // post with payload and additional headers auto req2 = asyik::http_easy_request(as, "POST", "http://some-host/api", "this is payload", { {"x-test", "ok"} //headers }); if(req2->response.result()==200) { LOG(INFO)<<"Body="<response.body<<"\n"; LOG(INFO)<<"request success!\n"; } // do client request again, but with TIMEOUT=10s (default is 30s) auto req3 = asyik::http_easy_request(as, 10000, //timeout in ms "POST", "http://some-host/api", "this is payload", { {"x-test", "ok"} //headers }); if(req3->response.result()==200) { LOG(INFO)<<"Body="<response.body<<"\n"; LOG(INFO)<<"request success!\n"; } as->stop(); } ); // start service and fiber scheduler as->run(); } ``` -------------------------------- ### Using Promise-Future Pattern with execute() and async() Source: https://github.com/okyfirmansyah/libasyik/blob/master/docs/service.md Demonstrates how to spawn asynchronous tasks and wait for their results using fiber::future. ```c++ #include "libasyik/service.hpp" int main() { auto as = asyik::make_service(); auto read_fu1 = as->execute( [as]()->size_t { return read_some_data(...); } ); auto read_fu2 = as->async( [as]()->size_t { return fread(...); } ); // and now wait for both value final result auto read_sz1=read_fu1.get(); auto read_sz2=read_fu2.get(); } ``` -------------------------------- ### Handle Multipart Responses with http_easy_request_multipart Source: https://context7.com/okyfirmansyah/libasyik/llms.txt Use http_easy_request_multipart to process streaming multipart data like MJPEG. A callback function is invoked for each received part. The example demonstrates stopping after a certain number of frames. ```cpp #include "libasyik/service.hpp" #include "libasyik/http.hpp" int main() { auto as = asyik::make_service(); as->execute([as]() { int frame_count = 0; // MJPEG stream handling asyik::http_easy_request_multipart(as, 30000, // 30 second timeout "GET", "http://camera.local/mjpeg", [&frame_count](asyik::http_request_ptr req) { // Called for each frame/part received std::string content_type{req->multipart_response.headers["content-type"]}; std::string& body = req->multipart_response.body; LOG(INFO) << "Frame " << frame_count++ << ", size: " << body.length() << " bytes\n"; // Process frame data... if (frame_count >= 100) { // Signal to stop after 100 frames throw std::runtime_error("done"); } }); as->stop(); }); as->run(); } ``` -------------------------------- ### Implement SSE Server with Manual Stream Handling Source: https://github.com/okyfirmansyah/libasyik/blob/master/docs/http.md Uses activate_direct_response_handling to take control of the connection stream for real-time event streaming. Requires using asyik::use_fiber_future to enable fiber-friendly asynchronous operations. ```c++ int main() { auto as = asyik::make_service(); auto server = asyik::make_http_server(as, "127.0.0.1", 4004); server->on_http_request("/sse", "GET", [server](auto req, auto args) { auto connection = req->get_connection_handle(server); auto &stream = connection->get_stream(); req->activate_direct_response_handling(); // at this point we own connection/stream directly.. std::string s= "HTTP/1.1 200 OK\r\n" "Connection: keep-alive\r\n" "Content-type: text/event-stream\r\n\r\n" "retry: 5000\r\n\r\n"; // note: libasyik provide asyik::use_fiber_future to turn // any boost asio's API into yield-enable fiber future stream.async_write_some(asio::buffer(s.data(), s.length()), asyik::use_fiber_future).get(); // now sending stream of events indefinitely int i=0; for(;;) { std::string body="event: foo\r\n" "data: halo "+std::to_string(i++)+"\r\n" "\r\n"; stream.async_write_some(asio::buffer(body.data(), body.length()), asyik::use_fiber_future).get(); asyik::sleep_for(std::chrono::seconds(1)); } }); as->run(); } ``` -------------------------------- ### Configure Worker Thread Pool Size Source: https://github.com/okyfirmansyah/libasyik/blob/master/docs/service.md Override the default worker thread pool size multiplier using the `ASYIK_THREAD_MULTIPLIER` environment variable before starting the process. Invalid or non-positive values fall back to the default of 5. ```bash # use 2× hardware_concurrency worker threads instead of the default 5× ASYIK_THREAD_MULTIPLIER=2 ./my_server ``` -------------------------------- ### Configure Boost.Asio benchmark target Source: https://github.com/okyfirmansyah/libasyik/blob/master/benchmarks/CMakeLists.txt Builds the bench_asio target using raw Boost.Asio for TCP and manual HTTP parsing. ```cmake add_executable(bench_asio asio/bench_asio.cpp) target_compile_features(bench_asio PRIVATE cxx_std_17) target_compile_options(bench_asio PRIVATE ${BENCH_COMPILE_FLAGS}) target_include_directories(bench_asio PRIVATE ${Boost_INCLUDE_DIR}) target_link_libraries(bench_asio PRIVATE Threads::Threads) ``` -------------------------------- ### Execute SQL Statements with libasyik Source: https://context7.com/okyfirmansyah/libasyik/llms.txt Demonstrates performing INSERT, SELECT, UPDATE, and DELETE operations using parameter binding and output binding with SOCI. ```cpp #include "libasyik/service.hpp" #include "libasyik/sql.hpp" int main() { auto as = asyik::make_service(); auto pool = asyik::make_sql_pool(asyik::sql_backend_postgresql, "host=localhost dbname=test user=postgres password=secret", 4); as->execute([as, pool]() { auto ses = pool->get_session(as); // INSERT with parameters std::string name = "John Doe"; std::string email = "john@example.com"; ses->query("INSERT INTO users(name, email) VALUES(:name, :email)", soci::use(name), soci::use(email)); // SELECT with output binding int user_id = 1; std::string out_name; std::string out_email; ses->query("SELECT name, email FROM users WHERE id = :id", soci::use(user_id), soci::into(out_name), soci::into(out_email)); LOG(INFO) << "User: " << out_name << " <" << out_email << ">\n"; // UPDATE int id_to_update = 1; std::string new_email = "john.doe@newdomain.com"; ses->query("UPDATE users SET email = :email WHERE id = :id", soci::use(new_email), soci::use(id_to_update)); // DELETE int id_to_delete = 99; ses->query("DELETE FROM users WHERE id = :id", soci::use(id_to_delete)); as->stop(); }); as->run(); } ``` -------------------------------- ### Build benchmarks manually Source: https://github.com/okyfirmansyah/libasyik/blob/master/docs/benchmarking.md Configures and compiles the benchmark binaries using CMake. ```bash mkdir -p build_bench && cd build_bench cmake .. \ -DLIBASYIK_BUILD_BENCHMARKS=ON \ -DLIBASYIK_ENABLE_SOCI=OFF \ -DLIBASYIK_ENABLE_SSL_SERVER=OFF make -j$(nproc) bench_server bench_beast ``` -------------------------------- ### Serve Static Files Source: https://context7.com/okyfirmansyah/libasyik/llms.txt Serves directory trees with support for MIME detection, ETag, and range requests. API routes should be registered with insert_front if they conflict with static paths. ```cpp #include "libasyik/service.hpp" #include "libasyik/http.hpp" int main() { auto as = asyik::make_service(); auto server = asyik::make_http_server(as, "127.0.0.1", 8080); // Basic static file serving server->serve_static("/static", "/var/www/html"); // Custom configuration asyik::static_file_config cfg; cfg.enable_etag = true; cfg.enable_last_modified = true; cfg.enable_range = true; cfg.cache_control = "public, max-age=86400"; cfg.index_file = "index.html"; server->serve_static("/assets", "./public", cfg); // Multiple prefixes server->serve_static("/downloads", "/srv/files"); // API routes should be registered first or use insert_front server->on_http_request("/api/", "GET", [](auto req, auto args) { req->response.body = "API: " + args[1]; req->response.result(200); }, /*insert_front=*/true); as->run(); } // curl http://127.0.0.1:8080/static/css/app.css // curl -H "Range: bytes=0-99" http://127.0.0.1:8080/static/large-file.bin ``` -------------------------------- ### Handle WebSocket Connections with Fibers Source: https://github.com/okyfirmansyah/libasyik/blob/master/docs/service.md Demonstrates creating a WebSocket server where each connection is handled by a separate fiber. ```c++ #include "libasyik/service.hpp" #include "libasyik/http.hpp" // function/thread to handle a connection(websocket persistent connection) void websocket_handler(asyik::websocket_ptr ws, const asyik::http_route_args &args) { try { while(1) // echo server { auto s = ws->get_string(); ws->send_string(s); } } catch(...) // ends when connection closed { LOG(INFO)<<"handler completed..\n"; } } int main() { auto as = asyik::make_service(); auto server = asyik::make_http_server(as, "127.0.0.1", 4004); // this will spawn websocket_handler as user-land thread(Fiber) // for each incoming websocket connection server->on_websocket("/websocket", websocket_handler); LOG(INFO)<<"server started..\n"; as->run(); } ``` -------------------------------- ### Create HTTPS Server Source: https://context7.com/okyfirmansyah/libasyik/llms.txt Initializes an SSL/TLS-enabled HTTP server using an OpenSSL context. ```cpp #include "libasyik/service.hpp" #include "libasyik/http.hpp" #include namespace ssl = boost::asio::ssl; int main() { auto as = asyik::make_service(); ssl::context ctx{ssl::context::tlsv12}; ctx.set_options(ssl::context::default_workarounds | ssl::context::no_sslv2); ctx.use_certificate_chain_file("server.crt"); ctx.use_private_key_file("server.key", ssl::context::pem); auto server = asyik::make_https_server(as, std::move(ctx), "0.0.0.0", 443); server->on_http_request("/secure", "GET", [](auto req, auto args) { req->response.body = "Secure connection!"; req->response.result(200); }); as->run(); } ``` -------------------------------- ### Build Asio with io_uring Backend Source: https://github.com/okyfirmansyah/libasyik/blob/master/benchmarks/CMakeLists.txt Configures the 'bench_asio_iouring' executable to use Boost.Asio with io_uring. Requires liburing and Boost. Ensure Boost.Asio is configured to use io_uring by defining BOOST_ASIO_HAS_IO_URING and BOOST_ASIO_DISABLE_EPOLL. ```cmake find_library(URING_LIB uring) find_path(URING_INCLUDE_DIR liburing.h) if(URING_LIB AND URING_INCLUDE_DIR) # Extra find_package calls needed for libasyik_iouring library rebuild find_package(Boost COMPONENTS context atomic fiber date_time url REQUIRED) find_package(OpenSSL REQUIRED) # Asio-over-io_uring variant add_executable(bench_asio_iouring asio/bench_asio.cpp) target_compile_features(bench_asio_iouring PRIVATE cxx_std_17) target_compile_options(bench_asio_iouring PRIVATE ${BENCH_COMPILE_FLAGS}) target_include_directories(bench_asio_iouring PRIVATE ${Boost_INCLUDE_DIR} ${URING_INCLUDE_DIR}) target_compile_definitions(bench_asio_iouring PRIVATE BOOST_ASIO_HAS_IO_URING=1 BOOST_ASIO_DISABLE_EPOLL=1 ) target_link_libraries(bench_asio_iouring PRIVATE Threads::Threads ${URING_LIB}) message(STATUS "Benchmark target: bench_asio_iouring (Asio + io_uring backend, port 8088 by default)") else() ``` -------------------------------- ### Build libasyik with Profiling Enabled Source: https://github.com/okyfirmansyah/libasyik/blob/master/docs/benchmarking.md Compile the benchmark server with profiling enabled by setting CMake flags. This includes the profiling instrumentation in both the library and the benchmark executable. ```bash cd build_bench cmake .. -DLIBASYIK_BUILD_BENCHMARKS=ON -DLIBASYIK_BENCH_PROFILING=ON make -j$(nproc) bench_server ``` -------------------------------- ### Run benchmark suite Source: https://github.com/okyfirmansyah/libasyik/blob/master/docs/benchmarking.md Executes the benchmark script with various configurations for production or sanity testing. ```bash # Full 3-way comparison (all CPU cores, 30 s per scenario — production quality): bash benchmarks/run_benchmark.sh \ --target=all \ --duration=30 \ --concurrency=50,100,200,500 \ --thread-multiplier=$(nproc) # Quick sanity run (10 s, fewer concurrency levels): bash benchmarks/run_benchmark.sh \ --target=all \ --duration=10 \ --concurrency=100,200 # Single target: bash benchmarks/run_benchmark.sh --target=beast ```