import socket import Messages import threading from ClientMsg import ClientMsg from NetworkIdMsg import NetworkIdMsg 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.ipAddress = 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.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.ipAddress == 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) self.others.append(remote_participant) remote_participant.network_id = len(self.others) return remote_participant def Send(self, msg): buffer_size = msg.Serialize([self.buffer]) if buffer_size <= 0: return True self.udp_socket.sendto(self.buffer[:buffer_size], (self.ipAddress, 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], ('', self.port)) return True def Update(self, currentTime): if (currentTime > self.nextPublishMe): self.Publish(ClientMsg(self.network_id)) print(f'Sent ClientMsg') self.nextPublishMe = currentTime + Participant.publishInterval Thing.UpdateAll(currentTime) 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'############################ New Client') pass def ProcessNetworkIdMsg(self, msg: NetworkIdMsg): self.network_id = msg.network_id print(f'receive network id {msg.network_id}') pass def ProcessInvestigateMsg(self, data: bytearray): pass def Receiver(self): while True: data, addr = self.udp_socket.recvfrom(1024) remote_participant = self.GetParticipant(addr[0], addr[1]) if remote_participant is None: remote_participant = self.AddParticipant(addr[0], addr[1]) remote_participant.ReceiveData(data) def ReceiveData(self, data): msgId = data[0] match msgId: case ClientMsg.id: self.ProcessClientMsg(ClientMsg(data)) case NetworkIdMsg.id: self.ProcessNetworkIdMsg(NetworkIdMsg(data)) case Messages.InvestigateMsg.id: msg = Messages.InvestigateMsg(data) self.ProcessInvestigateMsg(msg) case Messages.BinaryMsg.id: msg = Messages.BinaryMsg(data) msg.thing.ProcessBinary(msg.data)