RoboidControl-python/Participant.py
2024-12-31 16:16:42 +01:00

142 lines
5.0 KiB
Python

import socket
import threading
from ClientMsg import ClientMsg
from NetworkIdMsg import NetworkIdMsg
from ThingMsg import ThingMsg
from NameMsg import NameMsg
from ModelUrlMsg import ModelUrlMsg
from Thing import Thing
## A participant is device which can communicate with other participants
#
## Currently only UDP communication is supported
class Participant:
publishInterval = 3000 # 3 seconds
def __init__(self, ipAddress = "0.0.0.0", port=7681, remote=False):
self.buffer = bytearray(256)
self.ip_address = ipAddress
self.port = port
self.udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
self.udp_socket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
self.buffer = bytearray(256)
if remote == False:
self.udp_socket.bind(("0.0.0.0", 7681))
self.network_id = 0
self.nextPublishMe = 0
self.others = []
self.AddParticipant(self.ip_address, self.port)
self.thread = threading.Thread(target = self.Receiver)
self.thread.daemon = True
self.thread.start()
def GetParticipant(self, ip_address, port):
found_participants = (item for item in self.others
if item.ip_address == ip_address and item.port == port)
participant = next(found_participants, None)
return participant
def AddParticipant(self, ip_address, port):
remote_participant = Participant(ip_address, port, remote=True)
remote_participant.network_id = len(self.others)
self.others.append(remote_participant)
return remote_participant
def Update(self, currentTime):
if (currentTime > self.nextPublishMe):
self.Publish(ClientMsg(self.network_id))
print(f'Sent ClientMsg {self.network_id}')
self.nextPublishMe = currentTime + Participant.publishInterval
Thing.UpdateAll(currentTime)
#region Send
def SendThingInfo(self, thing):
self.Send(ThingMsg(self.network_id, thing))
self.Send(NameMsg(self.network_id, thing))
self.Send(ModelUrlMsg(self.network_id, thing))
def Send(self, msg):
buffer_size = msg.Serialize([self.buffer])
if buffer_size <= 0:
return True
# print(f'send {self.buffer[0]} to {self.ip_address} {self.port}')
self.udp_socket.sendto(self.buffer[:buffer_size], (self.ip_address, self.port))
return True
def Publish(self, msg):
buffer_size = msg.Serialize([self.buffer])
if buffer_size <= 0:
return True
self.udp_socket.sendto(self.buffer[:buffer_size], ('<broadcast>', self.port))
return True
#endregion
#region Receive
def Receiver(self):
while True:
data, addr = self.udp_socket.recvfrom(1024)
remote_ip_address = addr[0]
remote_port = addr[1]
# print(f'msg received from {remote_ip_address}:{remote_port}')
remote_participant = self.GetParticipant(remote_ip_address, remote_port)
if remote_participant is None:
remote_participant = self.AddParticipant(remote_ip_address, self.port)
remote_participant.ReceiveData(data)
def ReceiveData(self, data):
msgId = data[0]
# print(f'msg {msgId} ')
match msgId:
case ClientMsg.id:
self.ProcessClientMsg(ClientMsg(data))
case NetworkIdMsg.id:
self.ProcessNetworkIdMsg(NetworkIdMsg(data))
# case InvestigateMsg.id:
# self.ProcessInvestigateMsg(InvestigateMsg(data))
case ThingMsg.id:
self.ProcessThingMsg(ThingMsg(data))
case NameMsg.id:
self.ProcessNameMsg(NameMsg(data))
case ModelUrlMsg.id:
self.ProcessModelUrlMsg(ModelUrlMsg(data))
# case Messages.BinaryMsg.id:
# msg = Messages.BinaryMsg(data)
# msg.thing.ProcessBinary(msg.data)
def ProcessClientMsg(self, msg: ClientMsg):
if msg.network_id == 0:
self.Send(NetworkIdMsg(self.network_id))
print(f'############################ New Client -> {self.network_id}')
else:
print(f'############################ Client')
def ProcessNetworkIdMsg(self, msg: NetworkIdMsg):
if self.network_id != msg.network_id:
self.network_id = msg.network_id
print(f'receive network id {msg.network_id}')
for thing in Thing.allThings:
self.SendThingInfo(thing)
# self.Send(NameMsg(self.network_id, thing))
def ProcessInvestigateMsg(self, data: bytearray):
pass
def ProcessThingMsg(self, msg: ThingMsg):
print(f'received thing {msg.thing_id}')
def ProcessNameMsg(self, msg: NameMsg):
print(f'received name {msg.name}')
def ProcessModelUrlMsg(self, msg: ModelUrlMsg):
print(f'received model url: {msg.url}')
#endregion