mirror of
https://github.com/socialwifi/RouterOS-api.git
synced 2025-08-31 07:09:48 +02:00
85 lines
2.4 KiB
Python
85 lines
2.4 KiB
Python
import socket
|
|
|
|
from routeros_api import exceptions
|
|
|
|
LENGTH_MATRIX = [
|
|
(0x80, 0x0),
|
|
(0x40, 0x80),
|
|
(0x20, 0xC0),
|
|
(0x10, 0xE0),
|
|
(0x1, 0xF0),
|
|
]
|
|
|
|
OVER_MAX_LENGTH_MASK = 0xF8
|
|
|
|
|
|
class Connection(object):
|
|
def __init__(self, socket):
|
|
self.socket = socket
|
|
|
|
def send_sentence(self, words):
|
|
try:
|
|
for word in words + [b'']:
|
|
full_word = encode_length(len(word)) + word
|
|
self.socket.send(full_word)
|
|
except socket.error as e:
|
|
raise exceptions.RouterOsApiConnectionError(str(e))
|
|
|
|
def receive_sentence(self):
|
|
try:
|
|
return list(iter(self.receive_word, b''))
|
|
except socket.error as e:
|
|
raise exceptions.RouterOsApiConnectionError(str(e))
|
|
|
|
def receive_word(self):
|
|
result = []
|
|
result_length = 0
|
|
expected_length = decode_length(self.socket.receive)
|
|
while result_length != expected_length:
|
|
received = self.socket.receive(expected_length - result_length)
|
|
result.append(received)
|
|
result_length += len(received)
|
|
assert result_length <= expected_length
|
|
return b''.join(result)
|
|
|
|
|
|
def encode_length(length):
|
|
data, number_of_bytes = _encode_length(length)
|
|
return to_bytes(data, number_of_bytes)
|
|
|
|
|
|
def _encode_length(length):
|
|
if length < 0:
|
|
raise exceptions.FatalRouterOsApiError("Negative length.")
|
|
|
|
for bytes, (max_value, mask) in enumerate(LENGTH_MATRIX):
|
|
offset = 8 * bytes
|
|
if length < (max_value << offset):
|
|
return length | (mask << offset), bytes + 1
|
|
raise exceptions.FatalRouterOsApiError("String to long.")
|
|
|
|
|
|
def to_bytes(number, length):
|
|
if hasattr(number, 'to_bytes'):
|
|
return number.to_bytes(length, 'big')
|
|
else:
|
|
result = []
|
|
for byte in reversed(range(length)):
|
|
result.append(chr((number >> (8 * byte)) & 0xff))
|
|
return b''.join(result)
|
|
|
|
|
|
def decode_length(read):
|
|
first = ord(read(1))
|
|
masks = tuple(zip(*LENGTH_MATRIX))[1]
|
|
mask_with_next = zip(masks, masks[1:] + (OVER_MAX_LENGTH_MASK,))
|
|
for bytes, (mask, next_mask) in enumerate(mask_with_next):
|
|
if next_mask & first == mask:
|
|
result = first & ~next_mask
|
|
break
|
|
else:
|
|
raise exceptions.FatalRouterOsApiError("Malformed length")
|
|
for _ in range(bytes):
|
|
result <<= 8
|
|
result += ord(read(1))
|
|
return result
|