async def run_command(msg): if cc.my_state_event[cc.State.TERMINATING].is_set(): return False cc.change_my_state(state=cc.State.COORDINATING) formatted_command = format_command(cmd=msg.data) for module_name, command_key, command_dict in get_all_commands(): if command_key in formatted_command: #if intersect_strings(command_key, formatted_command).get("char_count", 0) >= 2: # test = command_key.split(" ") # try: # answer = set(test).issubset(set(formatted_command)) # except: # traceback.print_exc() # if answer: #actually run the command dprint(command_key) module_function = getattr(sys.modules[module_name], command_dict[Command.FUNCTION]) result = await module_function(msg) if result != False: cc.change_my_state(state=cc.State.LISTENING) return result aprint("I don't know what you mean by \'", msg.data, "\'.") cc.change_my_state(state=cc.State.LISTENING) return False
async def get_voice_input(loop): '''Waits for a line of input from system microphone. Throws an EnvironmentError if no microphone could be setup. ''' if not mic: if not setup_microphone(): raise EnvironmentError try: result_future = asyncio.Future() def threaded_listen(): global mic global r result = None with mic as source: try: audio = r.listen(source, phrase_time_limit=10) result = r.recognize_google(audio) except Exception as ex: dprint(ex) if result: loop.call_soon_threadsafe(result_future.set_result, result) else: loop.call_soon_threadsafe(result_future.set_exception, ValueError) return True listener_thread = threading.Thread(target=threaded_listen) listener_thread.daemon = True listener_thread.start() return await result_future except Exception as ex: dprint(ex) return None
def load_commands(): global command_modules dprint("Loading commands...") command_modules = [] for module_filename in os.listdir(COMMANDS_DIRECTORY): module_name, extension = os.path.splitext(module_filename) if "__init__" in module_name or extension != ".py": continue try: #import module #module = import_module(os.path.join(COMMANDS_DIRECTORY, module_filename)) #spec = util.spec_from_file_location(os.path.splitext(module_filename)[0], os.path.join(COMMANDS_DIRECTORY, module_filename)) #dprint(spec) #mod = util.module_from_spec(spec) #spec.loader.exec_module(mod) #dprint(mod.__name__) #mod = sys.modules[mod.__name__] #collect module's commands mod_path = '.'.join( (os.path.basename(COMMANDS_DIRECTORY), module_name)) mod = sys.modules[mod_path] if mod._commands != None: dprint(mod_path, " commands: ", mod._commands) command_modules.append(mod_path) except Exception as _: traceback.print_exc()
async def update_resources(msg): '''Message header must contain str(Resource.SECTION):section. Message data must contain a dict of resources. Updates the local resources with the given ones. ''' dprint("updating resources from ", msg.sender_mac) propagate = ( cerebratesinfo.get_overmind_mac() == mysysteminfo.get_mac_address()) section = None for header in msg.header: if str(Resource.SECTION) in header: split_header = header.split(':') if len(split_header) <= 1: continue section = split_header[len(split_header) - 1] if section: break if not section: return cc.CLOSE_CONNECTION, "no section supplied in header" for resources in msg.data: #if Overmind receives new information then propagate it to other cerebrates if resource_handler.update_resources( section=section, resources=resources) and propagate: communication.Secretary.broadcast_message( msg=communication.Message("update_resources", ':'.join((str(Resource.SECTION), section)), data=[resources])) return cc.CLOSE_CONNECTION, "resources updated"
async def acknowledge(msg): '''Initiates file and record updating between cerebrates. When a cerebrate comes online it broadcasts to other cerebrates asking for acknowledgment. Only the Overmind responds. ''' #Only respond if local is the Overmind if cerebratesinfo.get_overmind_mac() != mysysteminfo.get_mac_address(): return cc.CLOSE_CONNECTION, cc.FINISHED dprint("acknowledging") #Send a current list of records await communication.Secretary.communicate_message( cerebrate_mac=msg.sender_mac, msg=communication.Message( "update_records", cc.RECIPROCATE, cc.OVERRULE, data=cerebratesinfo.get_cerebrate_records_list())) #Send a current list of resources await _send_all_resources(cerebrate_mac=msg.sender_mac) #Get a current list of their resources await communication.Secretary.communicate_message( cerebrate_mac=msg.sender_mac, msg=communication.Message("send_resources")) #Ensure up-to-date files if msg.data.get("version", None): return await check_version(msg=msg) return cc.CLOSE_CONNECTION, cc.SUCCESS
def update_cerebrate_record(cerebrate_record): '''Overwrites the appropriate cerebrate record with the given record. Creates a new one if the given cerebrate does not exist. Returns False if no MAC is given in record. ''' mac = cerebrate_record.get(Record.MAC, None) if not mac: logging.warning('No MAC address provided in record:') logging.info(''.join(("record: ", str(cerebrate_record)))) return False with shelve.open(CEREBRATE_RECORDS, writeback=True) as db: if not db.get(mac, None): db[mac] = default_dictionary() cerebrate_time = cerebrate_record.get(Record.LASTCONTACT, datetime.datetime(1, 1, 1)) db_time = db[mac].get(Record.LASTCONTACT, datetime.datetime(1, 1, 1)) #print(cerebrate_time, " vs ", db_time) if cerebrate_time >= db_time: #print("Updating '", mac, "' record") dprint("Updating record:") dprint(cerebrate_record) db[mac] = cerebrate_record return True else: dprint("Out of date:") dprint(cerebrate_record) return False return True
async def _designate_overmind(mac): if cerebratesinfo.get_overmind_mac() == mac: return dprint("designating ", mac) cerebratesinfo.designate_overmind(mac=mac) if mac != mysysteminfo.get_mac_address(): '''shouldn't need to ask for acknowledgment, cerebrates are already up to date''' #dprint("asking for acknowledgment") #await communication.Secretary.communicate_message(cerebrate_mac=mac, msg=communication.Message("acknowledge", data={"version": cc.my_version})) else: communication.Secretary.broadcast_message(msg=communication.Message( "update_records", cc.OVERRULE, data=[cerebratesinfo.get_overmind_record()]))
def threaded_listen(): global mic global r result = None with mic as source: try: audio = r.listen(source, phrase_time_limit=10) result = r.recognize_google(audio) except Exception as ex: dprint(ex) if result: loop.call_soon_threadsafe(result_future.set_result, result) else: loop.call_soon_threadsafe(result_future.set_exception, ValueError) return True
async def run_command(msg): '''Given a Message, runs the contained command if possible Returns an action, data pair. ''' if cc.my_state_event[cc.State.TERMINATING].is_set(): return cc.CLOSE_CONNECTION, "cerebrate terminating" formatted_header = command.format_header(header=msg.header) cerebratesinfo.update_cerebrate_contact_time( mac=mysysteminfo.get_mac_address()) for key, _ in commands.items(): if key in formatted_header: dprint("before: ", cerebratesinfo.get_overmind_mac()) result = await commands[key][command.Command.FUNCTION](msg) dprint("after: ", cerebratesinfo.get_overmind_mac()) return result return cc.CLOSE_CONNECTION, "command not recognized"
async def audio_listener(loop): await cc.my_state_event[cc.State.LISTENING].wait() while not cc.my_state_event[cc.State.TERMINATING].is_set(): try: voice_input = await audio.get_voice_input(loop) if not voice_input: continue if not cc.accept_audio_control.is_set(): if not "eddie" in voice_input.lower(): dprint("ignore input") continue voice_input = voice_input.replace('Eddie', '', 1).strip() await command.run_command( msg=communication.Message("cmd", "voice", data=voice_input)) except EnvironmentError: cc.accept_audio_control.clear() except Exception: traceback.print_exc()
async def communicate_message(cerebrate_mac, msg:Message): """Opens a TCP connection with the given cerebrate, provided they are running a Secretary. Returns a cc.SUCCESS if connection and initial write are successful. No guarantee after that. """ #print("Communicating: ", msg.header) dprint(msg.data) result_string = "Fail" try: reader, writer = await Secretary.__initiate_connection(cerebrate_mac=cerebrate_mac) if not reader or not writer: return result_string await Secretary._write_message(writer=writer, msg=msg) asyncio.ensure_future(Secretary.__connection_made(reader=reader, writer=writer)) result_string = cc.SUCCESS except asyncio.TimeoutError: print(cerebrate_mac, " timed out") Secretary._timed_out(mac=cerebrate_mac) return result_string
async def send_update(msg): version = msg.data.get("version", None) if not version: return cc.CLOSE_CONNECTION, "requester's version number not included" if version >= cc.my_version: return cc.CLOSE_CONNECTION, "requester not out of date" requirements.update_requirements() dprint("Sending updates to ", msg.sender_mac) files = await get_cerebrate_file_names() success = await communication.Secretary.transfer_files( cerebrate_mac=msg.sender_mac, file_names=files) if success: await communication.Secretary.communicate_message( cerebrate_mac=msg.sender_mac, msg=communication.Message("restart", data="cerebrate updated")) else: dprint("FAILED TO UPDATE ", msg.sender_mac) return cc.CLOSE_CONNECTION, "failed" return cc.CLOSE_CONNECTION, cc.SUCCESS
async def update_records(msg): '''Message data must contain a list of cerebrate records. Updates the local cerebrate records with the given ones, if the given ones contain more recent information. If CC.RECIPROCATE is in the header a Message containing the local copy of updated cerebrate records will be returned. ''' if cc.OVERRULE in msg.header: dprint("Being overruled") await _designate_overmind(mac=msg.sender_mac) dprint("updating records from ", msg.sender_mac) propagate = ( cerebratesinfo.get_overmind_mac() == mysysteminfo.get_mac_address()) for record in msg.data: #if Overmind receives new information then propagate it to other cerebrates if cerebratesinfo.update_cerebrate_record( cerebrate_record=record) and propagate: communication.Secretary.broadcast_message( msg=communication.Message("update_records", data=[record])) if cc.RECIPROCATE in msg.header: return cc.REMOTE_COMMAND, communication.Message( "update_records", data=cerebratesinfo.get_cerebrate_records_list()) return cc.CLOSE_CONNECTION, "records updated"
def __exit__(self, type, value, traceback): dprint("Finished bypassing lock")
def __enter__(self): dprint("Bypassing lock") return True
async def assume_overmind(msg): '''Sets self as Overmind, broadcasts the change to others. ''' dprint("Assuming Overmind") await _designate_overmind(mac=mysysteminfo.get_mac_address()) return cc.CLOSE_CONNECTION, cc.SUCCESS