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