1#ifndef _PAINLESS_MESH_ROUTER_HPP_
2#define _PAINLESS_MESH_ROUTER_HPP_
26 std::function<
bool(std::shared_ptr<T>)> func) {
27 auto route = std::find_if(tree.
subs.begin(), tree.
subs.end(), func);
28 if (route == tree.
subs.end())
return NULL;
45 return findRoute<T>(tree, [nodeId](std::shared_ptr<T> s) {
58 std::shared_ptr<T> exclude =
nullptr) {
59 return findRoute<T>(tree, [nodeId, exclude](std::shared_ptr<T> s) {
64template <
class T,
class U>
65bool send(T& package, std::shared_ptr<U> conn,
bool priority =
false) {
69 return conn->addMessage(msg, priority);
72template <
class T,
class U>
73bool send(T&& package, std::shared_ptr<U> conn,
bool priority =
false) {
77 return conn->addMessage(msg, priority);
82 bool priority =
false) {
85 return conn->addMessage(msg, priority);
90 bool priority =
false) {
93 return conn->addMessage(msg, priority);
97template <
class T,
class U>
101 variant.printTo(msg);
102 return conn->addMessageWithPriority(msg, priorityLevel);
105template <
class T,
class U>
109 variant.printTo(msg);
110 return conn->addMessageWithPriority(msg, priorityLevel);
116 variant.printTo(msg);
117 return conn->addMessageWithPriority(msg, priorityLevel);
123 variant.printTo(msg);
124 return conn->addMessageWithPriority(msg, priorityLevel);
137 variant.printTo(msg);
138 auto conn = findRoute<U>(layout, variant.
dest());
139 if (conn)
return conn->addMessageWithPriority(msg, variant.
priority());
143template <
class T,
class U>
146 return send<U>(variant, layout);
149template <
class T,
class U>
152 return send<U>(variant, layout);
157 return send<U>(variant, layout);
164 variant.printTo(msg);
165 const auto priority = variant.
priority();
167 for (
auto&& conn : layout.
subs) {
168 if (conn->nodeId != 0 && conn->nodeId != exclude) {
169 auto sent = conn->addMessageWithPriority(msg, priority);
176template <
class T,
class U>
180 return broadcast<U>(variant, layout, exclude);
183template <
class T,
class U>
187 return broadcast<U>(variant, layout, exclude);
193 return broadcast<T>(variant, layout, exclude);
198 std::shared_ptr<T> connection,
const TSTRING& pkg,
200 uint32_t receivedAt) {
201 using namespace logger;
202 Log(COMMUNICATION,
"routePackage(): Recvd from %u: %s\n", connection->nodeId,
204#if ARDUINOJSON_VERSION_MAJOR == 7
212 "routePackage(): parsing failed. err=%s, total_length=%lu, data=%s<--\n",
213 variant.
error.c_str(),
static_cast<unsigned long>(pkg.length()),
220 send<T>(variant, layout);
223 broadcast<T>(variant, layout, connection->
nodeId);
225 auto calls = cbl.
execute(variant.
type(), variant, connection, receivedAt);
227 Log(DEBUG,
"routePackage(): No callbacks executed; %u, %s\n",
228 variant.
type(), pkg.c_str());
233 size_t nestingDepth = std::count(pkg.begin(), pkg.end(),
'{') +
234 std::count(pkg.begin(), pkg.end(),
'[');
236#if ARDUINOJSON_VERSION_MAJOR >= 7
238 size_t calculatedCapacity = pkg.length() + 1024;
243 size_t calculatedCapacity = pkg.length() +
244 JSON_OBJECT_SIZE(10) * (std::max)(nestingDepth,
size_t(1)) +
250 constexpr size_t MAX_MESSAGE_CAPACITY = 8192;
251 size_t capacity = (std::min)(calculatedCapacity, MAX_MESSAGE_CAPACITY);
253 auto variant = std::make_shared<protocol::Variant>(pkg, capacity);
255 if (variant->
error) {
258 if (variant->
error == DeserializationError::NoMemory) {
260 "routePackage(): Message too large. length=%lu, calculated_capacity=%lu, "
261 "nesting_depth=%lu. Consider increasing MAX_MESSAGE_CAPACITY if needed.\n",
262 static_cast<unsigned long>(pkg.length()),
263 static_cast<unsigned long>(calculatedCapacity),
264 static_cast<unsigned long>(nestingDepth));
267 "routePackage(): parsing failed. err=%s, length=%lu, data=%s<--\n",
268 variant->
error.c_str(),
static_cast<unsigned long>(pkg.length()),
276 send<T>((*variant), layout);
279 broadcast<T>((*variant), layout, connection->
nodeId);
281 auto calls = cbl.
execute(variant->
type(), (*variant), connection, receivedAt);
283 Log(DEBUG,
"routePackage(): No callbacks executed; %u, %s\n",
284 variant->
type(), pkg.c_str());
288template <
class T,
class U>
290 std::shared_ptr<U> conn) {
293 if (!conn->validSubs(newTree)) {
295 Log.
remote(
"Invalid connection to %u\n", conn->nodeId);
300 if (conn->newConnection) {
321 auto otherRoute = router::findLiveRoute<U>(mesh, newTree.
nodeId, conn);
324 "handleNodeSync(): %u's tree contains this node and %u is already "
325 "reachable through %u: a loop. Closing the new connection\n",
332 "handleNodeSync(): %u's tree lists this node where it used to be; "
333 "stale, not a loop\n",
343 auto oldConnection = router::findLiveRoute<U>(mesh, newTree.
nodeId, conn);
345 if (oldConnection->nodeId == newTree.
nodeId) {
347 "handleNodeSync(): %u connected again while its old link is "
348 "still open; closing the old one\n",
350 oldConnection->close();
353 "handleNodeSync(): %u was reachable through %u; that place is "
354 "stale, the direct connection wins\n",
355 newTree.
nodeId, oldConnection->nodeId);
359 auto remoteNodeId = newTree.
nodeId;
360 mesh.addTask([&mesh, remoteNodeId]() {
363 remoteNodeId, mesh.getNodeTime());
364 mesh.newConnectionCallbacks.execute(remoteNodeId);
372 conn->timeSyncTask.set(10 * TASK_SECOND, TASK_FOREVER, [conn, &mesh]() {
374 mesh.startTimeSync(conn);
376 mesh.mScheduler->addTask(conn->timeSyncTask);
379 conn->timeSyncTask.enable();
382 conn->timeSyncTask.enableDelayed();
383 conn->newConnection =
false;
401 bool restated = conn->presented == fingerprint;
402 conn->presented = fingerprint;
405 conn->nodeSyncTask.delay();
406 mesh.stability += (std::min)(1000 - mesh.stability, (
size_t)25);
417 for (
auto&& other : mesh.subs) {
418 if (other == conn || other->nodeId == 0)
continue;
422 "handleNodeSync(): %u nodes now under %u were still listed under "
423 "%u; forgotten there\n",
424 (
unsigned)removed, conn->nodeId, other->nodeId);
440 if (conn->nodeId != 0) {
441 bool dropped =
false;
449 for (
auto&& other : mesh.subs) {
450 if (other != conn) other->presented = 0;
454 if (conn->updateSubs(newTree)) {
455 auto nodeId = newTree.
nodeId;
457 [&mesh, nodeId]() { mesh.changedConnectionCallbacks.execute(nodeId); });
459 conn->nodeSyncTask.delay();
460 mesh.stability += (std::min)(1000 - mesh.stability, (
size_t)25);
464template <
class T,
typename U>
471 uint32_t receivedAt) {
473 handleNodeSync<T, U>(mesh, newTree, connection);
474 send<protocol::NodeSyncReply>(
475 connection->reply(std::move(mesh.asNodeTree())), connection,
true);
483 uint32_t receivedAt) {
485 handleNodeSync<T, U>(mesh, newTree, connection);
486 connection->timeOutTask.disable();
Definition callback.hpp:57
int execute(int id, Args... args)
Definition callback.hpp:98
void onPackage(int id, std::function< void(Args...)> func)
Definition callback.hpp:62
uint32_t getNodeId() const
Definition layout.hpp:108
uint32_t nodeId
Definition layout.hpp:125
std::list< std::shared_ptr< T > > subs
Definition layout.hpp:101
void remote(const char *format...)
Definition logger.hpp:160
Definition protocol.hpp:332
Definition protocol.hpp:277
Definition protocol.hpp:167
uint32_t nodeId
Definition protocol.hpp:169
Definition protocol.hpp:481
int type()
Definition protocol.hpp:750
router::Type routing()
Definition protocol.hpp:780
uint32_t dest()
Definition protocol.hpp:800
DeserializationError error
Definition protocol.hpp:837
T to()
Definition protocol.hpp:743
uint8_t priority()
Definition protocol.hpp:775
String TSTRING
Definition configuration.hpp:132
bool forget(protocol::NodeTree &tree, uint32_t nodeId)
Definition layout.hpp:37
uint32_t fingerprint(const protocol::NodeTree &tree, uint32_t hash=2166136261u)
Definition layout.hpp:72
bool contains(protocol::NodeTree nodeTree, uint32_t nodeId)
Definition layout.hpp:16
std::list< uint32_t > asList(protocol::NodeTree nodeTree, bool includeSelf=true)
Definition layout.hpp:262
size_t forgetAll(protocol::NodeTree &tree, const protocol::NodeTree &elsewhere)
Definition layout.hpp:58
@ S_TIME
Definition logger.hpp:24
@ SYNC
Definition logger.hpp:23
@ CONNECTION
Definition logger.hpp:22
@ NODE_SYNC_REPLY
Definition protocol.hpp:39
@ NODE_SYNC_REQUEST
Definition protocol.hpp:38
void addPackageCallback(callback::MeshPackageCallbackList< U > &callbackList, T &mesh)
Definition router.hpp:465
@ SINGLE
Definition protocol.hpp:30
@ BROADCAST
Definition protocol.hpp:30
bool send(T &package, std::shared_ptr< U > conn, bool priority=false)
Definition router.hpp:65
size_t broadcast(protocol::Variant &variant, const layout::Layout< T > &layout, uint32_t exclude)
Definition router.hpp:161
void handleNodeSync(T &mesh, protocol::NodeTree newTree, std::shared_ptr< U > conn)
Definition router.hpp:289
bool sendWithPriority(T &package, std::shared_ptr< U > conn, uint8_t priorityLevel)
Definition router.hpp:98
std::shared_ptr< T > findRoute(const layout::Layout< T > &tree, std::function< bool(std::shared_ptr< T >)> func)
Definition router.hpp:25
std::shared_ptr< T > findLiveRoute(const layout::Layout< T > &tree, uint32_t nodeId, std::shared_ptr< T > exclude=nullptr)
Definition router.hpp:57
void routePackage(const layout::Layout< T > &layout, std::shared_ptr< T > connection, const TSTRING &pkg, callback::MeshPackageCallbackList< T > &cbl, uint32_t receivedAt)
Definition router.hpp:197
painlessmesh::logger::LogClass Log
Definition wifi.cpp:2
painlessmesh::logger::LogClass Log
Definition wifi.cpp:2