SpaceFaceTemplate / SpaceFace.py
Space-Face's picture
Update SpaceFace.py
4ea9251 verified
raw
history blame
5.75 kB
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()