SpaceFaceTemplate / SpaceFace.py
Space-Face's picture
Update SpaceFace.py
4ea9251 verified
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:
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
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:
endpoint[reqendpoint].receivedMessage(payload, user, respond)
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()