/* Part of the WEBSOCKET MODULE Copyright (C) 2016-2019 by Xose PĂ©rez Copyright (C) 2019 by Maxim Prokhorov */ #pragma once #include "espurna.h" #include "ws.h" #include #include #include #include // ----------------------------------------------------------------------------- // WS authentication // ----------------------------------------------------------------------------- struct WsTicket { IPAddress ip; unsigned long timestamp = 0; }; // ----------------------------------------------------------------------------- // WS callbacks // ----------------------------------------------------------------------------- // The idea here is to bind either: // - constant 'callbacks' list as reference, which was registered via wsRegister() // - in-place callback / callbacks that will be moved inside this container struct WsPostponedCallbacks { public: enum class Mode { Sequence, All }; WsPostponedCallbacks(uint32_t client_id, ws_on_send_callback_f&& cb) : client_id(client_id), timestamp(ESP.getCycleCount()), _storage(new ws_on_send_callback_list_t {std::move(cb)}), _callbacks(*_storage.get()), _current(_callbacks.begin()), _mode(Mode::All) {} WsPostponedCallbacks(uint32_t client_id, const ws_on_send_callback_f& cb) : client_id(client_id), timestamp(ESP.getCycleCount()), _storage(new ws_on_send_callback_list_t {cb}), _callbacks(*_storage.get()), _current(_callbacks.begin()), _mode(Mode::All) {} template explicit WsPostponedCallbacks(T&& cb) : WsPostponedCallbacks(0, std::forward(cb)) {} WsPostponedCallbacks(const uint32_t client_id, const ws_on_send_callback_list_t& cbs, Mode mode = Mode::Sequence) : client_id(client_id), timestamp(ESP.getCycleCount()), _callbacks(cbs), _current(_callbacks.begin()), _mode(mode) {} WsPostponedCallbacks(const uint32_t client_id, ws_on_send_callback_list_t&& cbs, Mode mode = Mode::All) : client_id(client_id), timestamp(ESP.getCycleCount()), _storage(new ws_on_send_callback_list_t(std::move(cbs))), _callbacks(*_storage.get()), _current(_callbacks.begin()), _mode(mode) {} bool done() { return _current == _callbacks.end(); } void sendAll(JsonObject& root) { _current = _callbacks.end(); for (auto& callback : _callbacks) { callback(root); } } void sendCurrent(JsonObject& root) { if (_current == _callbacks.end()) return; (*_current)(root); ++_current; } void send(JsonObject& root) { switch (_mode) { case Mode::Sequence: sendCurrent(root); break; case Mode::All: sendAll(root); break; } } const uint32_t client_id; const decltype(ESP.getCycleCount()) timestamp; private: std::unique_ptr _storage; const ws_on_send_callback_list_t& _callbacks; ws_on_send_callback_list_t::const_iterator _current; const Mode _mode; }; // ----------------------------------------------------------------------------- // Debug // ----------------------------------------------------------------------------- struct WsDebug { using Message = std::pair; using MsgList = std::vector; WsDebug(size_t capacity) : _flush(false), _current(0), _capacity(capacity) { _messages.reserve(_capacity); } void clear() { _messages.clear(); _current = 0; _flush = false; } template void add(T&& message) { if (_current >= _capacity) { _flush = true; send(wsConnected()); } _messages.emplace(_messages.begin() + _current, std::forward(message)); _flush = true; ++_current; } void add(const char* prefix, const char* message) { add(std::move(std::make_pair(prefix, message))); } void send(bool connected); private: bool _flush; size_t _current; const size_t _capacity; MsgList _messages; };