Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
155 changes: 135 additions & 20 deletions include/webframe.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
#include <unordered_map>

#include <webframe/application.hpp>
#include <webframe/config.hpp>
#include <webframe/context.hpp>
#include <webframe/exception.hpp>
#include <webframe/handler.hpp>
#include <webframe/router.hpp>
Expand All @@ -43,8 +45,18 @@
#include <windows.h>
#endif

/**
* @file webframe.hpp
* @brief WebFrame API
* @author John R Patek Sr <johnpatek2@gmail.com>
*/
namespace webframe
{
/**
* @enum method
* @brief HTTP methods supported by WebFrame
* @details Basic CRUD operations via the HTTP methods GET, POST, PUT, and DELETE.
*/
enum class method
{
http_get,
Expand All @@ -53,58 +65,161 @@ namespace webframe
http_delete
};

/**
* @class request
* @brief abstract interface for HTTP requests
* @details Common abstraction for all WebFrame runtimes to process HTTP requests.
*/
class request
{
public:
/**
* @brief get the HTTP method of the request
* @return the HTTP method of the request
*/
virtual method get_method() const = 0;
/**
* @brief get the path of the request
* @return the path of the request
*/
virtual std::string get_path() const = 0;

/**
* @brief get the value of a specific header
* @param key the header key
* @param value reference to the header value
* @return true if the header exists, false otherwise. The string reference will only
* be set if the header exists.
*/
virtual bool get_header(const std::string &key, std::string &value) const = 0;

/**
* @brief get the body of the request as a pointer and size
* @return a pair containing a pointer to the body data and the size of the body
* @details The body data is not guaranteed to be null-terminated. The pointer and size are only
* valid for the duration of the request handling. If the request does not have a body, the pointer
* will be null and the size will be zero.
*/
virtual std::pair<const uint8_t *, size_t> get_body() const = 0;

/**
* @brief read the body of the request using a callback
* @param callback a function to be called with the body data and size
* @details The callback will be called with chunks of the body data. None of the runtimes are
* currently capable of streaming request bodies, so the callback will be called at most once with the
* entire body. If there is no request body, the callback will not be called.
*/
virtual void read_body(const std::function<void(const uint8_t *, size_t)> &callback) const = 0;
};

/**
* @class response
* @brief abstract interface for HTTP responses
* @details Common abstraction for all WebFrame runtimes to generate HTTP responses.
*/
class response
{
public:
/**
* @brief set the HTTP status code of the response
* @param status_code the HTTP status code
* @details The status code is not checked against valid HTTP status codes. It can be set to
* any integer value, but there is no guarantee that the runtime implementation will accept it.
*/
virtual void set_status(int status_code) = 0;

/**
* @brief set a header of the response
* @param key the header key
* @param value the header value
* @details The headers are not validated, and there is no standard way to handle duplicate entries.
*/
virtual void set_header(const std::string &key, const std::string &value) = 0;

/**
* @brief set the body of the response
* @param data pointer to the body data
* @param size the size of the body data
* @details This must be called once after the status and headers have been set. If it is called
* before, the status will be 200 and the headers will be empty. There is no standard way to handle
* multiple calls.
*/
virtual void set_body(const uint8_t *data, size_t size) = 0;
virtual void write_body(const std::function<bool(std::pair<const uint8_t *, size_t> &)> &callback) = 0 ;
};


/**
* @brief write the body of the response using a callback
* @param callback a function to be called with a chunk to set the body data and size.
* @details The callback will be called with chunks of the body data until it returns false to indicate
* end-of-stream. The callback will always be called at least once, and will only populate the chunk if
* the data is not null and the size is greater than zero.
*/
virtual void write_body(const std::function<bool(std::pair<const uint8_t *, size_t> &)> &callback) = 0;
};

/**
* @class runtime
* @brief abstract interface for WebFrame runtimes
* @details Given an application and a router, the runtime is responsible for abstracting HTTP traffic from the
* underlying platform. The user will rarely, if ever, interact with this interface directly.
*/
class runtime
{
public:
#ifdef WEBFRAME_WIN32_APP
/**
* @brief dispatch the application using the Win32 API
* @param hInstance the handle to the current instance of the application
* @param hPrevInstance the handle to the previous instance of the application (always null)
* @param lpCmdLine the command line arguments as a single string
* @param nCmdShow the show state of the application window
* @param a the application to dispatch
* @param r the router to use for dispatching requests
* @return the exit code of the application
* @details This is only used for the Win32 desktop runtime. You should not call this directly. Use the WEBFRAME_MAIN macro
* to define the entry point of your application, and it will call this function for you.
*/
virtual int dispatch(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow, application *a, router *r) = 0;
#else
/**
* @brief dispatch the application using the standard C++ API
* @param argc the number of command line arguments
* @param argv the command line arguments as an array of strings
* @param a the application to dispatch
* @param r the router to use for dispatching requests
* @return the exit code of the application
* @details This is used for all non-Win32 runtimes, including Windows servers. Like the other dispatch function, it
* should not be called directly.
*/
virtual int dispatch(int argc, const char **argv, application *a, router *r) = 0;
#endif
};

