Skip to content

Commit

Permalink
Added locks
Browse files Browse the repository at this point in the history
  • Loading branch information
TheCommCraft committed May 8, 2024
1 parent 10e706b commit cc8161b
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 26 deletions.
2 changes: 1 addition & 1 deletion scratchcommunication/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
Module for communicating with scratch projects.
"""

__version_number__ = '2.7.1'
__version_number__ = '2.7.2'

from .session import *
from .cloud import *
Expand Down
92 changes: 68 additions & 24 deletions scratchcommunication/cloud_socket.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from .cloud import CloudConnection
from . import security as sec
from threading import Lock
from typing import Union, Any, Self
import random, time
from itertools import islice
Expand All @@ -18,6 +19,11 @@ def batched(iterable, n):
while batch := tuple(islice(it, n)):
yield batch

class BaseCloudSocketMSG:
"""
Base class for cloud socket messages.
"""

class BaseCloudSocketClient:
"""
Base class for connecting with cloud sockets
Expand Down Expand Up @@ -67,6 +73,15 @@ class BaseCloudSocket:
"""
Base Class for creating cloud sockets with projects
"""
security : sec.RSAKeys
cloud : CloudConnection
clients : dict
new_clients : list
connecting_clients : list
key_parts : dict
last_timestamp : float
packet_size : int
accepting : Lock
def __init__(self, *, cloud : CloudConnection, packet_size : int = 220, security : Union[None, tuple] = None):
raise NotImplementedError

Expand Down Expand Up @@ -100,6 +115,16 @@ class BaseCloudSocketConnection:
"""
Base Class for handling incoming connections from a cloud socket
"""
cloud_socket : BaseCloudSocket
client_id : str
username : str
security : str
encrypter : sec.SymmetricEncryption
secure : bool
new_msgs : list
current_msg : BaseCloudSocketMSG
receiving : Lock
sending : Lock
def __init__(self, *, cloud_socket : BaseCloudSocket, client_id : str, username : str = None, security : str = None):
raise NotImplementedError

Expand Down Expand Up @@ -134,6 +159,7 @@ def __init__(self, *, cloud : CloudConnection, packet_size : int = 220, security
self.key_parts = {}
self.last_timestamp = time.time()
self.packet_size = packet_size
self.accepting = Lock()

def listen(self):
"""
Expand Down Expand Up @@ -251,14 +277,20 @@ def accept(self, timeout : Union[float, None] = 10) -> tuple[BaseCloudSocketConn
"""
Returns a new client
"""
endtime = time.time() + timeout if timeout is not None else None
while (not self.new_clients) and (timeout is None or time.time() < endtime):
pass
try:
new_client = self.new_clients.pop(0)
return new_client
except IndexError:
endtime = (time.time() + timeout) if timeout is not None else None
result = self.accepting.acquire(timeout=timeout if timeout is not None else -1)
if not result:
raise TimeoutError("The timeout expired (consider setting timeout=None)")
try:
while (not self.new_clients) and (timeout is None or time.time() < endtime):
pass
try:
new_client = self.new_clients.pop(0)
return new_client
except IndexError:
raise TimeoutError("The timeout expired (consider setting timeout=None)")
finally:
self.accepting.release()

class CloudSocketConnection(BaseCloudSocketConnection):
"""
Expand All @@ -273,6 +305,8 @@ def __init__(self, *, cloud_socket : BaseCloudSocket, client_id : str, username
self.secure = bool(self.security)
self.new_msgs = []
self.current_msg = CloudSocketMSG()
self.receiving = Lock()
self.sending = Lock()

def __enter__(self):
return self
Expand All @@ -299,31 +333,41 @@ def send(self, data : str):
"""
Use for sending data to the client
"""
if self.secure:
self._secure_send(data)
return
data = str(self.cloud_socket._encode(data))
packets = ["".join(i) for i in batched(data, self.cloud_socket.packet_size)]
packet_idx = 0
for packet in packets[:-1]:
self.cloud_socket.cloud.set_variable(name=f"TO_CLIENT_{random.randint(1, 4)}", value=f"-{packet}.{self.client_id}{packet_idx}")
packet_idx += 1
self.cloud_socket.cloud.set_variable(name=f"TO_CLIENT_{random.randint(1, 4)}", value=f"{packets[-1]}.{self.client_id}{packet_idx}")
with self.sending:
if self.secure:
self._secure_send(data)
return
data = str(self.cloud_socket._encode(data))
packets = ["".join(i) for i in batched(data, self.cloud_socket.packet_size)]
packet_idx = 0
for packet in packets[:-1]:
self.cloud_socket.cloud.set_variable(name=f"TO_CLIENT_{random.randint(1, 4)}", value=f"-{packet}.{self.client_id}{packet_idx}")
packet_idx += 1
self.cloud_socket.cloud.set_variable(name=f"TO_CLIENT_{random.randint(1, 4)}", value=f"{packets[-1]}.{self.client_id}{packet_idx}")

def recv(self, timeout : Union[float, None] = 10) -> str:
"""
Use for receiving data from the client
timeout defaults to 10 (seconds) but can be set to None if you do not want timeout.
"""
endtime = time.time() + timeout if timeout is not None else None
while (not self.new_msgs) and (timeout is None or time.time() < endtime):
pass
try:
return self.new_msgs.pop(0).message
except IndexError:
endtime = (time.time() + timeout) if timeout is not None else None
result = self.receiving.acquire(timeout=timeout if timeout is not None else -1)
if not result:
raise TimeoutError("The timeout expired (consider setting timeout=None)")
try:
while (not self.new_msgs) and (timeout is None or time.time() < endtime):
pass
try:
return self.new_msgs.pop(0).message
except IndexError:
raise TimeoutError("The timeout expired (consider setting timeout=None)")
finally:
self.receiving.release()

class CloudSocketMSG:
class CloudSocketMSG(BaseCloudSocketMSG):
"""
Class for cloud socket messages.
"""
def __init__(self, message : str = "", complete : bool = False):
self.message = message
self.complete = complete
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
with open("README.md", encoding="utf-8") as f:
long_description = f.read()

VERSION = '2.7.1'
VERSION = '2.7.2'

setup(
name='scratchcommunication',
Expand Down

0 comments on commit cc8161b

Please sign in to comment.