some more message parsing fixes and routing implementation

This commit is contained in:
Laura Klünder 2023-10-06 02:15:51 +02:00
parent b40b396eb4
commit 59ebdd74bb
3 changed files with 69 additions and 10 deletions

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, MESH_BROADCAST_ADDRESS, MeshMessageType
from c3nav.mesh.messages import MeshMessage, MESH_BROADCAST_ADDRESS, MeshMessageType, MESH_ROOT_ADDRESS
from c3nav.mesh.models import MeshNode, NodeMessage
@ -30,9 +30,9 @@ class MeshConsumer(WebsocketConsumer):
# remove all other destinations
self.remove_dst_nodes(self.dst_nodes)
def send_msg(self, msg, sender=None):
# print("sending", msg)
# self.log_text(msg.dst, "sending %s" % msg)
def send_msg(self, msg, sender=None, exclude_uplink_address=None):
#print("sending", msg, MeshMessage.encode(msg).hex(' ', 1))
#self.log_text(msg.dst, "sending %s" % msg)
self.send(bytes_data=MeshMessage.encode(msg))
async_to_sync(self.channel_layer.group_send)("mesh_msg_sent", {
"type": "mesh.msg_sent",
@ -54,9 +54,29 @@ class MeshConsumer(WebsocketConsumer):
return
if msg.dst != messages.MESH_ROOT_ADDRESS and msg.dst != messages.MESH_PARENT_ADDRESS:
# message not adressed to us, forward it
print('Received message for forwarding:', msg)
# todo: this message isn't for us, forward it
return
if not self.uplink_node:
self.log_text(self.uplink_node, "received message not for us before sign in message, ignoring...")
print('no sign in yet, ignoring')
return
# trace messages collect node adresses before forwarding
if isinstance(msg, messages.MeshRouteTraceMessage):
print('adding ourselves to trace message before forwarding')
self.log_text(MESH_ROOT_ADDRESS, "adding ourselves to trace message before forwarding")
msg.trace.append(MESH_ROOT_ADDRESS)
msg.send(exclude_uplink_address=self.uplink_node.address)
# don't handle this message unless it's a broadcast message
if msg.dst != messages.MESH_BROADCAST_ADDRESS:
# don't handle this message unless it's a broadcast message
self.log_text(MESH_ROOT_ADDRESS, "received non-broadcast message not for us, forwarding...")
return
print('it\'s a broadcast so it\'s also for us')
self.log_text(MESH_ROOT_ADDRESS, "received broadcast message, forwarding and handling...")
#print('Received message:', msg)
@ -103,6 +123,24 @@ class MeshConsumer(WebsocketConsumer):
if isinstance(msg, messages.MeshRemoveDestinationsMessage):
self.remove_dst_nodes(addresses=msg.addresses)
if isinstance(msg, messages.MeshRouteRequestMessage):
if msg.address == MESH_ROOT_ADDRESS:
self.log_text(MESH_ROOT_ADDRESS, "route request about us, start a trace")
messages.MeshRouteTraceMessage(
src=MESH_ROOT_ADDRESS,
dst=msg.src,
request_id=msg.request_id,
trace=[MESH_ROOT_ADDRESS],
).send()
else:
# todo: find a way to send a "no route" message if there is no route
self.log_text(MESH_ROOT_ADDRESS, "requesting route response responsible uplink")
async_to_sync(self.channel_layer.group_send)(get_mesh_comm_group(msg.address), {
"type": "mesh.send_route_response",
"request_id": msg.request_id,
"dst": msg.src,
})
def mesh_uplink_consumer(self, data):
# message handler: if we are not the given uplink, leave this group
if data["name"] != self.channel_name:
@ -116,8 +154,27 @@ class MeshConsumer(WebsocketConsumer):
self.remove_dst_nodes((data["address"], ))
def mesh_send(self, data):
if self.uplink_node.address == data["exclude_uplink_address"]:
if data["msg"]["dst"] == MESH_BROADCAST_ADDRESS:
self.log_text(
self.uplink_node.address, "not forwarding this broadcast message via us since it came from here"
)
else:
self.log_text(
self.uplink_node.address, "we're the route for this message but it came from here so... no"
)
return
self.send_msg(MeshMessage.fromjson(data["msg"]), data["sender"])
def mesh_send_route_response(self, data):
self.log_text(self.uplink_node.address, "we're the uplink for this address, sending route response...")
messages.MeshRouteResponseMessage(
src=MESH_ROOT_ADDRESS,
dst=data["dst"],
request_id=data["request_id"],
route=self.uplink_node.address,
).send()
def log_received_message(self, src_node: MeshNode, msg: messages.MeshMessage):
as_json = MeshMessage.tojson(msg)
async_to_sync(self.channel_layer.group_send)("mesh_msg_received", {
@ -144,6 +201,7 @@ class MeshConsumer(WebsocketConsumer):
"node": address,
"text": text,
})
print("MESH %s: [%s] %s" % (self.uplink_node, address, text))
def add_dst_nodes(self, nodes=None, addresses=None):
nodes = list(nodes) if nodes else []

View file

@ -132,7 +132,7 @@ class VarArrayFormat(BaseVarFormat):
self.child_size = self.child_type.get_min_size()
def encode(self, values: Sequence) -> bytes:
data = struct.pack(self.num_fmt, (len(values),))
data = struct.pack(self.num_fmt, len(values))
for value in values:
data += self.child_type.encode(value)
return data
@ -153,7 +153,7 @@ class VarArrayFormat(BaseVarFormat):
class VarStrFormat(BaseVarFormat):
def encode(self, value: str) -> bytes:
return struct.pack(self.num_fmt, (len(str),))+value.encode()
return struct.pack(self.num_fmt, len(str))+value.encode()
def decode(self, data: bytes) -> tuple[str, bytes]:
num = struct.unpack(self.num_fmt, data[:self.num_size])[0]
@ -238,7 +238,7 @@ class StructType:
return data
@classmethod
def decode(cls, data: bytes) -> Self:
def decode(cls, data: bytes) -> tuple[Self, bytes]:
orig_data = data
kwargs = {}
no_init_data = {}

View file

@ -67,10 +67,11 @@ class MeshMessage(StructType, union_type_field="msg_id"):
raise TypeError('duplicate use of c_struct_name %s' % c_struct_name)
MeshMessage.c_structs[c_struct_name] = cls
def send(self, sender=None):
def send(self, sender=None, exclude_uplink_address=None):
async_to_sync(channels.layers.get_channel_layer().group_send)(get_mesh_comm_group(self.dst), {
"type": "mesh.send",
"sender": sender,
"exclude_uplink_address": exclude_uplink_address,
"msg": MeshMessage.tojson(self),
})