master.py 3.75 KB
Newer Older
m!nus's avatar
m!nus committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
import time
import logging
logging.basicConfig(format="[%(asctime)s] %(levelname)s: %(funcName)s: %(message)s", level=logging.DEBUG)
L = logging.getLogger(__name__)

from .base import *
from .server import *

class MasterServer(object):

	class Count(Request):
		packet_count_request = 10*b'\xff' + b'cou2'
		packet_count_response = 10*b'\xff' + b'siz2'

		def __init__(self, address, data_cb):
			self.address = address
			self.time_sent = None
			self.latency = None
			self.data_cb = data_cb

		def get_data(self):
			return self.packet_count_request

		def sent(self):
			self.time_sent = time()

		def response_received(self, data):
			if len(data) <= len(self.packet_count_response) or not data.startswith(self.packet_count_response):
				return True # that's not it, wait for more
			self.latency = time() - self.time_sent
			L.debug("received count response from {} in {} seconds".format(self.get_address(), self.latency))
			self.data_cb(data[len(self.packet_count_response):])

	class List(Request):
		packet_list_request = 10*b'\xff' + b'req2'
		packet_list_response = 10*b'\xff' + b'lis2'
		serveraddr_size = 18

		def __init__(self, address, data_cb):
			self.address = address
			self.time_sent = None
			self.latency = None
			self.data_cb = data_cb

		def get_data(self):
			return self.packet_list_request

		def sent(self):
			self.time_sent = time()

		def response_received(self, data):
			if len(data) <= len(self.packet_list_response) or not data.startswith(self.packet_list_response):
				return True # that's not it, wait for more
			self.latency = time() - self.time_sent
			L.debug("received list response from {} in {} seconds".format(self.get_address(), self.latency))
			self.data_cb(data[len(self.packet_list_response):])
			return True # needs more data - eventually

	def __init__(self, socket, address, name=None):
		self._socket = socket
61
		self.address = address
m!nus's avatar
m!nus committed
62 63 64 65
		self.name = name or "None"
		self.latency = None
		self.serverlist = []
		self.count = None
66 67
		self._request_count = self.Count(self.address, self._count_response)
		self._request_list = self.List(self.address, self.add_from_serverlist)
m!nus's avatar
m!nus committed
68 69

	def request_list(self):
70
		self.on_list_request(self._request_list)
m!nus's avatar
m!nus committed
71 72 73
		self._socket.send(self._request_list)

	def request_count(self):
74
		self.on_count_receive(self._request_count)
m!nus's avatar
m!nus committed
75 76 77 78 79 80 81 82
		self._socket.send(self._request_count)

	def add_from_serverlist(self, data):
		"""
		Add servers from a binary list as received from master servers
		"""
		if len(data) % self.List.serveraddr_size != 0:
			L.warning("Serverlist data length is not a multiple of {}".format(self.List.serveraddr_size))
83 84
		for address in listdata2addresslist(data):
			server = Server(self._socket, address, master=self)
m!nus's avatar
m!nus committed
85 86 87 88 89
			self.serverlist.append(server)
			self.on_server_add(server)

	def _count_response(self, data):
		self.count = unpack('!H', data[0:2])[0]
90
		self.on_count_receive(self.count)
m!nus's avatar
m!nus committed
91 92
		L.debug("Count: {}".format(self.count))

m!nus's avatar
m!nus committed
93
	def __str__(self):
m!nus's avatar
m!nus committed
94
		return "<MasterServer name='{name}' address='{address}' servers='{server_count}'>".format(name=self.name, address=self.address, server_count=len(self.serverlist))
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123

	"""
	Events

	replace with your own code or subclass
	Example: master.on_server_add = lambda server: server.request_info()
	"""

	def on_server_add(self, server):
		"""a new server was added by add_to_serverlist"""
		pass

	def on_list_request(self, request):
		"""server list request is about to be send, last change to modify it"""
		pass

	def on_list_receive(self, partial_list):
		"""a part of the server list has been received
		partial_list is the binary payload (not including the header)
		"""
		pass

	def on_count_request(self, request):
		"""server count request is about to be send, last change to modify it"""
		pass

	def on_count_receive(self, count):
		"""server count has been received"""
		pass