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))
|