Last active
November 29, 2019 14:19
-
-
Save frankgould/88a85d34c61ad961fdd836195ae04448 to your computer and use it in GitHub Desktop.
This is the local rover client's library.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
# rover_libclient.py is the REMOTE socket library and Message class | |
import sys, selectors, json, struct | |
class Message: | |
def __init__(self, selector, sock, addr, name, request): | |
self.selector = selector | |
self.sock = sock | |
self.addr = addr | |
self.name = name | |
self.request = request | |
self._recv_buffer = b"" | |
self._send_buffer = b"" | |
self._jsonheader_len = None | |
self.jsonheader = {} | |
self.recv_string = None | |
self.json_content = {} | |
self._request_queued = False | |
def read(self): | |
try: | |
data = self.sock.recv(1024) # Should be ready to read | |
except BlockingIOError: # Resource temporarily unavailable (errno EWOULDBLOCK) | |
print("libclient BlockingIOError Resource temporarily unavailable") | |
except Exception as e: | |
print("libclient error: self.sock.recv() exception for " + str(e)) | |
pass | |
else: | |
if data: | |
# process protoheader | |
self._recv_buffer += data | |
hdrlen = 2 | |
if len(self._recv_buffer) >= hdrlen: | |
self._jsonheader_len = struct.unpack(">H", self._recv_buffer[:hdrlen])[0] | |
self.recv_string = str(self._recv_buffer[hdrlen:]) | |
self.recv_string = self.recv_string.replace("b","") | |
self.recv_string = self.recv_string.replace("'","") | |
# process jsonheader | |
hdrlen = self._jsonheader_len | |
if len(self._recv_buffer) >= hdrlen: | |
recv_data = self.recv_string[:hdrlen] | |
self.jsonheader = eval(recv_data) | |
for reqhdr in ("content-length","content-encoding",): | |
if reqhdr not in self.jsonheader: | |
raise ValueError(f'Missing required header "{reqhdr}".') | |
# process response | |
content_len = self.jsonheader["content-length"] | |
if len(self.recv_string) >= content_len: | |
recv_data = self.recv_string[-content_len:] | |
self.json_content = eval(recv_data) | |
self._recv_buffer = b"" | |
else: | |
print('Rover Server connection closed.\n') | |
sys.exit(0) | |
def write(self): | |
if not self._request_queued: | |
self.queue_request() | |
events = selectors.EVENT_WRITE | |
self.selector.modify(self.sock, events, data=self) | |
if self._send_buffer: | |
try: | |
# Should be ready to write | |
sent = self.sock.send(self._send_buffer) | |
except BlockingIOError: # Resource temporarily unavailable (errno EWOULDBLOCK) | |
print("BlockingIOError") | |
pass | |
except Exception as e: | |
print(f"error: sending",f"{self.addr}: {repr(e)}",) | |
sys.exit(0) | |
self._send_buffer = self._send_buffer[sent:] | |
events = selectors.EVENT_READ | |
self.selector.modify(self.sock, events, data=self) | |
self._jsonheader_len = None # clear json values for last read | |
self.jsonheader = None | |
self.json_content = {} | |
def broadcast(self): | |
if self._send_buffer: | |
try: | |
# Should be ready to write | |
sent = self.client.send(self._send_buffer) | |
except BlockingIOError: # Resource temporarily unavailable (errno EWOULDBLOCK) | |
print('BlockingIOError occurred and message not sent.') | |
pass | |
self._send_buffer = self._send_buffer[sent:] | |
events = selectors.EVENT_READ | |
self.selector.modify(self.client, events, data=self) | |
def close(self): | |
print("libclient closing connection to", self.addr) | |
try: | |
self.selector.unregister(self.sock) | |
except Exception as e: | |
print(f"error: selector.unregister() exception for",f"{self.addr}: {repr(e)}",) | |
try: | |
self.sock.close() | |
except OSError as e: | |
print(f"error: socket.close() exception for",f"{self.addr}: {repr(e)}",) | |
finally: | |
# Delete reference to socket object for garbage collection | |
self.sock = None | |
def queue_request(self): | |
encoding_type = "utf-8" | |
message_content = self.request | |
json_message = json.dumps(message_content, ensure_ascii=False).encode(encoding_type) | |
json_header = {"content-encoding": encoding_type,"content-length": len(json_message)} | |
json_header_bytes = json.dumps(json_header, ensure_ascii=False).encode(encoding_type) | |
message_header = struct.pack(">H", len(json_header_bytes)) | |
message = message_header + json_header_bytes + json_message | |
self._send_buffer += message | |
self._request_queued = True | |
events = selectors.EVENT_WRITE | |
self.selector.modify(self.sock, events, data=self) | |
def process_events(self, mask): | |
if mask & selectors.EVENT_READ: | |
self.read() | |
if mask & selectors.EVENT_WRITE: | |
self.write() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment