/*
|
|
|
|
WEBSOCKET MODULE
|
|
|
|
Copyright (C) 2016-2019 by Xose Pérez <xose dot perez at gmail dot com>
|
|
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include "espurna.h"
|
|
|
|
#include <IPAddress.h>
|
|
|
|
#include <cstdint>
|
|
#include <memory>
|
|
#include <vector>
|
|
|
|
constexpr const size_t WS_DEBUG_MSG_BUFFER = 8;
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// WS authentication
|
|
// -----------------------------------------------------------------------------
|
|
|
|
struct ws_ticket_t {
|
|
IPAddress ip;
|
|
unsigned long timestamp = 0;
|
|
};
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// 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;
|
|
};
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// Debug
|
|
// -----------------------------------------------------------------------------
|
|
|
|
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);
|
|
}
|
|
|
|
void clear() {
|
|
messages.clear();
|
|
current = 0;
|
|
flush = false;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
void send(const bool connected);
|
|
|
|
bool flush;
|
|
size_t current;
|
|
const size_t capacity;
|
|
std::vector<ws_debug_msg_t> messages;
|
|
|
|
};
|