runtime *webframe_init();
/**
* @brief create a WebFrame runtime instance
* @return a pointer to a WebFrame runtime instance
* @details Stub for constructing a runtime. The actual implementation is determined by the runtime library.
*/
runtime *create_runtime();
}

#if defined(WEBFRAME_WIN32_APP)
#define WEBFRAME_MAIN(AppType) \
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) \
{ \
std::unique_ptr<webframe::runtime> runtime(webframe::webframe_init()); \
AppType app; \
webframe::router router; \
return runtime->dispatch(hInstance, hPrevInstance, lpCmdLine, nCmdShow, &app, &router); \
}
#define WEBFRAME_MAIN(AppType) \
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) \
{ \
std::unique_ptr<webframe::runtime> runtime(webframe::create_runtime()); \
AppType app; \
webframe::router router; \
return runtime->dispatch(hInstance, hPrevInstance, lpCmdLine, nCmdShow, &app, &router); \
}
#else
#define WEBFRAME_MAIN(AppType) \
int main(int argc, const char **argv) \
{ \
std::unique_ptr<webframe::runtime> runtime(webframe::webframe_init()); \
AppType app; \
webframe::router router; \
return runtime->dispatch(argc, argv, &app, &router); \
}
#define WEBFRAME_MAIN(AppType) \
int main(int argc, const char **argv) \
{ \
std::unique_ptr<webframe::runtime> runtime(webframe::create_runtime()); \
AppType app; \
webframe::router router; \
return runtime->dispatch(argc, argv, &app, &router); \
}
#endif

#endif
80 changes: 77 additions & 3 deletions include/webframe/application.hpp
Original file line number Diff line number Diff line change
@@ -1,19 +1,93 @@
/* WebFrame
*
* Copyright (C) 2026 Maxtek Consulting
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

#ifndef WEBFRAME_APPLICATION_HPP
#define WEBFRAME_APPLICATION_HPP

/**
* @file webframe/application.hpp
* @brief WebFrame application API
* @author John R Patek Sr <johnpatek2@gmail.com>
*/
namespace webframe
{
class desktop_config;
class desktop_context;
class server_config;
class server_context;
class router;

/**
* @class application
* @brief abstract interface for WebFrame applications
* @details Represents a single interface for all WebFrame runtimes.
*/
class application
{
public:
application() = default;
virtual ~application() = default;
virtual void configure_desktop();
virtual void configure_server(int argc, const char **argv);

/**
* @brief configure the application for a desktop runtime
* @param config the desktop configuration for the application
* @details This is only used for desktop runtimes. Does not need to
* be implemented for server-only applications.
*/
virtual void configure_desktop(desktop_config *config);

/**
* @brief configure the application for a server runtime
* @param config the server configuration for the application
* @param argc the number of command-line arguments
* @param argv the command-line arguments
* @details This is only used for server runtimes. Does not need to
* be implemented for desktop-only applications.
*/
virtual void configure_server(server_config *config, int argc, const char **argv);

/**
* @brief configure the router for the application
* @param router the router to configure
* @details This is used to set handlers for HTTP traffic. This method
* should always be implemented, or the application will be unable to
* handle requests.
*/
virtual void configure_router(router *ctrl);
virtual void on_dispatch();

/**
* @brief launch the application in a desktop runtime
* @param context the desktop context to use for launching the application
* @details This is only used for desktop runtimes. The base implmentation will
* create a single window with the default size and load /index.html from the
* router. The context pointer will remain valid while the application is running,
* so it can be used to create additional windows or perform other operations.
*/
virtual void launch_desktop(desktop_context *context);

/**
* @brief launch the application in a server runtime
* @param context the server context to use for launching the application
* @details This is only used for server runtimes. The base implementation will
* register SIGINT as the kill signal. The context pointer will remain valid while
* the application is running.
*/
virtual void launch_server(server_context *context);
};
}

Expand Down
67 changes: 67 additions & 0 deletions include/webframe/config.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/* WebFrame
*
* Copyright (C) 2026 Maxtek Consulting
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

#ifndef WEBFRAME_CONFIG_HPP
#define WEBFRAME_CONFIG_HPP

#include <optional>
#include <string>

/**
* @file webframe/config.hpp
* @brief WebFrame configuration API
* @author John R Patek Sr <johnpatek2@gmail.com>
*/
namespace webframe
{
class desktop_config
{
public:
desktop_config() = default;
~desktop_config() = default;

void set_dark_mode(bool dark_mode);
void set_default_window_size(int width, int height);

bool get_dark_mode(bool &dark_mode) const;
std::pair<int, int> get_default_window_size() const;

private:
std::optional<bool> _force_dark_mode;
std::pair<int, int> _default_window_size = {800, 600};
};

class server_config
{
public:
server_config() = default;
~server_config() = default;

void set_host(const std::string &host);
void set_port(uint16_t port);

std::string get_host() const;
uint16_t get_port() const;

private:
std::string _host;
uint16_t _port;
};
}

#endif
Loading
Loading