Passed
Push — master ( a89286...fe5519 )
by Steffen
01:36
created

tw_serverinfo.network   A

Complexity

Total Complexity 9

Size/Duplication

Total Lines 73
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
eloc 40
dl 0
loc 73
ccs 29
cts 29
cp 1
rs 10
c 0
b 0
f 0
wmc 9

2 Methods

Rating   Name   Duplication   Size   Complexity  
A Network.receive_packet() 0 20 5
A Network.send_packet() 0 21 4
1 1
import secrets
2 1
import socket
3
4 1
from tw_serverinfo.models import Server
5 1
from tw_serverinfo.models.game_server import GameServer
6
7
8 1
class Network(object):
9
    # www.teeworlds.com has no AAAA domain record and doesn't support IPv6 only requests
10 1
    PROTOCOL_FAMILY = socket.AF_INET
11
12
    # connection timeout in ms
13 1
    CONNECTION_TIMEOUT = 1000
14
15
    # sleep duration between checking if we received a packet in ms
16 1
    CONNECTION_SLEEP_DURATION = 50
17
18 1
    PACKETS = {
19
        'SERVERBROWSE_GETCOUNT': b'\xff\xff\xff\xffcou2',
20
        'SERVERBROWSE_COUNT': b'\xff\xff\xff\xffsiz2',
21
        'SERVERBROWSE_GETLIST': b'\xff\xff\xff\xffreq2',
22
        'SERVERBROWSE_LIST': b'\xff\xff\xff\xfflis2',
23
        'SERVERBROWSE_GETINFO_64_LEGACY': b'\xff\xff\xff\xfffstd',
24
        'SERVERBROWSE_INFO_64_LEGACY': b'\xff\xff\xff\xffdtsf',
25
        'SERVERBROWSE_GETINFO': b'\xff\xff\xff\xffgie3',
26
        'SERVERBROWSE_INFO': b'\xff\xff\xff\xffinf3',
27
        'SERVERBROWSE_INFO_EXTENDED': b'\xff\xff\xff\xffiext',
28
        'SERVERBROWSE_INFO_EXTENDED_MORE': b'\xff\xff\xff\xffiex+',
29
    }
30
31 1
    @staticmethod
32 1
    def send_packet(sock: socket.socket, data: bytes, server: Server) -> None:
33
        """Generate or reuse a request token  and send the passed data with the request token to the passed socket
34
        Returns the updated server dict with additional token on game server types
35
36
        :type sock: socket.socket
37
        :type data: bytes
38
        :type server: dict
39
        :return:
40
        """
41 1
        if not server.request_token:
42 1
            server.request_token = secrets.token_bytes(nbytes=2)
43
44 1
        packet = b'xe%s\0\0%s' % (server.request_token, data)
45
46 1
        if isinstance(server, GameServer):
47 1
            if not server.token:
48 1
                server.token = secrets.token_bytes(nbytes=1)
49 1
            packet += server.token
50
51 1
        sock.sendto(packet, (server.ip, server.port))
52
53 1
    @staticmethod
54 1
    def receive_packet(sock: socket.socket, servers: list, callback: callable) -> bool:
55
        """Check if we received a packet if yes check for the servers with the ip and port
56
        and pass the server together with the data to the processing function given as a callback
57
58
        :param sock:
59
        :param servers:
60
        :param callback:
61
        :return:
62
        """
63 1
        try:
64 1
            data, addr = sock.recvfrom(2048, 0)
65 1
        except BlockingIOError:
66 1
            return False
67
68 1
        for server in servers:  # type: Server
69 1
            if server.ip == addr[0] and server.port == addr[1]:
70 1
                callback(data, server)
71
72
        return True
73