def main(): nb_connection = 0 Websock.send_esp_state(1) while True: Mesh.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) while True: try: Mesh.socket.bind((c.HOST, c.PORT)) Mesh.socket.listen(5) except socket.error as msg: print_flush("Socket has failed :", msg) time.sleep(0.1) continue break socket_thread = None while True: print_flush("Socket opened, waiting for connection...") conn, addr = Mesh.socket.accept() print_flush("Connection accepted with {0}".format(addr)) if (socket_thread != None): socket_thread.close_socket() print_flush("The previous connection has been closed") socket_thread = Mesh(conn, addr) Mesh.print_mesh_info() socket_thread.start()
def callback(self, ch, method, properties, body): Mesh.consummed += 1 if Mesh.consummed % 100 == 0: #display mesh status each 100 models received Mesh.required_amount = SchedulerState.get_amount() Mesh.print_mesh_info() # uncommment to reduce the amount of frames send during the esp declaration phase # if Mesh.comp < Mesh.required_amount : # print_flush("Not enough pixels on the mesh network to display the model") # return if Websock.should_get_deco(): Listen.deco = json.loads(Websock.get_deco()) b = body.decode('ascii') self.model.set_from_json(b) tmp = Websock.get_esp_state() if tmp != None and eval(tmp) != self.previous_state: Mesh.change_esp_state = True print_flush("tmp != None, tmp = {}".format(tmp)) self.previous_state = eval(tmp) else: Mesh.change_esp_state = False if Mesh.change_esp_state: # A procedure has started (ie AMA.py is launched) and both the mesh network and the serveur have to be ready self.procedures_manager() elif (Mesh.ama == 1): # A procedure is running self.ama_care() elif (Mesh.addressed): # Production mod : all pixels are addressed Mesh.sequence = (Mesh.sequence + 1) % 65536 array = slef.msg.color(self.model._model, Mesh.sequence, Mesh.pixels, Listen.unk) self.mesh_conn.send(array) else: # Temporisation required between the launching of AMA.py and the frist model matching the procedure arrives print_flush("{} : It is not the time to send colors".format( Mesh.consummed))
def run(self, params, expires_at=None): with self.lock: self.model.set_all((0, 0, 0)) self.send_model() users = loads(Websock.get_users())['users'] if (len(users) == 1): self.user = users[0] Websock.set_grantUser(self.user) self.connectionserver = pika.BlockingConnection(self.paramsserver) self.channelserver = self.connectionserver.channel() self.channelserver.exchange_declare(exchange='logs', exchange_type='fanout') result = self.channelserver.queue_declare('', exclusive=True) queue_name = result.method.queue self.channelserver.queue_bind(exchange='logs', queue=queue_name) self.channelserver.basic_consume(queue=queue_name, on_message_callback=self.callback, auto_ack=True) logging.info( 'Waiting for pixel data on queue "{}".'.format(queue_name)) self.channelserver.start_consuming()
def admin_app_quit(user): if is_admin(user): if (SchedulerState.get_current_app()['name'] == "Snap"): Websock.set_grantUser({'id': "turnoff", 'username': "******"}) removed = SchedulerState.stop_forced_app_request(user) return jsonify(removed=removed) else: abort(403, "Forbidden Bru") return '', 204
def update(self): Websock.send_pos_unk(self.pos_unknown) #List of pixels to be addressed default = self.pixels.pop( 'default' ) #As default is a false pixel, it must be removed before sending the array #print_flush(self.pixels) Websock.send_pixels(self.pixels) #list of addressed pixels if default: #if default was removed, it is added again. self.pixels['default'] = default
def reattributing_indexes(self): self.deco = loads( Websock.get_deco()) #retrieves the disconnected cards. for mac in self.pos_unknown.keys(): if len(self.deco) > 0: # dummy security, should do something in the case of it happenning but dunno what (yet) pixel_deco = self.deco.popitem() self.pos_unknown[mac] = ( (-1, -1), pixel_deco[1][1] ) #associate the disconnected card index to the unknown card. self.pixels = loads( Websock.get_pixels()) #retrieves the current pixel list self.pixels['default'] = ((-1, -1), -1) #adds the fake pixel security.
def stop_app(self, c_app, stop_code=None, stop_message=None): # flask_log(" ========= STOP_APP ====================") if not c_app or 'task_id' not in c_app: print_flush('Cannot stop invalid app') return from tasks.celery import app if not c_app.get('is_default', False) and not c_app.get('is_forced', False): if stop_code and stop_message and 'userid' in c_app: Websock.send_data(stop_code, stop_message, c_app['username'], c_app['userid']) app.control.revoke(c_app['task_id'], terminate=True) self.frontage.fade_out() SchedulerState.set_current_app({})
def addressing_procedure(self): iteration = 1 #Unused variable - functionality to be implemented later #AMA/HAR shall continue as long as there are pixels without known position while (len(self.pos_unknown) != 0): if self.action == 1: #the previous pixel has its right position, considering a new one (mac, ((x, y), ind)) = self.pos_unknown.popitem() else: #the previous position was ill initialize, the same card is considered again, and removed from addressed pixel. self.pixels.pop(mac) self.pos_unknown.pop(mac) self.matriceR(ind, iteration) #First, send the position request model Websock.send_ama_model( 0) #Warn the server that the model is in 1D array format #print_flush(self.model) self.coord = ( -1, -1 ) #Reset coordinate in case previous addressing was wrong print_flush("Waiting for user to input coordinates...") #print_flush([(val[0][0],val[0][1]) for val in self.pixels.values()]) #print_flush(self.coord) #The command under generate an array containing all the (x, y) coordinates of addressed card. while ((self.coord in [(val[0][0], val[0][1]) for val in self.pixels.values()])): #Here is where the default pixel is used : is coordinate of (-1, -1) matches with self.coord, so the program can't progress until user specified new coordinate self.send_model() time.sleep(0.05) #print_flush("apr la boucle d'attente active............................................................;") self.pixels[mac] = (self.coord, ind ) #update of the local dictionary self.update() #Update the server dictionnaries self.matriceG(ind) #Send the validation matrix Websock.send_ama_model( 1 ) # Warns the server that the model must be interpreted as a normal 2D array. self.action = 0 #No validation input print_flush("Waiting for user validation...") while (self.action == 0): #wait for the confirmation of the administrator self.send_model() time.sleep(0.05) if self.action == 1: #Action is validated by user print_flush("Input confirmed") iteration += 1 else: # the pixel is reput in the pos_unknown dictionary as its position is false print_flush("Input canceled") self.pos_unknown[mac] = ((x, y), ind)
def __init__(self): clear_all_task() redis.set(SchedulerState.KEY_USERS_Q, '[]') redis.set(SchedulerState.KEY_FORCED_APP, 'False') Websock.set_grantUser({'id': "turnoff", 'username': "******"}) self.frontage = Frontage(SchedulerState.get_rows(), SchedulerState.get_cols()) self.current_app_state = None self.queue = None self.count = 0 self.apps = OrderedDict([(app, globals()[app]('', '')) for app in get_app_names()]) SchedulerState.set_registered_apps(self.apps)
def set_user(user): if (not is_admin(user)): abort(403, "Forbidden Bru") body = request.get_json() id = body['selected_client'] users = (json.loads(Websock.get_users()))['users'] guser = None if (id != "turnoff"): for user in users: if (user['id'] == id): guser = user if (guser == None): return jsonify(success=False, message="No such client") else: guser = {'id': "turnoff", 'username': "******"} Websock.set_grantUser(guser) return jsonify(success=True, message="Client authorized successfully")
def ama_care(self): #Get the new pixel addressed positions tmp = Websock.get_pixels() if tmp != None and tmp != {}: Mesh.pixels = json.loads(tmp) tmp = json.loads(Websock.get_pos_unk()) if tmp != None: Listen.unk = tmp #Get the model format to check tmp = Websock.get_ama_model() if tmp != None: self.ama_check = eval(tmp)['ama'] if self.ama_model(): # send a COLOR frame only if the model match the expected model Mesh.sequence = (Mesh.sequence + 1) % 65536 array = self.msg.color(self.model._model, Mesh.sequence, Mesh.pixels, Listen.unk, self.ama_check) self.mesh_conn.send(array)
def stop_app(self, c_app, stop_code=None, stop_message=None): # flask_log(" ========= STOP_APP ====================") if not c_app or 'task_id' not in c_app: return from tasks.celery import app if not c_app.get('is_default', False) and not c_app.get( 'is_forced', False): if stop_code and stop_message and 'userid' in c_app: Websock.send_data(stop_code, stop_message, c_app['username'], c_app['userid']) sleep(0.1) # revoke(c_app['task_id'], terminate=True, signal='SIGUSR1') # app.control.revoke(c_app['task_id'], terminate=True, signal='SIGUSR1') app.control.revoke(c_app['task_id'], terminate=True) self.frontage.fade_out() sleep(0.05)
def callback(self, ch, method, properties, body): self.consumme += 1 listpixels = loads(body.decode('ascii')) nuser = loads(Websock.get_grantUser()) if (nuser.get('id') is None or nuser.get('id') == "turnoff"): logging.info("Turn off request") self.erase_all() elif nuser['id'] != self.user['id']: self.user = nuser self.erase_all() self.set_rgb_matrix(listpixels['pixels']) else: self.set_rgb_matrix(listpixels['pixels'])
def skip_procedure(self): #Retrieves the previous configuration self.pixels = SchedulerState.get_pixels_dic() #print_flush("Before readressing : {0} - {1}".format(self.pixels, self.pos_unknown)) delete = [key for key in self.pos_unknown ] #retrieves all the mac address of the card to be addressed for key in delete: #Pixel will be matched one on one with those of the Database, according to their mac address. value = self.pos_unknown[key] pixel = self.pixels.get(key) if pixel is None: #No match is found : user shouldn't have use this... unforeseen behaviour may occur from this point on. print_flush("ERROR : using skip is not possible") else: pixel = (pixel[0], value[1] ) #The old index value is replaced with the new one. self.pixels[key] = pixel #the pixel is then updated self.pos_unknown.pop( key ) #Finally, the pixel being addressed, so it's removed for the Unkown list. #print_flush("After readressing : {0} - {1}".format(self.pixels, self.pos_unknown)) #Finally, the dictionnary modifications are notified to the server though the Websocket Websock.send_pos_unk(self.pos_unknown) Websock.send_pixels(self.pixels)
def __init__(self, com): Thread.__init__(self) self.msg = Frame() self.com = com self.count = 0 Websock.send_deco(Listen.deco) Websock.send_pos_unk(Listen.unk) Websock.send_get_deco(False)
def procedures_manager(self): Mesh.ama += 1 if Mesh.ama == 1: #AMA procedure starts print_flush("START AMA") Mesh.addressed = False Mesh.print_mesh_info() array = self.msg.ama(c.AMA_INIT) self.mesh_conn.send(array) elif Mesh.ama == 2: # Ends adressing procedures Mesh.addressed = True Mesh.print_mesh_info() array = self.msg.ama(c.AMA_COLOR) self.mesh_conn.send(array) print_flush("END addressing procedure") else: # HAR procedure starts print_flush("START HAR") Mesh.ama = 1 Mesh.addressed = False Mesh.print_mesh_info() array = self.msg.har(Mesh.mac_root, c.STATE_CONF) self.mesh_conn.send(array) print_flush(Listen.unk.keys(), Listen.deco) # The pixel in deco are one by one being forgotten and their index is attributed to one of the unknown for mac in Listen.unk.keys(): if len(Listen.deco) > 0: pixel_deco = Listen.deco.popitem() print_flush("Adding new element") print_flush(pixel_deco) print_flush("Inserted unknwon card at {0}".format( pixel_deco[1][1])) Listen.unk[mac] = ((-1, -1), pixel_deco[1][1]) array = self.msg.install_from_mac(mac, pixel_deco[1][1]) self.mesh_conn.send(array) Websock.send_pos_unk(Listen.unk) Mesh.print_mesh_info() array = slef.msg.ama(c.AMA_INIT) self.mesh_conn.send(array)
def update_DB(self): if self.pixels.get('default'): #Remove the fake pixel self.pixels.pop('default') #Updates the server dictionnaries Websock.send_pixels(self.pixels) Websock.send_pos_unk({}) Websock.send_deco(self.deco) Websock.send_get_deco() #Update DB if ( self.params['mode'] == 'ama' or self.params['mode'] == 'skip' ): # in case of initial addressing, the previous configuration is first deleted. SchedulerState.drop_dic() print_flush("Database cleaned") while (len(self.pixels) != 0): #Pixels are then added one by one to the database (mac, ((x, y), ind)) = self.pixels.popitem() SchedulerState.add_cell(x, y, mac, ind) print_flush("Database updated")
def run(self, params, expires_at=None): self.start_socket() # get necessary informations self.rows = SchedulerState.get_rows() self.cols = SchedulerState.get_cols() # get the pixels to address self.pos_unknown = loads( Websock.get_pos_unk()) #format {'@mac1' : ((x,j), index), ...}} self.params = params print_flush("Launched AMA app with {0} parameter".format( self.params['mode'])) if (self.params['mode'] == 'ama' ): # assisted manual addressing : reset the position of all pixels Websock.send_pixels({}) elif (self.params['mode'] == 'rac'): # hot assisted readdressing : reattribute the unusued pixel indexes (get from deconnected pixels) without changing already addressed pixels self.deco = loads(Websock.get_deco()) array = [] for key in self.deco.keys( ): #Generate the list of all free cells for the frontend value = self.deco[key] array += [value[0]] self.send_pixel_down(array) #sends this list to the frontend self.reattributing_indexes() #update the dictionnaries #Put esp root in ADDR or CONF state, depending on the current state of the server : indicate start of procedure Websock.send_esp_state(0) if self.params['mode'] == 'skip': self.skip_procedure() sleep(1) else: self.addressing_procedure() #publish on REDIS and save in DB the new pixels dictionary self.update_DB() #Put ESPs in COLOR state Websock.send_esp_state(1) self.visual_verification() self.wait_to_be_kill()
def send_message(self, code): Websock.send_data(code, 'Gamelife message', self.username, self.userid)
def send_game_over(self): Websock.send_data(Fap.CODE_GAME_OVER, 'GAME_OVER', self.username, self.userid)
def send_close_app(self): Websock.send_data(Fap.CODE_CLOSE_APP, 'CLOSING', self.username, self.userid)
class Fap(object): CODE_CLOSE_APP = 1 CODE_GAME_OVER = 2 CODE_EXPIRE = 3 CODE_EXPIRE_SOON = 4 CODE_TETRIS_CLEARED_ROW = 10 CODE_SNAKE_ATE_APPLE = 11 PARAMS_LIST = [] PLAYABLE = False ACTIVATED = True ENABLE = True LOCK = RWLock() LOCK_WS = RWLock() def __init__(self, username, userid): SchedulerState.set_expire_soon(False) self.max_time = None self.params = None self.username = username self.userid = userid self.ws = None self.model = Model(SchedulerState.get_rows(), SchedulerState.get_cols()) credentials = pika.PlainCredentials( environ.get('RABBITMQ_DEFAULT_USER'), environ.get('RABBITMQ_DEFAULT_PASS')) self.connection_params = pika.ConnectionParameters( host='rabbit', credentials=credentials, connection_attempts=100, heartbeat=0) self.connection = pika.BlockingConnection(self.connection_params) ##### Channel used for emiting model to scheduler self.channel = self.connection.channel() self.channel.exchange_declare(exchange='model', exchange_type='fanout') def run(self): raise NotImplementedError("Fap.run() must be overidden") def send_close_app(self): Websock.send_data(Fap.CODE_CLOSE_APP, 'CLOSING', self.username, self.userid) def send_game_over(self): Websock.send_data(Fap.CODE_GAME_OVER, 'GAME_OVER', self.username, self.userid) def send_message(self, code): Websock.send_data(code, 'Gamelife message', self.username, self.userid) @staticmethod def send_expires(username='', userid=''): SchedulerState.set_expire(True) Websock.send_data(Fap.CODE_EXPIRE, 'EXPIRE', username, userid) @staticmethod def send_expires_soon(timeout_in_sec, username='', userid=''): SchedulerState.set_expire_soon(True) Websock.send_data(Fap.CODE_EXPIRE_SOON, timeout_in_sec, username, userid) def start_socket(self): self.ws = Websock(self, '0.0.0.0', 33406) self.ws.start() def flash(self, duration=4., speed=1.5): """ Blocking and self-locking call flashing the current model on and off (mainly for game over) :param duration: Approximate duration of flashing in seconds :param rate: Rate of flashing in Hz """ rate = Rate(speed) t0 = time.time() model_id = 0 # with self._model_lock: models_bck = self.model._model.copy() model_off = False while time.time() - t0 < duration or model_off: # with self._model_lock: if model_id: self.model.set_all('black') else: self.model._model = models_bck.copy() model_id = (model_id + 1) % 2 model_off = not model_off self.send_model() rate.sleep() def send_model(self): if not self.LOCK.acquire_write(2): print('Wait for RWLock for too long in Bufferize...Stopping') return try: self.channel.basic_publish(exchange='model', routing_key='', body=self.model.json()) except Exception as e: print('FAP Cannot send model to scheduler') raise e finally: self.LOCK.release() def jsonify(self): struct = {} struct['name'] = self.__class__.__name__ struct['params'] = self.params struct['params_list'] = self.PARAMS_LIST struct['playable'] = self.PLAYABLE struct['activated'] = self.ACTIVATED struct['max_time'] = self.max_time return struct def close(self): if self.channel is not None: self.channel.close() if self.connection is not None: self.connection.close() if self.ws is not None: self.ws.close() time.sleep(0.2)
def start_socket(self): self.ws = Websock(self, '0.0.0.0', 33406) self.ws.start()
def send_expires(username='', userid=''): SchedulerState.set_expire(True) Websock.send_data(Fap.CODE_EXPIRE, 'EXPIRE', username, userid)
def send_expires_soon(timeout_in_sec, username='', userid=''): SchedulerState.set_expire_soon(True) Websock.send_data(Fap.CODE_EXPIRE_SOON, timeout_in_sec, username, userid)
def get_users(user): if (not is_admin(user)): abort(403, "Forbidden Bru") users = (json.loads(Websock.get_users()))['users'] guser = (json.loads(Websock.get_grantUser())) return jsonify(list_clients=users, selected_client=guser)
def send_pixel_down(self, positions): print_flush("Sending positions to frontend...") #print_flush(positions) Websock.send_data(positions, 'Pixel down message', self.username, self.userid)
def listen(self): data = "" self.count += 1 print_flush("{0} Listening... {1}".format( self.count, time.asctime(time.localtime(time.time())))) # receives 1500 (a wifi frame length) data = self.com.recv(1500) print_flush("\tReceived : {} ({}) (valid ? {})".format( data, len(data), self.msg.is_valid(data))) if (data != "" and self.msg.is_valid(data)): if (data[c.TYPE] == c.ERROR): mac = self.msg.array_to_mac(data[c.DATA + 2:c.DATA + 8]) print_flush("Pixel {0} has encountered a problem {1}".format( mac, data[c.DATA])) if data[c.DATA] == c.ERROR_DECO: # 1) the pixel deconnected has to be removed from the working pixel dictionnary and put in the deconnected pixel one # If the pixel is not adressed it can be removed from the server knowledges if (Mesh.pixels.get(mac) is not None): Listen.deco[mac] = Mesh.pixels.pop(mac) Websock.send_pixels(Mesh.pixels) Websock.send_deco(Listen.deco) elif (Listen.unk.get(mac) is not None): Listen.unk.pop(mac) array = self.msg.error(data, ack=True) print_flush("Add pixel {0} to Listen.deco : {1}".format( mac, Listen.deco)) elif data[c.DATA] == c.ERROR_CO: # 1) the new pixel is deal with along with the informations known about it. # If it has been adressed, it gets to work again without any action from administrator # Else a administrator action is required. In the former case the pixel goes in working pixels dic # In the latter it goes in unknown pixels dic to wait for human intervention if mac in Listen.deco: print_flush("Address is in Listen.deco") Mesh.pixels[mac] = Listen.deco.pop(mac) Websock.send_pixels(Mesh.pixels) Websock.send_deco(Listen.deco) array = self.msg.error(data, ack=True) elif mac in Mesh.pixels: print_flush("Address is in Mesh.pixels") array = self.msg.error(data, ack=True) else: # Raising UNK flag Listen.unk[mac] = ((-1, -1), -1) Websock.send_pos_unk(Listen.unk) array = self.msg.error(data, ack=True, unk=True) elif data[c.DATA] == c.ERROR_ROOT: # 1) a reelection has occured in the mesh network, the new esp root send a frame to declared herself. # The mac_root is updated and the known card number is comparted to the one of the root. Mesh.mac_root = mac nb_card = (data[c.DATA + 1] & 0xF0) >> 4 print_flush("on dit qu'il y a {}".format(nb_card)) # 2) If the error has occured because of the mesh network : the routing table is sent to the newly elected esp root # Else it was due to the sever wich takes the nb_pixels has granted and considered pixels has addressed. if Mesh.comp >= nb_card: self.send_table(data[c.DATA + 1] & 0x0F) else: Mesh.comp = nb_card Mesh.addressed = True array = self.msg.har(Mesh.mac_root, data[c.DATA + 1] & 0x0F) self.com.send(array) return else: print_flush("Unkown message type") print_flush( "Updates Listen.deco {0} \n Updates Listen.unk {1}". format(Listen.deco, Listen.unk)) # 2) Once the ERROR has been managed and informations updated, the esp root is informed of its fate self.com.send(array) print_flush("acquitted") elif (data[c.TYPE] == c.BEACON): # 1) BEACON are only received during configuration phase. The esp declared itself one-by-one. # Along with their declarations, they are stocked in unk dic wich is sent on Reddis at each new esp BEACON. # It is necessary to do so because their is no way to known in advance how many esp will be in the mesh network. mac = self.msg.array_to_mac(data[c.DATA:c.DATA + 6]) print_flush("Pixel {0} is declaring itself".format(mac)) if (Mesh.comp == 0): # The first to declared itself is the esp root Mesh.mac_root = mac if Listen.unk.get(mac) != None: # an ESP is only considered once print_flush("But it has already be declared ") pass Listen.unk[mac] = ((-1, -1), Mesh.comp) Websock.send_pos_unk(Listen.unk) array = self.msg.install(data, Mesh.comp) Mesh.comp += 1 # 2) A INSTALL Frame is sent to the esp root for it to update its routing table and acknoledge the esp first sender self.com.send(array) else: print_flush("received unintersting message...")