more mesh node stuff

This commit is contained in:
Laura Klünder 2023-10-03 17:51:49 +02:00
parent 4d3f54bbe8
commit 473e60aed0
5 changed files with 100 additions and 28 deletions

View file

@ -7,22 +7,14 @@
<table>
<tr>
<th>{% trans 'Node' %}</th>
<th>{% trans 'Status' %}</th>
<th>{% trans 'Chip' %}</th>
<th>{% trans 'Firmware' %}</th>
<th>{% trans 'Last msg' %}</th>
<th>{% trans 'Parent' %}</th>
<th>{% trans 'Route' %}</th>
<th>{% trans 'Last signin' %}</th>
<th>{% trans 'Uplink' %}</th>
</tr>
{% for node in nodes %}
<tr>
<td>
{% if node.route %}
<span style="color: green;">{% trans "online" %}</span>
{% else %}
<span style="color: red;">{% trans "offline" %}</span>
{% endif %}
</td>
<td>{{ node }}</td>
<td>
{{ node.last_messages.CONFIG_FIRMWARE.parsed.get_chip_display }}
@ -37,9 +29,12 @@
{{ timesince }} ago
{% endblocktrans %}
</td>
<td>{{ node.parent }}</td>
<td>{{ node.route }}</td>
<td>{{ node.last_messages.CONFIG_FIRMWARE.data }}</td>
<td>
{% blocktrans trimmed with timesince=node.last_signin|timesince %}
{{ timesince }} ago
{% endblocktrans %}
</td>
<td>{{ node.uplink }}</td>
</tr>
{% endfor %}
</table>

View file

@ -2,6 +2,7 @@ import traceback
from asgiref.sync import async_to_sync
from channels.generic.websocket import WebsocketConsumer
from django.utils import timezone
from c3nav.mesh import messages
from c3nav.mesh.models import MeshNode, NodeMessage
@ -19,9 +20,11 @@ class MeshConsumer(WebsocketConsumer):
def disconnect(self, close_code):
print('disconnected!')
if self.uplink_node is not None:
self.remove_route(self.uplink_node)
self.channel_layer.group_discard('route_%s' % self.node.address.replace(':', ''), self.channel_name)
self.channel_layer.group_discard('route_broadcast', self.channel_name)
# leave broadcast group
async_to_sync(self.channel_layer.group_add)('mesh_broadcast', self.channel_name)
# remove all other destinations
self.remove_dst_nodes(self.dst_nodes)
def send_msg(self, msg):
print('Sending message:', msg)
@ -57,9 +60,15 @@ class MeshConsumer(WebsocketConsumer):
layer=messages.NO_LAYER
))
# add signed in uplink node to broadcast route
# add signed in uplink node to broadcast group
async_to_sync(self.channel_layer.group_add)('mesh_broadcast', self.channel_name)
# kick out other consumers talking to the same uplink
async_to_sync(self.channel_layer.group_send)(self.group_name_for_node(msg.src), {
"type": "mesh.uplink_consumer",
"name": self.channel_name,
})
# add this node as a destination that this uplink handles (duh)
self.add_dst_nodes((src_node.address, ))
@ -72,12 +81,17 @@ class MeshConsumer(WebsocketConsumer):
self.log_received_message(src_node, msg)
def uplink_change(self, data):
def mesh_uplink_consumer(self, data):
# message handler: if we are not the given uplink, leave this group
if data["name"] != self.channel_name:
print('shutting down since we have been replaced')
self.close()
def mesh_dst_node_uplink(self, data):
# message handler: if we are not the given uplink, leave this group
if data["uplink"] != self.uplink_node.address:
group = self.group_name_for_node(data["address"])
print('leaving uplink group...')
async_to_sync(self.channel_layer.group_discard)(group, self.channel_name)
print('leaving node group...')
self.remove_dst_nodes((data["address"], ))
def log_received_message(self, src_node: MeshNode, msg: messages.Message):
NodeMessage.objects.create(
@ -88,7 +102,6 @@ class MeshConsumer(WebsocketConsumer):
)
def add_dst_nodes(self, addresses):
# add ourselves to this one
for address in addresses:
# create group name for this address
group = self.group_name_for_node(address)
@ -100,7 +113,7 @@ class MeshConsumer(WebsocketConsumer):
# tell other consumers to leave the group
async_to_sync(self.channel_layer.group_send)(group, {
"type": "uplink_change",
"type": "mesh.dst_node_uplink",
"node": address,
"uplink": self.uplink_node.address
})
@ -114,7 +127,27 @@ class MeshConsumer(WebsocketConsumer):
)
# add the stuff to the db as well
MeshNode.objects.filter(address__in=addresses).update(route_id=self.uplink_node.address)
MeshNode.objects.filter(address__in=addresses).update(
uplink_id=self.uplink_node.address,
last_signin=timezone.now(),
)
def remove_dst_nodes(self, addresses):
for address in addresses:
# create group name for this address
group = self.group_name_for_node(address)
# leave the group
if address in self.dst_nodes:
async_to_sync(self.channel_layer.group_discard)(group, self.channel_name)
self.dst_nodes.discard(address)
# add the stuff to the db as well
# todo: can't do this because of race condition
#MeshNode.objects.filter(address__in=addresses, uplink_id=self.uplink_node.address).update(
# uplink_id=self.uplink_node.address,
# last_signin=timezone.now(),
#)
def group_name_for_node(self, address):
return 'mesh_%s' % address.replace(':', '-')

View file

@ -0,0 +1,18 @@
# Generated by Django 4.2.1 on 2023-10-03 15:27
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('mesh', '0004_relay_vs_src_node_and_remove_firmware'),
]
operations = [
migrations.AddField(
model_name='meshnode',
name='last_signin',
field=models.DateTimeField(null=True, verbose_name='last signin'),
),
]

View file

@ -0,0 +1,25 @@
# Generated by Django 4.2.1 on 2023-10-03 15:31
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('mesh', '0005_meshnode_last_signin'),
]
operations = [
migrations.RenameField(
model_name='meshnode',
old_name='route',
new_name='uplink',
),
migrations.AlterField(
model_name='meshnode',
name='uplink',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.PROTECT, related_name='routed_nodes',
to='mesh.meshnode', verbose_name='uplink'),
),
]

View file

@ -32,8 +32,8 @@ class MeshNodeQuerySet(models.QuerySet):
try:
for message in NodeMessage.objects.order_by('-datetime', '-pk').filter(
message_type__in=self._prefetch_last_messages,
node__in=nodes.keys(),
).distinct('message_type', 'node'):
src_node__in=nodes.keys(),
).distinct('message_type', 'src_node'):
nodes[message.node].last_messages[message.message_type] = message
except NotSupportedError:
pass
@ -73,8 +73,9 @@ class MeshNode(models.Model):
address = models.CharField(_('mac address'), max_length=17, primary_key=True)
name = models.CharField(_('name'), max_length=32, null=True, blank=True)
first_seen = models.DateTimeField(_('first seen'), auto_now_add=True)
route = models.ForeignKey('MeshNode', models.PROTECT, null=True,
related_name='routed_nodes', verbose_name=_('route'))
uplink = models.ForeignKey('MeshNode', models.PROTECT, null=True,
related_name='routed_nodes', verbose_name=_('uplink'))
last_signin = models.DateTimeField(_('last signin'), null=True)
objects = models.Manager.from_queryset(MeshNodeQuerySet)()
def __str__(self):