mesh route results

This commit is contained in:
Laura Klünder 2023-10-05 05:02:01 +02:00
parent c724833542
commit 0343030980
7 changed files with 170 additions and 47 deletions

View file

@ -24,10 +24,10 @@ function connect() {
window.setTimeout(connect, 500);
}
ws.onmessage = (event) => {
var data = JSON.parse(event.data), line, text;
var data = JSON.parse(event.data), line, text, cell, link_tag;
switch(data.type) {
case 'mesh.log_entry':
line = document.createElement("tr"), cell, link_tag;
line = document.createElement("tr");
cell = document.createElement("td");
cell.innerText = data.timestamp;
@ -37,7 +37,7 @@ function connect() {
cell.innerText = data.channel;
if (data.uplink) {
cell.append(document.createElement("br"));
link_tag = document.createElement("a")
link_tag = document.createElement("a");
link_tag.href = "/control/mesh/" + data.uplink;
link_tag.innerText = data.uplink;
if (node_names[data.uplink]) {
@ -48,7 +48,7 @@ function connect() {
line.appendChild(cell);
cell = document.createElement("td");
link_tag = document.createElement("a")
link_tag = document.createElement("a");
link_tag.href = "/control/mesh/" + data.node;
link_tag.innerText = data.node;
if (node_names[data.node]) {
@ -73,6 +73,54 @@ function connect() {
document.getElementById("sending-status-"+data.recipient).appendChild(line);
{% endif %}
break;
case 'mesh.msg_received':
{% if send_uuid and msg_type == "MESH_ROUTE_REQUEST" %}
if (data.msg.route) {
link_tag = document.createElement("a");
link_tag.href = "/control/mesh/" + data.msg.src;
link_tag.innerText = data.msg.src;
if (node_names[data.msg.src]) {
link_tag.innerText += " ("+node_names[data.msg.src]+")";
}
if (data.msg.route === "00:00:00:00:00:00") {
line = document.createElement("li");
line.appendChild(link_tag);
document.getElementById("no-routes").appendChild(line);
} else {
line = document.createElement("tr");
cell = document.createElement("td");
cell.appendChild(link_tag);
line.appendChild(cell);
cell = document.createElement("td");
link_tag = document.createElement("a");
link_tag.href = "/control/mesh/" + data.msg.route;
link_tag.innerText = data.msg.route;
if (node_names[data.msg.route]) {
link_tag.innerText += " ("+node_names[data.msg.route]+")";
}
cell.append(link_tag);
line.appendChild(cell);
document.getElementById("route-responses").appendChild(line);
}
} else {
for (var i=0;i<data.msg.trace.length;i++) {
line = document.createElement("li");
link_tag = document.createElement("a");
link_tag.href = "/control/mesh/" + data.msg.trace[i];
link_tag.innerText = data.msg.trace[i];
if (node_names[data.msg.trace[i]]) {
link_tag.innerText += " ("+node_names[data.msg.trace[i]]+")";
}
line.appendChild(link_tag);
document.getElementById("route-trace").appendChild(line);
}
}
{% endif %}
break;
}
console.log(data);

View file

@ -9,18 +9,45 @@
{% block subcontent %}
<p><a class="button" href="{{ success_url }}">Go back</a></p>
<table>
<tr>
<th>Recipient</th>
<th>Status</th>
</tr>
{% for address, name in recipients %}
<tr>
<td>{{ address }}{% if name %} ({{ name }}){% endif %}</td>
<td id="sending-status-{{ address }}"></td>
</tr>
{% endfor %}
</table>
<div class="columns">
<div>
<h4>Sending progress</h4>
<table>
<tr>
<th>Recipient</th>
<th>Status</th>
</tr>
{% for address, name in recipients %}
<tr>
<td>{{ address }}{% if name %} ({{ name }}){% endif %}</td>
<td id="sending-status-{{ address }}"></td>
</tr>
{% endfor %}
</table>
</div>
{% if msg_type == "MESH_ROUTE_REQUEST" %}
<div>
<h4>Routes</h4>
<table>
<thead>
<tr>
<th>{% trans 'Node' %}</th>
<th>{% trans 'Route' %}</th>
</tr>
</thead>
<tbody id="route-responses"></tbody>
</table>
</div>
<div>
<h4>No Route</h4>
<ul id="no-routes"></ul>
</div>
<div>
<h4>Trace</h4>
<ul id="route-trace"></ul>
</div>
{% endif %}
</div>
{% include "control/fragment_mesh_websocket.html" %}
{% endblock %}

View file

@ -14,6 +14,7 @@ from c3nav.control.views.base import ControlPanelMixin
from c3nav.mesh.forms import MeshMessageForm, MeshNodeForm
from c3nav.mesh.messages import MeshMessageType
from c3nav.mesh.models import MeshNode, NodeMessage
from c3nav.mesh.utils import get_node_names
class MeshNodeListView(ControlPanelMixin, ListView):
@ -137,9 +138,7 @@ class MeshMessageSendingView(ControlPanelMixin, TemplateView):
data = self.request.session["mesh_msg_%s" % uuid]
except KeyError:
raise Http404
node_names = {
node.address: node.name for node in MeshNode.objects.all()
}
node_names = get_node_names()
return {
**super().get_context_data(),
"node_names": node_names,
@ -156,7 +155,5 @@ class MeshLogView(ControlPanelMixin, TemplateView):
def get_context_data(self, **kwargs):
return {
**super().get_context_data(),
"node_names": {
node.address: node.name for node in MeshNode.objects.all()
}
}
"node_names": get_node_names(),
}

View file

@ -6,7 +6,7 @@ from django.utils import timezone
from c3nav.mesh.utils import get_mesh_comm_group
from c3nav.mesh import messages
from c3nav.mesh.messages import MeshMessage, BROADCAST_ADDRESS
from c3nav.mesh.messages import MeshMessage, MESH_BROADCAST_ADDRESS, MeshMessageType
from c3nav.mesh.models import MeshNode, NodeMessage
@ -23,7 +23,9 @@ class MeshConsumer(WebsocketConsumer):
self.log_text(self.uplink_node, "mesh websocket disconnected")
if self.uplink_node is not None:
# leave broadcast group
async_to_sync(self.channel_layer.group_add)(get_mesh_comm_group(BROADCAST_ADDRESS), self.channel_name)
async_to_sync(self.channel_layer.group_discard)(
get_mesh_comm_group(MESH_BROADCAST_ADDRESS), self.channel_name
)
# remove all other destinations
self.remove_dst_nodes(self.dst_nodes)
@ -51,7 +53,7 @@ class MeshConsumer(WebsocketConsumer):
traceback.print_exc()
return
if msg.dst != messages.ROOT_ADDRESS and msg.dst != messages.PARENT_ADDRESS:
if msg.dst != messages.MESH_ROOT_ADDRESS and msg.dst != messages.MESH_PARENT_ADDRESS:
print('Received message for forwarding:', msg)
# todo: this message isn't for us, forward it
return
@ -67,13 +69,15 @@ class MeshConsumer(WebsocketConsumer):
# inform signed in uplink node about its layer
self.send_msg(messages.MeshLayerAnnounceMessage(
src=messages.ROOT_ADDRESS,
src=messages.MESH_ROOT_ADDRESS,
dst=msg.src,
layer=messages.NO_LAYER
))
# add signed in uplink node to broadcast group
async_to_sync(self.channel_layer.group_add)('mesh_broadcast', self.channel_name)
async_to_sync(self.channel_layer.group_add)(
get_mesh_comm_group(MESH_BROADCAST_ADDRESS), self.channel_name
)
# kick out other consumers talking to the same uplink
async_to_sync(self.channel_layer.group_send)(get_mesh_comm_group(msg.src), {
@ -179,7 +183,7 @@ class MeshConsumer(WebsocketConsumer):
# tell the node to dump its current information
self.send_msg(
messages.ConfigDumpMessage(
src=messages.ROOT_ADDRESS,
src=messages.MESH_ROOT_ADDRESS,
dst=address,
)
)
@ -230,10 +234,15 @@ class MeshUIConsumer(JsonWebsocketConsumer):
if not msg_to_send:
return
self.scope["session"].save()
async_to_sync(self.channel_layer.group_add)("mesh_msg_sent", self.channel_name)
self.msg_sent_filter = {"sender": self.channel_name}
if msg_to_send["msg_data"]["msg_id"] == MeshMessageType.MESH_ROUTE_REQUEST:
async_to_sync(self.channel_layer.group_add)("mesh_msg_received", self.channel_name)
self.msg_received_filter = {"request_id": msg_to_send["msg_data"]["request_id"]}
for recipient in msg_to_send["recipients"]:
print('send to', recipient)
MeshMessage.fromjson({
'dst': recipient,
**msg_to_send["msg_data"],
@ -243,7 +252,6 @@ class MeshUIConsumer(JsonWebsocketConsumer):
self.send_json(data)
def mesh_msg_sent(self, data):
print('got data', data)
for key, value in self.msg_sent_filter.items():
if isinstance(value, list):
if data.get(key, None) not in value:
@ -253,6 +261,18 @@ class MeshUIConsumer(JsonWebsocketConsumer):
return
self.send_json(data)
def mesh_msg_received(self, data):
print('got received', data)
for key, filter_value in self.msg_received_filter.items():
value = data.get(key, data["msg"].get(key, None))
if isinstance(filter_value, list):
if value not in filter_value:
return
else:
if value != filter_value:
return
self.send_json(data)
def disconnect(self, code):
async_to_sync(self.channel_layer.group_discard)("mesh_log", self.channel_name)
async_to_sync(self.channel_layer.group_discard)("mesh_msg_sent", self.channel_name)

View file

@ -1,4 +1,6 @@
import time
from dataclasses import fields as dataclass_fields
from functools import cached_property
from django import forms
from django.core.exceptions import ValidationError
@ -6,7 +8,7 @@ from django.http import Http404
from django.utils.translation import gettext_lazy as _
from c3nav.mesh.dataformats import LedConfig
from c3nav.mesh.messages import MeshMessageType, MeshMessage, ROOT_ADDRESS
from c3nav.mesh.messages import MeshMessageType, MeshMessage, MESH_ROOT_ADDRESS, MESH_BROADCAST_ADDRESS
from c3nav.mesh.models import MeshNode
@ -25,23 +27,26 @@ class MeshMessageForm(forms.Form):
super().__init__(*args, initial=initial, **kwargs)
recipient_root_choices = {
'ff:ff:ff:ff:ff:ff': _('broadcast')
MESH_BROADCAST_ADDRESS: _('broadcast')
}
recipient_node_choices = {
node_choices = {
node.address: str(node) for node in MeshNode.objects.all()
}
self.recipient_choices = {
self.node_choices_flat = {
**recipient_root_choices,
**recipient_node_choices,
**node_choices,
}
self.node_choices = tuple(node_choices.items())
self.node_choices_with_broadcast = (
*recipient_root_choices.items(),
(_('nodes'), self.node_choices),
)
if self.recipient is None:
self.fields['recipients'].choices = (
*recipient_root_choices.items(),
(_('nodes'), tuple(recipient_node_choices.items()))
)
self.fields['recipients'].choices = self.node_choices_with_broadcast
else:
if self.recipient not in self.recipient_choices:
raise Http404
if self.recipient not in self.node_choices_flat:
raise Http404('unknown recipient')
self.fields.pop('recipients')
# noinspection PyMethodOverriding
@ -56,7 +61,7 @@ class MeshMessageForm(forms.Form):
return cls.msg_types[msg_type]
def get_recipient_display(self):
return self.recipient_choices[self.recipient]
return self.node_choices_flat[self.recipient]
def get_cleaned_msg_data(self):
msg_data = self.cleaned_data.copy()
@ -69,7 +74,7 @@ class MeshMessageForm(forms.Form):
return {
'msg_id': self.msg_type,
'src': ROOT_ADDRESS,
'src': MESH_ROOT_ADDRESS,
**self.get_cleaned_msg_data(),
}
@ -87,6 +92,22 @@ class MeshMessageForm(forms.Form):
}).send()
class MeshRouteRequestForm(MeshMessageForm):
msg_type = MeshMessageType.MESH_ROUTE_REQUEST
address = forms.ChoiceField(choices=())
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields["address"].choices = self.node_choices
def get_msg_data(self):
return {
**super().get_msg_data(),
"request_id": int(time.time()*100000) % 2**32,
}
class ConfigUplinkMessageForm(MeshMessageForm):
msg_type = MeshMessageType.CONFIG_UPLINK

View file

@ -11,9 +11,9 @@ from c3nav.mesh.utils import get_mesh_comm_group, indent_c
from c3nav.mesh.dataformats import (BoolFormat, FixedStrFormat, HexFormat, LedConfig, LedConfigFormat,
MacAddressesListFormat, MacAddressFormat, SimpleFormat, VarStrFormat)
ROOT_ADDRESS = '00:00:00:00:00:00'
PARENT_ADDRESS = '00:00:00:ff:ff:ff'
BROADCAST_ADDRESS = 'ff:ff:ff:ff:ff:ff'
MESH_ROOT_ADDRESS = '00:00:00:00:00:00'
MESH_PARENT_ADDRESS = '00:00:00:ff:ff:ff'
MESH_BROADCAST_ADDRESS = 'ff:ff:ff:ff:ff:ff'
NO_LAYER = 0xFF
@unique

View file

@ -4,3 +4,13 @@ def get_mesh_comm_group(address):
def indent_c(code):
return " "+code.replace("\n", "\n ")
def get_node_names():
from c3nav.mesh.models import MeshNode
return {
**{node.address: node.name for node in MeshNode.objects.all()},
'ff:ff:ff:ff:ff:ff': "broadcast",
'00:00:00:ff:ff:ff': "direct parent",
'00:00:00:00:00:00': "root",
}