Spaces:
Running
Running
import coding | |
import scratchattach as scratch3 | |
import threading | |
import time | |
import random | |
import os | |
global conn | |
global projectid | |
global endpoint | |
global users | |
projectid = os.getenv("ProjectID") | |
users = {} | |
session = scratch3.login(os.getenv("Username"), os.getenv("Password")) | |
class User: | |
def __init__(self, name, id): | |
self.last_request = time.time() | |
self.name = name | |
self.id = id | |
class UserStartup: | |
def __init__(self): | |
self.last_request = time.time() | |
class Responder: | |
def __init__(self, projectid, channel, can_respond, can_stream, value, user): | |
user.last_request = time.time() | |
self.user = user | |
self.projectid = projectid | |
self.can_respond = can_respond | |
self.can_stream = can_stream | |
self.channel = channel | |
self.cooldown = time.time() | |
self.wrote = False | |
self.last_value = value | |
def poll(self): | |
value = scratch3.get_var(self.projectid, "channel "+str(self.channel)) | |
if value != self.last_value and value != None: | |
self.user.last_request = time.time() | |
self.last_value = value | |
binary = coding.decimal_to_binary(int(value)) | |
if binary[1:3]=="01": | |
value = str(coding.binary_to_decimal(binary[3:])) | |
if binary[1:3]=="10": | |
value = str("true" if binary[3:] == 1 else "false") | |
if binary[1:3]=="11": | |
value = coding.convert_to_text(binary[3:]) | |
return value | |
def close(self): | |
if self.can_stream or not self.can_respond: | |
while time.time() - self.cooldown < 0.5: | |
time.sleep(0.5 - (time.time() - self.cooldown)) | |
conn.set_var("channel "+str(self.channel), "0") | |
else: | |
while str(scratch3.get_var(self.projectid, "channel "+str(self.channel))) !="0": | |
pass | |
def respond(self, response): | |
global conn | |
if self.wrote and not self.can_stream: | |
raise Exception("Can't stream to this as a response") | |
if not (self.can_respond or self.can_stream): | |
raise Exception("Can't respond to this") | |
while time.time() - self.cooldown < 0.5: | |
time.sleep(0.5 - (time.time() - self.cooldown)) | |
if self.can_respond or self.can_stream: | |
payload = "1" | |
if type(response) is int: | |
payload+="01"+coding.decimal_to_binary(response) | |
elif type(response) is bool: | |
payload+="10"+"1" if response else "0" | |
elif type(response) is str: | |
payload+="11"+coding.convert_to_binary(response) | |
self.last_value = str(coding.binary_to_decimal(payload)) | |
conn.set_var("channel "+str(self.channel), str(coding.binary_to_decimal(payload))) | |
t= time.time() | |
times=0.2 | |
while scratch3.get_var(self.projectid, "channel "+str(self.channel)) !=str(coding.binary_to_decimal(payload)): | |
if time.time()-t>=times: | |
print("Message not sent, retrying") | |
times+=0.1 | |
conn.set_var("channel "+str(self.channel), str(coding.binary_to_decimal(payload))) | |
t=time.time() | |
self.wrote = True | |
self.cooldown = time.time() | |
class ConnectionEndpoint: | |
def receivedMessage(self, message, user, responder): | |
global users | |
r=random.randrange(1, 2047) | |
while r in users: | |
r=random.randrange(1, 2047) | |
users[r] = User(message, r) | |
responder.respond(r) | |
responder.close() | |
class HeartbeatEndpoint: | |
def receivedMessage(self, message, user, responder): | |
responder.close() | |
def thread(n): | |
global users | |
global conn | |
global projectid | |
global endpoint | |
heartbeater = HeartbeatEndpoint() | |
conn.set_var("channel "+str(n), "0") | |
while True: | |
value = scratch3.get_var(projectid, "channel "+str(n)) | |
if str(value) != "0" and value != None: | |
binary = coding.decimal_to_binary(int(value)) | |
reqendpoint = coding.binary_to_decimal(binary[1:6]) | |
header = coding.binary_to_decimal(binary[6:17]) | |
staticpayload = binary[17] == '1' | |
streamingpayload = binary[18] == '1' | |
acceptstaticpayload = binary[19] == '1' | |
acceptstreamingpayload = binary[20] == '1' | |
payload = None | |
if staticpayload and not streamingpayload: | |
payloadformat = binary[21:23] | |
if payloadformat == "01": | |
payload = str(coding.binary_to_decimal(binary[23:])) | |
if payloadformat == "10": | |
payload = "true" if binary[23:]=='1' else "false" | |
if payloadformat == "11": | |
payload = coding.convert_to_text(binary[23:]) | |
if header in users: | |
user = users[header] | |
else: | |
user = UserStartup() | |
respond = Responder(projectid, n, acceptstaticpayload, acceptstreamingpayload, value, user) | |
if reqendpoint == 31: | |
heartbeater.receivedMessage(payload, user, respond) | |
else: | |
try: | |
endpoint[reqendpoint].receivedMessage(payload, user, respond) | |
except: | |
pass | |
def monitor_users(): | |
global users | |
while True: | |
time.sleep(1) | |
for k, v in users.items(): | |
if time.time() - v.last_request >= 300: | |
del users[k] | |
def start_server(endpoints): | |
global projectid | |
global conn | |
global endpoint | |
endpoints.insert(0, ConnectionEndpoint()) | |
endpoint = endpoints | |
conn = session.connect_cloud(projectid) | |
threads = [threading.Thread(target=thread, args=(i+1,)) for i in range(10)] | |
for t in threads: | |
t.start() | |
monitorusers = threading.Thread(target=monitor_users) | |
monitorusers.start() | |