Compare commits

..

No commits in common. "80fb8cd7cc328767a45cf87da39d1954662b2800" and "a8d9afe3d19512e478c83e0b206ceb2b95beb765" have entirely different histories.

3 changed files with 62 additions and 99 deletions

View File

@ -1,12 +1,8 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import queue
import select
import socket import socket
import ssl import ssl
import threading
from . import messages
class Connection: class Connection:
""" """
@ -26,11 +22,9 @@ class Connection:
self._host = host self._host = host
self._port = port self._port = port
self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self._recv_buffer = b""
self._seq = 0 # state of the sequence number generator self._socket.settimeout(3)
self._requests = {} # waiting area for pending responses
self._close = False
def connect(self): def connect(self):
""" """
@ -38,104 +32,51 @@ class Connection:
""" """
self._socket.connect((self._host, self._port)) self._socket.connect((self._host, self._port))
self._socket.setblocking(False)
threading.Thread(target=self._receive_loop, daemon=True).start() def send(self, message):
def _receive_loop(self):
""" """
Receives messages from socket and associates them to the responding request Sends message string
This function is intended to be executed in thread. :param message: Message string
""" """
recv_buffer = b""
while not self._close:
if select.select([self._socket], [], []) != ([], [], []):
# wait for data availiable
while True:
# fill buffer with one message
data = self._socket.recv(1024)
if not data:
# buffer is empty
break
recv_buffer += data
if b"\0" in recv_buffer:
# there is a full message in buffer, handle that first
break
if b"\0" not in recv_buffer:
# no new messages
break
# get one message from recv_buffer
message, buffer = recv_buffer.split(b"\0", 1)
recv_buffer = buffer
# parse the message
message = message.decode("utf-8")
response = messages.parse(message)
if response.seq in self._requests:
# if this response belongs to a request, we return it and resolve the lock
self._requests[response.seq]["response"] = response
self._requests[response.seq]["event"].set()
# else the message will be ignored
def _generate_seq(self):
"""
Returns new sequence number
This generates a number that tries to be unique during a session
"""
seq = self._seq
self._seq += 1
return seq
def request(self, request):
"""
Sends a request, waits for response and return response
:param request: Request object
Usage::
>>> r = c.request(mitel_ommclient2.messages.Ping())
>>> r.name
'PingResp'
"""
# generate new sequence number and attach to request
seq = self._generate_seq()
request.seq = seq
# add request to waiting area
self._requests[seq] = {
"event": threading.Event(),
}
# send request
message = messages.construct(request)
self._socket.send(message.encode("utf-8") + b"\0") self._socket.send(message.encode("utf-8") + b"\0")
# wait for response def recv(self):
self._requests[seq]["event"].wait() """
Returns one message
# return reponse and remove from waiting area Use multiple times to receive multiple messages
return self._requests.pop(seq, {"response": None})["response"] """
data = b""
while True:
try:
new_data = self._socket.recv(1024)
except TimeoutError:
break
data += new_data
if b"\0" in new_data:
break
self._recv_buffer += data
if b"\0" not in self._recv_buffer:
# no new messages
return None
message, buffer = self._recv_buffer.split(b"\0", 1)
self._recv_buffer = buffer
return message.decode("utf-8")
def close(self): def close(self):
""" """
Shut down connection Shout down connection
""" """
self._close = True
return self._socket.close() return self._socket.close()
def __del__(self): def __del__(self):

View File

@ -28,10 +28,6 @@ class Request:
def seq(self): def seq(self):
return self.attrs.get("seq") return self.attrs.get("seq")
@seq.setter
def seq(self, seq):
self.attrs["seq"] = seq
class DictRequest(Request): class DictRequest(Request):
""" """
@ -83,7 +79,7 @@ class Response:
@property @property
def seq(self): def seq(self):
return int(self.attrs.get("seq")) return self.attrs.get("seq")
@property @property
def errCode(self): def errCode(self):

View File

@ -35,6 +35,17 @@ class Session:
self._ensure_connection() self._ensure_connection()
def _wait_for_respose(self):
"""
Wait until data got received and return message string
"""
while True:
r = self._connection.recv()
if r is not None:
return r
sleep(0.1)
def _ensure_connection(self): def _ensure_connection(self):
""" """
Make sure we are connected and logged in Make sure we are connected and logged in
@ -54,4 +65,19 @@ class Session:
r.raise_on_error() r.raise_on_error()
def request(self, request): def request(self, request):
return self._connection.request(request) """
Sends a request and waits for response
:param request: Request object
Usage::
>>> r = s.request(mitel_ommclient2.messages.Ping())
>>> r.name
'PingResp'
"""
message = messages.construct(request)
self._connection.send(message)
res = self._wait_for_respose()
return messages.parse(res)