def __init__(self, signal_server=None, private=None): super(ChatClient, self).__init__() self.private = private self.signal_server = signal_server self.prompt = ColoredPrompt(sender=self, prompt=self.getClientName()) stdio.StandardIO(self.prompt) self.chat_server_endpoint = None self.punched_endpoints = [] self.punches = []
class ChatClient(BaseClient): def __init__(self, signal_server=None, private=None): super(ChatClient, self).__init__() self.private = private self.signal_server = signal_server self.prompt = ColoredPrompt(sender=self, prompt=self.getClientName()) stdio.StandardIO(self.prompt) self.chat_server_endpoint = None self.punched_endpoints = [] self.punches = [] def sendLine(self, line): if self.chat_server_endpoint is None: return line = line.strip() line = line.replace('|', '_') # replace special characters msg = 'MSG|%s' % line self.transport.write(msg, self.chat_server_endpoint) def startProtocol(self): self.ensureConnectionToChatServer() def datagramReceived(self, data, addr): if data.startswith(b'INITIATE_PEER_CONNECTION'): self.handleInitiatePeerConnection(addr, data) elif data.startswith(b'HOLED'): self.handlePuncholed(addr) elif data.startswith('MSG'): self.handleChatMessage(addr, data) else: super(ChatClient, self).datagramReceived(data, addr) def ensureConnectionToChatServer(self): if self.chat_server_endpoint is None: msg = b'INITIATE_PEER_CONNECTION|%s|%s' % self.private self.transport.write(msg, self.signal_server) @unpack_datagramm_args def handleInitiatePeerConnection(self, _, public_ip, public_port, private_ip, private_port): private_endpoint = (private_ip, int(private_port)) public_endpoint = (public_ip, int(public_port)) self.prompt.log('connecting to following addresses %s, %s.' % (private_endpoint, public_endpoint)) PUNCHOLING_TIME = 3 # 3s. PACKETS_PER_SEC = 100 self.punched_endpoints = [private_endpoint, public_endpoint] self.clearPunches() for i in xrange(PUNCHOLING_TIME * PACKETS_PER_SEC): time = float(i)/PACKETS_PER_SEC deferred = reactor.callLater(time, self.punch, public_endpoint) self.punches.append(deferred) self.punches.append(reactor.callLater(0.1, self.punch, private_endpoint)) # reconnect recursion reactor.callLater(PUNCHOLING_TIME, self.ensureConnectionToChatServer) def handlePuncholed(self, addr): if addr not in self.punched_endpoints: return self.prompt.log("connected to %s." % str(addr)) self.punched_endpoints = [] self.clearPunches() self.chat_server_endpoint = addr self.connectToServer(addr, self.private) @unpack_datagramm_args def handleChatMessage(self, addr, name, msg): if addr == self.chat_server_endpoint: self.prompt.logChatMsg(name, msg) def punch(self, endpoint): self.transport.write('PUNCH', endpoint) def clearPunches(self): for punch in self.punches: if punch.active(): punch.cancel() self.punches = []