#pragma once #ifdef COMPILE_WEB_CLIENT #include #include #include #include #include #include #include "misc/queue.h" #include #include #include namespace ts::server { class WebControlServer; class WebClient : public SpeakingClient { friend class WebControlServer; public: WebClient(WebControlServer*, int socketFd); ~WebClient() override; void sendJson(const Json::Value&); void sendCommand(const ts::Command &command, bool low) override; void sendCommand(const ts::command_builder &command, bool low) override; bool disconnect(const std::string &reason) override; bool close_connection(const std::chrono::system_clock::time_point& timeout = std::chrono::system_clock::time_point()) override; [[nodiscard]] inline std::chrono::nanoseconds client_ping() const { return this->client_ping_layer_7(); } [[nodiscard]] inline std::chrono::nanoseconds client_ping_layer_5() const { return this->ping.value; } [[nodiscard]] inline std::chrono::nanoseconds client_ping_layer_7() const { return this->js_ping.value; } protected: void tick(const std::chrono::system_clock::time_point&) override; /* Every 500ms */ void applySelfLock(const std::shared_ptr &cl){ _this = cl; } private: WebControlServer* handle; int file_descriptor; bool allow_raw_commands{false}; bool ssl_detected{false}; bool ssl_encrypted{true}; pipes::SSL ssl_handler; pipes::WebSocket ws_handler; std::mutex event_mutex; ::event* readEvent; ::event* writeEvent; struct { uint8_t current_id{0}; std::chrono::system_clock::time_point last_request; std::chrono::system_clock::time_point last_response; std::chrono::nanoseconds value{}; std::chrono::nanoseconds timeout{2000}; } ping; struct { uint8_t current_id{0}; std::chrono::system_clock::time_point last_request; std::chrono::system_clock::time_point last_response; std::chrono::nanoseconds value{}; std::chrono::nanoseconds timeout{2000}; } js_ping; std::mutex queue_mutex; std::deque queue_read; std::deque queue_write; threads::Mutex execute_mutex; /* needs to be recursive! */ std::thread flush_thread; std::recursive_mutex close_lock; struct { std::mutex mutex{}; pipes::buffer target_header{}; bool is_new_header{false}; bool is_set{false}; } whisper; private: void initialize(); void handleMessageRead(int, short, void*); void handleMessageWrite(int, short, void*); void enqueue_raw_packet(const pipes::buffer_view& /* buffer */); void processNextMessage(const std::chrono::system_clock::time_point& /* scheduled */); void registerMessageProcess(); std::shared_ptr> event_handle_packet; //WS events void onWSConnected(); void onWSDisconnected(const std::string& reason); void onWSMessage(const pipes::WSMessage&); protected: void disconnectFinal(); void handleMessage(const pipes::buffer_view&); public: void send_voice_packet(const pipes::buffer_view &view, const VoicePacketFlags &flags) override; void send_voice_whisper_packet(const pipes::buffer_view &/* teamspeak packet */, const pipes::buffer_view &/* teaspeak packet */, const VoicePacketFlags &flags) override; protected: command_result handleCommand(Command &command) override; command_result handleCommandClientInit(Command &command) override; command_result handleCommandSetWhisperTarget(Command &command); command_result handleCommandClearWhisperTarget(Command &command); }; } #endif