|
|
@ -15,6 +15,8 @@ Copyright (C) 2016-2019 by Xose Pérez <xose dot perez at gmail dot com> |
|
|
|
#include <vector>
|
|
|
|
|
|
|
|
#include "system.h"
|
|
|
|
#include "ws.h"
|
|
|
|
#include "ws_internal.h"
|
|
|
|
#include "libs/WebSocketIncommingBuffer.h"
|
|
|
|
|
|
|
|
AsyncWebSocket _ws("/ws"); |
|
|
@ -51,112 +53,12 @@ ws_callbacks_t& ws_callbacks_t::onKeyCheck(ws_on_keycheck_callback_f cb) { |
|
|
|
} |
|
|
|
|
|
|
|
ws_callbacks_t _ws_callbacks; |
|
|
|
|
|
|
|
struct ws_counter_t { |
|
|
|
|
|
|
|
ws_counter_t() : current(0), start(0), stop(0) {} |
|
|
|
|
|
|
|
ws_counter_t(uint32_t start, uint32_t stop) : |
|
|
|
current(start), start(start), stop(stop) {} |
|
|
|
|
|
|
|
void reset() { |
|
|
|
current = start; |
|
|
|
} |
|
|
|
|
|
|
|
void next() { |
|
|
|
if (current < stop) { |
|
|
|
++current; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
bool done() { |
|
|
|
return (current >= stop); |
|
|
|
} |
|
|
|
|
|
|
|
uint32_t current; |
|
|
|
uint32_t start; |
|
|
|
uint32_t stop; |
|
|
|
}; |
|
|
|
|
|
|
|
struct ws_data_t { |
|
|
|
|
|
|
|
enum mode_t { |
|
|
|
SEQUENCE, |
|
|
|
ALL |
|
|
|
}; |
|
|
|
|
|
|
|
ws_data_t(const ws_on_send_callback_f& cb) : |
|
|
|
storage(new ws_on_send_callback_list_t {cb}), |
|
|
|
client_id(0), |
|
|
|
mode(ALL), |
|
|
|
callbacks(*storage.get()), |
|
|
|
counter(0, 1) |
|
|
|
{} |
|
|
|
|
|
|
|
ws_data_t(uint32_t client_id, const ws_on_send_callback_f& cb) : |
|
|
|
storage(new ws_on_send_callback_list_t {cb}), |
|
|
|
client_id(client_id), |
|
|
|
mode(ALL), |
|
|
|
callbacks(*storage.get()), |
|
|
|
counter(0, 1) |
|
|
|
{} |
|
|
|
|
|
|
|
ws_data_t(const uint32_t client_id, ws_on_send_callback_list_t&& callbacks, mode_t mode = SEQUENCE) : |
|
|
|
storage(new ws_on_send_callback_list_t(std::move(callbacks))), |
|
|
|
client_id(client_id), |
|
|
|
mode(mode), |
|
|
|
callbacks(*storage.get()), |
|
|
|
counter(0, (storage.get())->size()) |
|
|
|
{} |
|
|
|
|
|
|
|
ws_data_t(const uint32_t client_id, const ws_on_send_callback_list_t& callbacks, mode_t mode = SEQUENCE) : |
|
|
|
client_id(client_id), |
|
|
|
mode(mode), |
|
|
|
callbacks(callbacks), |
|
|
|
counter(0, callbacks.size()) |
|
|
|
{} |
|
|
|
|
|
|
|
bool done() { |
|
|
|
return counter.done(); |
|
|
|
} |
|
|
|
|
|
|
|
void sendAll(JsonObject& root) { |
|
|
|
while (!counter.done()) counter.next(); |
|
|
|
for (auto& callback : callbacks) { |
|
|
|
callback(root); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void sendCurrent(JsonObject& root) { |
|
|
|
callbacks[counter.current](root); |
|
|
|
counter.next(); |
|
|
|
} |
|
|
|
|
|
|
|
void send(JsonObject& root) { |
|
|
|
switch (mode) { |
|
|
|
case SEQUENCE: sendCurrent(root); break; |
|
|
|
case ALL: sendAll(root); break; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
std::unique_ptr<ws_on_send_callback_list_t> storage; |
|
|
|
|
|
|
|
const uint32_t client_id; |
|
|
|
const mode_t mode; |
|
|
|
const ws_on_send_callback_list_t& callbacks; |
|
|
|
ws_counter_t counter; |
|
|
|
}; |
|
|
|
|
|
|
|
std::queue<ws_data_t> _ws_client_data; |
|
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
// WS authentication
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
struct ws_ticket_t { |
|
|
|
IPAddress ip; |
|
|
|
unsigned long timestamp = 0; |
|
|
|
}; |
|
|
|
ws_ticket_t _ws_tickets[WS_BUFFER_SIZE]; |
|
|
|
|
|
|
|
void _onAuth(AsyncWebServerRequest *request) { |
|
|
@ -206,71 +108,33 @@ bool _wsAuth(AsyncWebSocketClient * client) { |
|
|
|
|
|
|
|
#if DEBUG_WEB_SUPPORT
|
|
|
|
|
|
|
|
using ws_debug_msg_t = std::pair<String, String>; |
|
|
|
|
|
|
|
struct ws_debug_t { |
|
|
|
|
|
|
|
ws_debug_t(size_t capacity) : |
|
|
|
flush(false), |
|
|
|
current(0), |
|
|
|
capacity(capacity) |
|
|
|
{ |
|
|
|
messages.reserve(capacity); |
|
|
|
} |
|
|
|
ws_debug_t _ws_debug(WS_DEBUG_MSG_BUFFER); |
|
|
|
|
|
|
|
void clear() { |
|
|
|
messages.clear(); |
|
|
|
current = 0; |
|
|
|
flush = false; |
|
|
|
void ws_debug_t::send(const bool connected) { |
|
|
|
if (!connected && flush) { |
|
|
|
clear(); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
void add(const char* prefix, const char* message) { |
|
|
|
if (current >= capacity) { |
|
|
|
flush = true; |
|
|
|
send(wsConnected()); |
|
|
|
} |
|
|
|
|
|
|
|
messages.emplace(messages.begin() + current, prefix, message); |
|
|
|
flush = true; |
|
|
|
++current; |
|
|
|
} |
|
|
|
if (!flush) return; |
|
|
|
// ref: http://arduinojson.org/v5/assistant/
|
|
|
|
// {"weblog": {"msg":[...],"pre":[...]}}
|
|
|
|
DynamicJsonBuffer jsonBuffer(2*JSON_ARRAY_SIZE(messages.size()) + JSON_OBJECT_SIZE(1) + JSON_OBJECT_SIZE(2)); |
|
|
|
|
|
|
|
void send(const bool connected) { |
|
|
|
if (!connected && flush) { |
|
|
|
clear(); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
if (!flush) return; |
|
|
|
// ref: http://arduinojson.org/v5/assistant/
|
|
|
|
// {"weblog": {"msg":[...],"pre":[...]}}
|
|
|
|
DynamicJsonBuffer jsonBuffer(2*JSON_ARRAY_SIZE(messages.size()) + JSON_OBJECT_SIZE(1) + JSON_OBJECT_SIZE(2)); |
|
|
|
|
|
|
|
JsonObject& root = jsonBuffer.createObject(); |
|
|
|
JsonObject& weblog = root.createNestedObject("weblog"); |
|
|
|
|
|
|
|
JsonArray& msg = weblog.createNestedArray("msg"); |
|
|
|
JsonArray& pre = weblog.createNestedArray("pre"); |
|
|
|
JsonObject& root = jsonBuffer.createObject(); |
|
|
|
JsonObject& weblog = root.createNestedObject("weblog"); |
|
|
|
|
|
|
|
for (auto& message : messages) { |
|
|
|
pre.add(message.first.c_str()); |
|
|
|
msg.add(message.second.c_str()); |
|
|
|
} |
|
|
|
JsonArray& msg = weblog.createNestedArray("msg"); |
|
|
|
JsonArray& pre = weblog.createNestedArray("pre"); |
|
|
|
|
|
|
|
wsSend(root); |
|
|
|
clear(); |
|
|
|
for (auto& message : messages) { |
|
|
|
pre.add(message.first.c_str()); |
|
|
|
msg.add(message.second.c_str()); |
|
|
|
} |
|
|
|
|
|
|
|
bool flush; |
|
|
|
size_t current; |
|
|
|
const size_t capacity; |
|
|
|
std::vector<ws_debug_msg_t> messages; |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
// TODO: move to the headers?
|
|
|
|
constexpr const size_t WS_DEBUG_MSG_BUFFER = 8; |
|
|
|
ws_debug_t _ws_debug(WS_DEBUG_MSG_BUFFER); |
|
|
|
wsSend(root); |
|
|
|
clear(); |
|
|
|
} |
|
|
|
|
|
|
|
bool wsDebugSend(const char* prefix, const char* message) { |
|
|
|
if (!wsConnected()) return false; |
|
|
|