Fork of the espurna firmware for `mhsw` switches
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

177 lines
4.3 KiB

  1. /*
  2. Part of the WEBSOCKET MODULE
  3. Copyright (C) 2016-2019 by Xose Pérez <xose dot perez at gmail dot com>
  4. Copyright (C) 2019 by Maxim Prokhorov <prokhorov dot max at outlook dot com>
  5. */
  6. #pragma once
  7. #include "espurna.h"
  8. #include "ws.h"
  9. #include <IPAddress.h>
  10. #include <cstdint>
  11. #include <memory>
  12. #include <vector>
  13. // -----------------------------------------------------------------------------
  14. // WS authentication
  15. // -----------------------------------------------------------------------------
  16. struct WsTicket {
  17. IPAddress ip;
  18. unsigned long timestamp = 0;
  19. };
  20. // -----------------------------------------------------------------------------
  21. // WS callbacks
  22. // -----------------------------------------------------------------------------
  23. // The idea here is to bind either:
  24. // - constant 'callbacks' list as reference, which was registered via wsRegister()
  25. // - in-place callback / callbacks that will be moved inside this container
  26. struct WsPostponedCallbacks {
  27. public:
  28. enum class Mode {
  29. Sequence,
  30. All
  31. };
  32. WsPostponedCallbacks(uint32_t client_id, ws_on_send_callback_f&& cb) :
  33. client_id(client_id),
  34. timestamp(ESP.getCycleCount()),
  35. _storage(new ws_on_send_callback_list_t {std::move(cb)}),
  36. _callbacks(*_storage.get()),
  37. _current(_callbacks.begin()),
  38. _mode(Mode::All)
  39. {}
  40. WsPostponedCallbacks(uint32_t client_id, const ws_on_send_callback_f& cb) :
  41. client_id(client_id),
  42. timestamp(ESP.getCycleCount()),
  43. _storage(new ws_on_send_callback_list_t {cb}),
  44. _callbacks(*_storage.get()),
  45. _current(_callbacks.begin()),
  46. _mode(Mode::All)
  47. {}
  48. template <typename T>
  49. explicit WsPostponedCallbacks(T&& cb) :
  50. WsPostponedCallbacks(0, std::forward<T>(cb))
  51. {}
  52. WsPostponedCallbacks(const uint32_t client_id, const ws_on_send_callback_list_t& cbs, Mode mode = Mode::Sequence) :
  53. client_id(client_id),
  54. timestamp(ESP.getCycleCount()),
  55. _callbacks(cbs),
  56. _current(_callbacks.begin()),
  57. _mode(mode)
  58. {}
  59. WsPostponedCallbacks(const uint32_t client_id, ws_on_send_callback_list_t&& cbs, Mode mode = Mode::All) :
  60. client_id(client_id),
  61. timestamp(ESP.getCycleCount()),
  62. _storage(new ws_on_send_callback_list_t(std::move(cbs))),
  63. _callbacks(*_storage.get()),
  64. _current(_callbacks.begin()),
  65. _mode(mode)
  66. {}
  67. bool done() {
  68. return _current == _callbacks.end();
  69. }
  70. void sendAll(JsonObject& root) {
  71. _current = _callbacks.end();
  72. for (auto& callback : _callbacks) {
  73. callback(root);
  74. }
  75. }
  76. void sendCurrent(JsonObject& root) {
  77. if (_current == _callbacks.end()) return;
  78. (*_current)(root);
  79. ++_current;
  80. }
  81. void send(JsonObject& root) {
  82. switch (_mode) {
  83. case Mode::Sequence:
  84. sendCurrent(root);
  85. break;
  86. case Mode::All:
  87. sendAll(root);
  88. break;
  89. }
  90. }
  91. const uint32_t client_id;
  92. const decltype(ESP.getCycleCount()) timestamp;
  93. private:
  94. std::unique_ptr<ws_on_send_callback_list_t> _storage;
  95. const ws_on_send_callback_list_t& _callbacks;
  96. ws_on_send_callback_list_t::const_iterator _current;
  97. const Mode _mode;
  98. };
  99. // -----------------------------------------------------------------------------
  100. // Debug
  101. // -----------------------------------------------------------------------------
  102. struct WsDebug {
  103. using Message = std::pair<String, String>;
  104. using MsgList = std::vector<Message>;
  105. WsDebug(size_t capacity) :
  106. _flush(false),
  107. _current(0),
  108. _capacity(capacity)
  109. {
  110. _messages.reserve(_capacity);
  111. }
  112. void clear() {
  113. _messages.clear();
  114. _current = 0;
  115. _flush = false;
  116. }
  117. template <typename T = Message>
  118. void add(T&& message) {
  119. if (_current >= _capacity) {
  120. _flush = true;
  121. send(wsConnected());
  122. }
  123. _messages.emplace(_messages.begin() + _current, std::forward<T>(message));
  124. _flush = true;
  125. ++_current;
  126. }
  127. void add(const char* prefix, const char* message) {
  128. add(std::move(std::make_pair(prefix, message)));
  129. }
  130. void send(bool connected);
  131. private:
  132. bool _flush;
  133. size_t _current;
  134. const size_t _capacity;
  135. MsgList _messages;
  136. };