def handle(self, socket, address): """ If not a leader, a node will simply return a single item list pointing to the leader. Otherwise, it will add the host of the connected client to the cluster roster, broadcast to all nodes the new roster, and wait for keepalives. If no keepalive within timeout or the client drops, it drops it from the roster and broadcasts to all remaining nodes. """ if not self.c.is_leader: socket.send(json.dumps({'leader': self.c.client.leader, 'port': self.c.port})) socket.close() logger.debug("Redirected to %s:%s" % (self.c.client.leader, self.c.port)) else: socket.send(self._cluster_message()) sockfile = socket.makefile() name = sockfile.readline() if not name: return if name == '\n': name = address[0] else: name = name.strip() logger.debug('New connection from %s' % name) self._update(add={'host': name, 'socket': socket}) # TODO: Use TCP keepalives timeout = self._client_timeout(socket) for line in util.line_protocol(sockfile, strip=False): timeout.kill() timeout = self._client_timeout(socket) socket.send('\n') #logger.debug("Keepalive from %s:%s" % address) #logger.debug("Client disconnected from %s:%s" % address) self._update(remove=name)
def handle(self, socket): self.set_ready() #logger.debug("Connected to leader") client_address = self.identity or socket.getsockname()[0] socket.send('%s\n' % client_address) # TODO: Use TCP keepalives keepalive = self._server_keepalive(socket) try: for line in util.line_protocol(socket, strip=False): if line == '\n': # Keepalive ack from leader keepalive.kill() keepalive = self._server_keepalive(socket) else: cluster = json.loads(line) if 'leader' in cluster: # Means you have the wrong leader, redirect self.leader = cluster['leader'] logger.info("Redirected to %s:%s..." % (self.leader, self.c.port)) raise NewLeader() elif client_address in cluster['cluster']: # Only report cluster once I'm a member self.c.set.replace(set(cluster['cluster'])) self.c.set.remove(self.leader) self._leader_election() except NewLeader: #self.manager.trigger_callback() if self.leader == client_address: self.c.is_leader = True self.c.promoted.set() self.stop() # doesn't work else: return
def test_does_connect(): class SimpleServer(gevent.server.StreamServer): def handle(self, socket, address): socket.sendall("hello and goodbye!") socket.shutdown(0) server = SimpleServer(("127.0.0.1", 0)) server.start() client = util.connect_and_retry(("127.0.0.1", server.server_port)) lines = [line for line in util.line_protocol(client)] assert len(lines) == 1, "Didn't receive the line" server.stop()
def test_eventual_connect(): class SimpleServer(gevent.server.StreamServer): def handle(self, socket, address): socket.sendall("hello and goodbye!") socket.shutdown(0) server = SimpleServer(("127.0.0.1", 16667)) gevent.spawn_later(0.5, server.start) client = util.connect_and_retry(("127.0.0.1", 16667), max_delay=1) lines = [line for line in util.line_protocol(client)] assert len(lines) == 1, "Didn't receive the line" server.stop()
def test_one_liner(): one_line = 'hello and goodbye!' class SimpleServer(gevent.server.StreamServer): def handle(self, socket, address): socket.sendall(one_line) socket.shutdown(0) server = SimpleServer(('127.0.0.1', 0)) server.start() client = gevent.socket.create_connection(('127.0.0.1', server.server_port)) lines = [line for line in util.line_protocol(client)] assert len(lines) == 1, "Got too many (or not enough) lines" assert lines[0] == one_line, "Didn't get the line expected" server.stop()
def test_multi_lines_rn(): one_line = 'hello and goodbye!' number_lines = 5 class SimpleServer(gevent.server.StreamServer): def handle(self, socket, address): socket.sendall('\r\n'.join([one_line for n in xrange(number_lines)])) socket.shutdown(0) server = SimpleServer(('127.0.0.1', 0)) server.start() client = gevent.socket.create_connection(('127.0.0.1', server.server_port)) lines = [line for line in util.line_protocol(client)] assert len(lines) == number_lines, "Got too many (or not enough) lines" assert lines.pop() == one_line, "Didn't get the line expected" server.stop()
def test_strip_on_lines(): one_line = 'hello and goodbye!\n' number_lines = 5 class SimpleServer(gevent.server.StreamServer): def handle(self, socket, address): socket.sendall(''.join([one_line for n in xrange(number_lines)])) socket.shutdown(0) server = SimpleServer(('127.0.0.1', 0)) server.start() client = gevent.socket.create_connection(('127.0.0.1', server.server_port)) lines = [line for line in util.line_protocol(client)] assert len(lines) == number_lines, "Got too many (or not enough) lines" assert lines.pop() != one_line, "Line includes newlines (or something)" assert lines.pop() == one_line.strip(), "Line doesn't match when stripped" server.stop()
def test_no_strip_on_lines(): one_line = 'hello and goodbye!\n' number_lines = 5 class SimpleServer(gevent.server.StreamServer): def handle(self, socket, address): socket.sendall(''.join([one_line for n in xrange(number_lines)])) socket.sendall('\n') socket.shutdown(0) server = SimpleServer(('127.0.0.1', 0)) server.start() client = gevent.socket.create_connection(('127.0.0.1', server.server_port)) lines = [line for line in util.line_protocol(client, strip=False)] assert len(lines) == number_lines+1, "Got too many (or not enough) lines" assert lines.pop() == '\n', "Didn't get empty line" assert lines.pop() == one_line, "Line doesn't match line with newline" server.stop()
def handle(self, socket, address): """ If not a leader, a node will simply return a single item list pointing to the leader. Otherwise, it will add the host of the connected client to the cluster roster, broadcast to all nodes the new roster, and wait for keepalives. If no keepalive within timeout or the client drops, it drops it from the roster and broadcasts to all remaining nodes. """ if not self.c.is_leader: socket.send( json.dumps({ 'leader': self.c.client.leader, 'port': self.c.port })) socket.close() logger.debug("Redirected to %s:%s" % (self.c.client.leader, self.c.port)) else: socket.send(self._cluster_message()) sockfile = socket.makefile() name = sockfile.readline() if not name: return if name == '\n': name = address[0] else: name = name.strip() logger.debug('New connection from %s' % name) self._update(add={'host': name, 'socket': socket}) # TODO: Use TCP keepalives timeout = self._client_timeout(socket) for line in util.line_protocol(sockfile, strip=False): timeout.kill() timeout = self._client_timeout(socket) socket.send('\n') #logger.debug("Keepalive from %s:%s" % address) #logger.debug("Client disconnected from %s:%s" % address) self._update(remove=name)