Files
mcstatus/mcstatus/protocol/connection.py
2014-09-05 00:03:46 +02:00

117 lines
3.1 KiB
Python

import socket
import struct
class Connection:
def __init__(self):
self.sent = bytearray()
self.received = bytearray()
def read(self, length):
result = self.received[:length]
self.received = self.received[length:]
return result
def write(self, data):
if isinstance(data, str):
data = bytearray(data)
self.sent.extend(data)
def receive(self, data):
if not isinstance(data, bytearray):
data = bytearray(data)
self.received.extend(data)
def remaining(self):
return len(self.received)
def flush(self):
result = self.sent
self.sent = ""
return result
def read_varint(self):
result = 0
for i in range(5):
part = ord(self.read(1))
result |= (part & 0x7F) << 7 * i
if not part & 0x80:
return result
raise IOError("Server sent a varint that was too big!")
def write_varint(self, value):
remaining = value
for i in range(5):
if remaining & ~0x7F == 0:
self.write(struct.pack("!B", remaining))
return
self.write(struct.pack("!B", remaining & 0x7F | 0x80))
remaining >>= 7
raise ValueError("The value %d is too big to send in a varint" % value)
def read_utf(self):
length = self.read_varint()
return self.read(length).decode('utf8')
def write_utf(self, value):
self.write_varint(len(value))
self.write(bytearray(value, 'utf8'))
def read_short(self):
return struct.unpack(">h", self.read(2))[0]
def write_short(self, value):
self.write(struct.pack(">h", value))
def read_ushort(self):
return struct.unpack(">H", self.read(2))[0]
def write_ushort(self, value):
self.write(struct.pack(">H", value))
def read_long(self):
return struct.unpack(">q", self.read(8))[0]
def write_long(self, value):
self.write(struct.pack(">q", value))
def read_ulong(self):
return struct.unpack(">Q", self.read(8))[0]
def write_ulong(self, value):
self.write(struct.pack(">Q", value))
def read_buffer(self):
length = self.read_varint()
result = Connection()
result.receive(self.read(length))
return result
def write_buffer(self, buffer):
data = buffer.flush()
self.write_varint(len(data))
self.write(data)
class TCPSocketConnection(Connection):
def __init__(self, addr):
Connection.__init__(self)
self.socket = socket.create_connection(addr, timeout=10)
def flush(self):
raise TypeError("SocketConnection does not support flush()")
def receive(self, data):
raise TypeError("SocketConnection does not support receive()")
def remaining(self):
raise TypeError("SocketConnection does not support remaining()")
def read(self, length):
result = bytearray()
while len(result) < length:
result.extend(self.socket.recv(length - len(result)))
return result
def write(self, data):
self.socket.send(data)