Neutralinojs Documentation

repository·main·Indexed 27 days ago

https://github.com/neutralinojs/neutralinojs

A lightweight, portable desktop application development framework for building cross-platform apps using HTML, CSS, and JS without Chromium or Node.js. This documentation includes details on integrated libraries such as efsw for file system monitoring and cpp-httplib for C++11 header-only HTTP/HTTPS server and client implementation.

Tokens
14.5K
Snippets
47
Records
72
Agent score
93%

What's inside Neutralinojs

  1. Overview of Neutralinojs

    main
    Neutralinojs is a lightweight, portable framework for building cross-platform desktop applications using JavaScript, HTML, and CSS. Unlike Electron or NW.js, it does not bundle Chromium or Node.js. Instead, it utilizes the operating system's existing webview library (e.g., gtk-webkit2 on Linux) and implements a WebSocket connection for native operations via a built-in static web server. This results in significantly smaller and more efficient applications. Supported platforms include Linux, macOS, Windows, Web, and Chrome.
  2. Install and use cpp-httplib

    main

    cpp-httplib is a C++11 single-file, header-only, cross-platform HTTP/HTTPS library. To use it, simply include the httplib.h file in your project.

    Important Limitations:

    • Uses blocking socket I/O (not suitable for non-blocking requirements).
    • Supports HTTP/1.1 only (HTTP/2 and HTTP/3 are not implemented).
    • 32-bit platforms are NOT supported; use at your own risk due to potential integer truncation and security concerns.
    #include "path/to/httplib.h"
  3. Use Middleware Handlers (Pre-routing, Pre-request, Post-routing)

    main

    You can intercept requests at different stages of the lifecycle:

    1. set_pre_routing_handler: Runs before route matching and before the body is read. Use this to reject requests as early as possible. Returns Server::HandlerResponse::Handled to stop processing or Unhandled to continue.
    2. set_pre_request_handler: Runs after the route is matched (so req.matched_route and req.path_params are available) but before the request body is read. Ideal for authentication/authorization checks without buffering large bodies.
    3. set_post_routing_handler: Runs after the route handler completes. Useful for adding headers to the response.
    4. set_post_routing_handler: Runs after the route handler completes. Useful for adding headers to the response.
    // Pre-routing: Reject early
    svr.set_pre_routing_handler([](const auto& req, auto& res) {
      if (req.path == "/forbidden") {
        res.status = StatusCode::Forbidden_403;
        return Server::HandlerResponse::Handled;
      }
      return Server::HandlerResponse::Unhandled;
    });
    
    // Pre-request: Check route-specific params before reading body
    svr.set_pre_request_handler([](const auto& req, auto& res) {
      if (req.matched_route == "/user/:user") {
        if (req.path_params.at("user") != "admin") {
          res.status = StatusCode::Unauthorized_401;
          return Server::HandlerResponse::Handled;
        }
      }
      return Server::HandlerResponse::Unhandled;
    });
  4. Generate missing source files in the development branch

    main

    The development branch does not include automatically generated source files. To generate them, you need Python 3.8 and Perl.

    First, install the required Python packages:

    python3 -m pip install --user -r scripts/basic.requirements.txt

    Then, use one of the following methods to generate the files:

    • Run make (automatically generates files during build).
    • Run make generated_files.
    • On Unix/POSIX: tests/scripts/check-generated-files.sh -u.
    • On Windows: scripts\make_generated_files.bat.
    python3 -m pip install --user -r scripts/basic.requirements.txt
    make generated_files
  5. Create a basic HTTP Server with cpp-httplib

    main

    You can create an HTTP server by instantiating a Server object and defining routes using methods like Get, Post, Put, Patch, Delete, and Options. Each handler receives a Request and a Response object. You can use regular expressions for path matching or named path parameters (e.g., :id).

    #include <httplib.h>
    
    int main(void)
    {
      using namespace httplib;
    
      Server svr;
    
      // Simple GET route
      svr.Get("/hi", [](const Request& req, Response& res) {
        res.set_content("Hello World!", "text/plain");
      });
    
      // Route with path parameter
      svr.Get("/users/:id", [&](const Request& req, Response& res) {
        auto user_id = req.path_params.at("id");
        res.set_content(user_id, "text/plain");
      });
    
      // Route with regex and captures
      svr.Get(R"(/numbers/(\d+))", [&](const Request& req, Response& res) {
        auto numbers = req.matches[1];
        res.set_content(numbers, "text/plain");
      });
    
      svr.listen("localhost", 1234);
    }
  6. Implement WebSockets (Server and Client)

    main

    The library supports WebSockets via the WebSocket method on the server and the httplib::ws::WebSocketClient on the client.

    Important Considerations:

    • Threading: WebSocket connections occupy a thread for their entire lifetime. For large-scale workloads, configure a dynamic thread pool using svr.new_task_queue.
    • Extensions: WebSocket extensions (like permessage-deflate) are not supported. The server will silently decline them.
    • Liveness: You can detect unresponsive peers by setting set_websocket_max_missed_pongs(n). If the client misses n consecutive pings, the connection is closed.
    • SSL: Supported via the wss:// scheme.
    // Server
    httplib::Server svr;
    
    svr.WebSocket("/ws", [](const httplib::Request &req, httplib::ws::WebSocket &ws) {
        httplib::ws::Message msg;
        while (ws.read(msg)) {
            if (msg.is_text()) {
                ws.send("Echo: " + msg.data);
            }
        }
    });
    
    svr.listen("localhost", 8080);
    // Client
    httplib::ws::WebSocketClient ws("ws://localhost:8080/ws");
    
    if (ws.connect()) {
        ws.send("Hello, WebSocket!");
    
        std::string msg;
        if (ws.read(msg)) {
            std::cout << "Received: " << msg << std::endl;
        }
    
        ws.close();
    }
  7. Implement a file system watcher with efsw

    main

    To monitor file system changes, inherit from efsw::FileWatchListener and override the handleFileAction method. You can then use an efsw::FileWatcher instance to add paths to watch and start the asynchronous monitoring process.

    Key components:

    • efsw::FileWatchListener: The base class for receiving file events.
    • efsw::FileWatcher: The main engine that manages watches and runs the monitoring loop.
    • efsw::WatchID: A unique identifier returned when adding a watch, used to remove it later.
    • efsw::Actions: An enumeration representing the type of event (Add, Delete, Modified, Moved).
    // 1. Implement the listener
    class UpdateListener : public efsw::FileWatchListener {
      public:
        void handleFileAction( efsw::WatchID watchid, const std::string& dir,
                               const std::string& filename, efsw::Action action,
                               std::string oldFilename ) override {
            switch ( action ) {
                case efsw::Actions::Add:
                    std::cout << "Added: " << filename << std::endl;
                    break;
                case efsw::Actions::Delete:
                    std::cout << "Deleted: " << filename << std::endl;
                    break;
                case efsw::Actions::Modified:
                    std::cout << "Modified: " << filename << std::endl;
                    break;
                case efsw::Actions::Moved:
                    std::cout << "Moved: " << filename << " from " << oldFilename << std::endl;
                    break;
                default:
                    break;
            }
        }
    };
    
    // 2. Setup and start watching
    efsw::FileWatcher* fileWatcher = new efsw::FileWatcher();
    UpdateListener* listener = new UpdateListener();
    
    // Add a recursive watch
    efsw::WatchID watchID = fileWatcher->addWatch( "/tmp", listener, true );
    
    // Start watching asynchronously
    fileWatcher->watch();
    
    // 3. Cleanup
    fileWatcher->removeWatch( watchID );
  8. Build Mbed TLS using GNU Make

    main

    To build the library and sample programs using GNU Make, ensure you have a C99 toolchain and GNU Make installed.

    Common commands:

    • make: Build the library.
    • make check: Run the test suite (requires Python and Perl).
    • make no_test: Build the library without running tests.
    • make generated_files: Generate required configuration-independent files (useful in the development branch).

    Environment variables for customization:

    • SHARED=1: Build shared libraries in addition to static libraries.
    • DEBUG=1: Perform a debug build.
    • WINDOWS_BUILD=1: Use if the target is Windows but the build environment is Unix-like.
    • WINDOWS=1: Use if the build environment is a Windows shell (e.g., mingw32-make).
    make
    # or
    make check
  9. Compile efsw using Premake

    main

    To build efsw, you must have Premake installed. Use the following commands based on your target platform:

    Linux/macOS (Makefiles):

    1. Generate Makefiles: premake4 gmake
    2. Navigate to the platform directory: cd make/*YOURPLATFORM*/
    3. Build: make or make config=release (to generate static/shared libs and test app).

    Windows (Visual Studio):

    • Generate project: premake4 vs2010

    macOS (Xcode):

    • Generate project: premake4 xcode4

    Note: A CMake file is also available in the repository, though not officially supported.

    premake4 gmake
    cd make/*YOURPLATFORM*/
    make
  10. Configure Windows Include Order for httplib.h

    main

    When developing on Windows, you must include httplib.h before Windows.h. Alternatively, you can include Windows.h first if you define WIN32_LEAN_AND_MEAN beforehand.

    // Option 1: httplib.h first
    #include <httplib.h>
    #include <Windows.h>
    // Option 2: Define WIN32_LEAN_AND_MEAN
    #define WIN32_LEAN_AND_MEAN
    #include <Windows.h>
    #include <httplib.h>
  11. Install and use the Neutralinojs CLI (neu)

    main
    To develop with Neutralinojs, you need the neu CLI. You can install it globally via npm. Once installed, you can create a new application, navigate to its directory, and run it. To package your application for distribution, use the build command, which is extremely fast as it requires no compilation.