#pragma once #include #include #include #include #include #include "Uri.hpp" #include #include // forward declaration. class websocket_session; namespace pipedal { using HttpRequest =boost::beast::http::request; std::string last_modified(const std::filesystem::path& path); class SocketHandler { public: class IWriteCallback { public: virtual void close() = 0; virtual void writeCallback(const std::string& text) = 0; }; private: friend class ::websocket_session; IWriteCallback *writeCallback_; void setWriteCallback(IWriteCallback *writeCallback) { writeCallback_ = writeCallback; } protected: virtual void onReceive(const std::string_view&text) = 0; public: void receive(const std::string_view&text) { onReceive(text); } void send(const std::string &text) { if (writeCallback_ != nullptr) { writeCallback_->writeCallback(text); } } virtual void Close() { writeCallback_->close(); } virtual ~SocketHandler() = default; virtual void onAttach() { } }; class ISocketFactory { public: virtual bool wants(const uri &request) = 0; virtual std::shared_ptr CreateHandler(const uri& request) = 0; }; class RequestHandler { private: uri target_url_; public: RequestHandler(const char*target_url) : target_url_(target_url) { } ~RequestHandler() = default; virtual bool wantsRedirect(const uri& requestUri) { return false; } uri GetRedirect(const uri& requestUri) { return requestUri; } virtual bool wants(boost::beast::http::verb verb,const uri &request_uri) const { if (request_uri.segment_count() < target_url_.segment_count()) { return false; } for (int i = 0; i < target_url_.segment_count(); ++i) { if (request_uri.segment(i) != target_url_.segment(i)) { return false; } } return true; } virtual void head_response( const uri&request_uri, const boost::beast::http::request &req, boost::beast::http::response &res, boost::beast::error_code &ec) = 0; virtual void get_response( const uri&request_uri, const boost::beast::http::request &req, boost::beast::http::response &res, boost::beast::error_code &ec) = 0; virtual void post_response( const uri&request_uri, const boost::beast::http::request &req, boost::beast::http::response &res, boost::beast::error_code &ec) { get_response(request_uri,req,res,ec); } }; class BeastServer { private: boost::asio::ip::address address; unsigned short port; std::string doc_root; int threads; std::mutex log_mutex; std::vector > request_handlers; std::vector > socket_factories; std::mutex io_mutex; boost::asio::io_context *pIoContext = nullptr; void*pListener = nullptr; std::thread*pBgThread = nullptr; bool logHttpRequests = false; bool hasAccessPointGateway = false; boost::asio::ip::network_v4 accessPointGateway; std::string accessPointServerAddress; bool stopping = false; public: BeastServer( const boost::asio::ip::address& address, int port, const char*rootPath, int threads = 10); void Run(); void RunInBackground(); bool Stopping() const { return this->stopping; } void Stop(); void Join(); void SetLogHttpRequests(bool logRequests) { this->logHttpRequests = logRequests; } bool LogHttpRequests() const { return this->logHttpRequests; } boost::asio::io_context& IoContext() { return *pIoContext; } void AddRequestHandler(std::shared_ptr requestHandler) { request_handlers.push_back(requestHandler); } void AddSocketFactory(const std::shared_ptr &socketHandler) { socket_factories.push_back(socketHandler); } std::vector > &RequestHandlers() { return request_handlers; } const std::string&GetDocRoot() { return doc_root; } virtual ~BeastServer(); std::shared_ptr GetSocketFactory(const uri &request_uri); void SetAccessPointGateway(const boost::asio::ip::network_v4 &gateway, const std::string&accessPointServerAddress) { this->accessPointGateway = gateway; this->hasAccessPointGateway = true; this->accessPointServerAddress = accessPointServerAddress; } bool HasAccessPointGateway() const { return hasAccessPointGateway; } boost::asio::ip::network_v4 &GetAccessPointGateway() { return this->accessPointGateway; } const std::string & GetAccessPointServerAddress() const { return this->accessPointServerAddress; } public: virtual void onError(boost::system::error_code ec, char const* what); virtual void onWarning(boost::system::error_code ec, char const* what); virtual void onInfo(char const* what); virtual void onListenerClosed(); }; } // namespace pipedal;