summaryrefslogtreecommitdiff
path: root/net/common.py
blob: a589b4454beb4301f473c62d92d09a19b0c8b322 (plain) (blame)
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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
import time
import socket
import asyncore
from logging import DEBUG
from construct import Struct, ULInt16, String, Enum, Byte
from dispatcher import dispatch
from loggers import netlog


def StringZ(name, length, **kw):
    kw['padchar'] = "\x00"
    kw['paddir'] = "right"
    return String(name, length, **kw)


def Gender(name):
    return Enum(Byte(name), BOY=1, GIRL=0, UNSPECIFIED=2, OTHER=3)


class SocketWrapper(asyncore.dispatcher_with_send):
    """
    socket wrapper with file-like read() and write() methods
    """
    def __init__(self, host=None, port=0,
                 protodef={}, onerror=None, sock=None):
        asyncore.dispatcher_with_send.__init__(self, sock)
        self.read_buffer = ''
        if sock is None:
            self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
            self.socket.setblocking(1)
            self.socket.settimeout(0.7)

        self.protodef = protodef
        self.raw = False
        self.onerror = onerror
        if protodef == {}:
            netlog.warning("protodef is empty")
        if host is not None:
            self.connect((host, port))

    def handle_read(self):
        try:
            self.read_buffer += self.recv(2)
        except socket.error:
            return
        while len(self.read_buffer) > 0:
            dispatch(self, self.protodef)

    def handle_error(self):
        if self.onerror is not None:
            self.onerror()
        else:
            raise

    def read(self, n=-1):
        data = ''
        if n < 0:
            data = self.read_buffer
            self.read_buffer = ''
        else:
            tries = 0
            while len(self.read_buffer) < n:
                try:
                    self.read_buffer += self.recv(n - len(self.read_buffer))
                except socket.error as e:
                    tries += 1
                    if tries < 10:
                        netlog.error("socket.error %s", e)
                        time.sleep(0.2)
                    else:
                        raise

            data = self.read_buffer[:n]
            self.read_buffer = self.read_buffer[n:]

        if netlog.isEnabledFor(DEBUG):
            netlog.debug("read  " +
                         ":".join("{:02x}".format(ord(c)) for c in data))
        return data

    def write(self, data):
        if netlog.isEnabledFor(DEBUG):
            netlog.debug("write " +
                         ":".join("{:02x}".format(ord(c)) for c in data))
        if self.raw:
            self.socket.sendall(data)
        else:
            self.send(data)


def send_packet(srv, opcode_, *fields):
    class C:
        opcode = opcode_

    ms = [ULInt16("opcode")]

    for macro, value in fields:
        setattr(C, macro.name, value)
        ms.append(macro)

    d = Struct("packet", *ms)
    d.build_stream(C, srv)


def distance(x1, y1, x2, y2):
    return max(abs(x2 - x1), abs(y2 - y1))