def run(self, context: typings.Context, args: list): player_model = context["models"]["Player"] player_view = context["views"]["player"] player_count = self.pop_arg(args) if player_count and player_count.isdigit(): total_created = self.create_multiples(player_count, player_model) return player_view.render_multiples(total_created, title="Created Players") questions = { "first_name": text( message="Enter the first name of the player:", validate=validators.TextValidator(), default=f'{self._generate_fake("first_name")}', ), "last_name": text( message="Enter the last name of the player:", validate=validators.TextValidator(), default=f'{self._generate_fake("last_name")}', ), "birthday": text( message="Enter the birthday of the player:", validate=validators.DateValidator(), default=f'{self._generate_fake("birthday")}', ), "sexe": select( message="Enter the sexe of the player:", choices=["Male", "Female"], default=f'{self._generate_fake("sexe")}', ), "rank": text( message="Enter the rank of the player:", validate=validators.DigitValidator(), default=f'{self._generate_fake("rank")}', ), } result = {} for key, value in questions.items(): sanitize_value = type(getattr(player_model(), key)) try: result[key] = sanitize_value(value.execute()) except KeyboardInterrupt: raise errors.GenericError("Canceld the creation of the player", title="Note") new_player = player_model(**result) new_player = new_player.save() player_view.render_single(new_player, title="Created Player")
def config_set(name, option): if type(option) is str: choice = inquirer.text( message= f"{Localizer.get_localized_text('prints','config_modification','set_prompt')} {name} (expecting str)", default=str(option), validate=lambda result: not result.isdigit(), filter=lambda result: str(result)) choice = choice.execute() return choice if type(option) is int: choice = inquirer.text( message= f"{Localizer.get_localized_text('prints','config_modification','set_prompt')} {name} (expecting int)", default=str(option), validate=lambda result: result.isdigit(), filter=lambda result: int(result)) choice = choice.execute() return choice if type(option) is bool: choice = inquirer.select( message= f"{Localizer.get_localized_text('prints','config_modification','set_prompt')} {name}", default=option, choices=[{ "name": "true", "value": True }, { "name": "false", "value": False }], pointer=">") choice = choice.execute() return choice if type(option) is list: current = option[0] options = option[1] choice = inquirer.select( message= f"{Localizer.get_localized_text('prints','config_modification','set_prompt')} {name}", default=current, choices={option: option for option in options}, pointer=">") choice = choice.execute() option[0] = choice return option
def input( text: str, default: str = "", mandatory: bool = False, validate: InquirerPyValidate = None, invalid_message: str = "", ): kwargs = {} if mandatory: kwargs.update({ "validate": lambda result: len(result) > 0, "invalid_message": "Input cannot be empty.", }) if validate and invalid_message: kwargs.update({ "validate": validate, "invalid_message": invalid_message }) result = inquirer.text(text, default=default, style=INQUIRER_STYLE, mandatory=mandatory, amark="✔", **kwargs).execute() return result
def spend_resource(database): faction_name = iq.select( message="Faction name:", choices=factionCrud.get_faction_names(database)).execute() resource = iq.select(message="Resource type:", choices=resource_types).execute() amount = int(iq.text("Amount spent:").execute()) factionCrud.spend_resource(database, faction_name, resource, amount)
def update_resource(database): faction_name = iq.select( message="Faction name:", choices=factionCrud.get_faction_names(database)).execute() resource = iq.select(message="Resource type:", choices=resource_types).execute() new_total = int(iq.text("New total:").execute()) factionCrud.set_resource(database, faction_name, resource, new_total)
def damage_planet(database): planet_name = promptUtils.planet_prompt(database) amount_to_reduce = int(iq.text("Garrison points lost:").execute()) if amount_to_reduce is None: planetCrud.reduce_garrison_points(database, planet_name) else: planetCrud.reduce_garrison_points(database, planet_name, int(amount_to_reduce))
def generate_factions(database): factions_file = "game_resources/factions.json" use_default_path = iq.confirm( "Use default path? (game_resources/factions.json)").execute() if not use_default_path: factions_file = iq.text("Factions file location:").execute() with open(factions_file) as f: factions_from_file = json.load(f)['factions'] factionCrud.build_factions(database, factions_from_file)
def update_all_resources(database): do_update_all_factions = iq.confirm("Update all factions?").execute() faction_name = None if not do_update_all_factions: faction_name = iq.text("Faction name:").execute() factions = list(map(lambda fac: fac.faction_name, factionCrud.get_factions(database)))\ if faction_name is None\ else [faction_name] for faction in factions: factionCrud.update_resources(database, faction)
def main(): """Alternate syntax example.""" name = inquirer.text(message="Enter your name:").execute() company = inquirer.text( message="Which company would you like to apply:", completer={ "Google": None, "Facebook": None, "Amazon": None, "Netflix": None, "Apple": None, "Microsoft": None, }, multicolumn_complete=True, ).execute() salary = inquirer.text( message="What's your salary expectation(k):", transformer=lambda result: "%sk" % result, filter=lambda result: int(result) * 1000, validate=NumberValidator(), ).execute()
def upgrade_facility(database): facility_id = iq.text("Facility id:").execute() is_blockaded = iq.confirm("Blockaded?").execute() facilityCrud.upgrade_facility(database, facility_id) if not is_blockaded: planet_name = facilityCrud.query_facility_by_id( database, facility_id).first().planet planetCrud.restore_garrison_points(database, planet_name) facilityCrud.restore_planet_facilities(database, planet_name)
def update_research(database): faction_name = iq.select( message="Faction name:", choices=factionCrud.get_faction_names(database)).execute() module_name = iq.select(message="Module name:", choices=module_types).execute() tech_level = int( iq.text( message="Tech level:", validate=lambda level: 0 < int(level) < 10, invalid_message="Research has a maximum of 10.", ).execute()) factionCrud.set_research(database, faction_name, module_name, tech_level)
def generate_planets(database): planets_file_path = "game_resources/planets.json" use_default_path = iq.confirm( f"Use default path? ({planets_file_path})").execute() if not use_default_path: planets_file_path = iq.text("Planets file location:").execute() errors = planetUtils.validate_planets_file(planets_file_path) if len(errors) > 0: return print('\n'.join(errors)) with open(planets_file_path) as f: planets_from_file = json.load(f)['planets'] try: planetCrud.build_map(database, planets_from_file) # TODO better exception handling except Exception: print("Could not generate map.")
def changeHostname(ctx: click.Context, hostname: str): click.secho('Changing device\'s hostname', fg='yellow') if not hostname: hostname = inquirer.text(message='Enter new device name', default='ProjectAlice', validate=lambda name: commons. validateHostname(name) is not None).execute() commons.waitAnimation() commons.sshCmd(f"sudo hostnamectl set-hostname '{hostname}'") ctx.invoke(reboot, ctx, return_to_main_menu=False) commons.waitAnimation() stdout, stderr = commons.sshCmdWithReturn('hostname') if stdout.readline().lower().strip() == hostname.lower().strip(): commons.printSuccess('Device name changed!') else: commons.printError('Failed changing device name...') commons.returnToMainMenu(ctx, pause=True)
from InquirerPy import inquirer from InquirerPy.validator import NumberValidator age = inquirer.text( message="Enter your age:", validate=NumberValidator(), default="18", filter=lambda result: int(result), transformer=lambda result: "Adult" if int(result) >= 18 else "Youth", ).execute() drinks = ["Soda", "Cidr", "Water", "Milk"] if age < 18 else ["Wine", "Beer"] drink = inquirer.rawlist(message="What drinks would you like to buy:", default=2, choices=drinks).execute() if drink in {"Wine", "Beer"}: bag = inquirer.select(message="Would you like a bag:", choices=["Yes", "No"]).execute() confirm = inquirer.confirm(message="Confirm?", default=True).execute()
def run(self, context: typings.Context, args: list): tournament_model = context["models"]["Tournament"] tournament_view = context["views"]["tournament"] players = context["models"]["Player"].find_many() has_min_players = lambda players: len(players) >= 8 if not has_min_players(players): raise errors.GenericError( "Cannot create a tournament without at least 8 players created !" ) questions = { "name": text( message="Enter the name of the tournament:", validate=validators.TextValidator(), default=f'{self._generate_fake("name")}', ), "location": text( message="Enter the location of the tournament:", validate=lambda text: len(text) > 0, default=f'{self._generate_fake("location")}', ), "date": text( message="Enter date of the tournament:", validate=validators.DateValidator(), default=f'{self._generate_fake("date")}', ), "rounds": text( message="Enter the rounds of the tournament:", validate=validators.DigitValidator(), default="4", ), "players": select( message="Select the participants:", choices=[{ "name": f"{p.full_name}", "value": p } for p in players], instruction= "> use Spacebar to select, and Enter to exit the selection", validate=lambda players: has_min_players(players) and len( players) % 2 == 0 and len(players), invalid_message= "Cannot select less than 8 players OR odd players", multiselect=True, transformer=lambda result: "%s player%s selected" % (len(result), "s" if len(result) > 1 else ""), ), "time_control": select( message="Time control of the Tournament:", choices=["blitz", "bullet"], default="blitz", ), "desc": text( message="Description:", default="None", ), } result = {} for key, value in questions.items(): sanitize_value = type(getattr(tournament_model(), key)) try: result[key] = sanitize_value(value.execute()) except KeyboardInterrupt: raise errors.GenericError( "Canceld the creation of the tournament", title="Note") new_tournament = tournament_model(**result) new_tournament = new_tournament.save() tournament_view.render_single(new_tournament, title="Created Tournament", hint=True)
Thread(target=_req_handler, daemon=True).start() while (True): if (len(clis) == 0): continue op_info = clis[0] print(op_info) user = UserSettingsSchema().load(op_info) allow_user = inquirer.text( message= f'\nThe user "{user.username}" is requesting to join, accept request?', validate=lambda text: text.lower() in ['y', 'yes', 'n', 'no'], invalid_message='Please answer with a yes or no (y/n)').execute() if (allow_user.lower() in ['yes', 'y']): oponent = user sock.send_str('accepted', user.private_topic) break else: sock.send_str('declined', user.private_topic) print(f'The user "{user.username}" is declined ...') print('\rWaiting for a user to connect ...', end='') del clis[0]
def log_room_desc(command=""): logger.add_log(dungeon.rooms[tuple(player.position)].description, command) # endregion abilities = create_abilities() dungeon = None # dungeon = dungeon_gen(abilities, dungeon_difficulty=dungeon_difficulty, # dungeon_size=dungeon_size) while True: user_input = inquirer.text( message="What's your name:\n", validate=lambda text: len(text) > 0, invalid_message="name cannot be empty.", ).execute() greetMassage = "Hello Brave " name = user_input if name != "": if name.lower() == "quit" or name.lower() == "exit": quit() _player = fetch_player(name=name) if _player: logger.add_log(f"welcome back Brave {name}") player = _player json_dungeon = fetch_dungeon(player) if json_dungeon: dungeon = load_save_or_new_game() break
def restore_ship(database): ship_id = iq.text("Ship id:").execute() shipCrud.restore_ship_hp(database, ship_id)
def installAlice(ctx: click.Context, force: bool): click.secho('\nInstalling Alice!', fg='yellow') result = sshCmdWithReturn('test -d ~/ProjectAlice/ && echo "1"')[0].readline() if result: if not force: commons.printError('Alice seems to already exist on that host') confirm = inquirer.confirm( message='Erase and reinstall?', default=False ).execute() if confirm: commons.returnToMainMenu(ctx) return sshCmd('sudo systemctl stop ProjectAlice') sshCmd('sudo rm -rf ~/ProjectAlice') adminPinCode = inquirer.secret( message='Enter an admin pin code. It must be made of 4 characters, all digits only. (default: 1234)', default='1234', validate=lambda code: code.isdigit() and int(code) < 10000, invalid_message='Pin must be 4 numbers', transformer=lambda _: commons.HIDDEN ).execute() mqttHost = inquirer.text( message='Mqtt hostname', default='localhost', validate=EmptyInputValidator(commons.NO_EMPTY) ).execute() mqttPort = inquirer.number( message='Mqtt port', default=1883, validate=EmptyInputValidator(commons.NO_EMPTY) ).execute() activeLanguage = inquirer.select( message='What language should Alice be using?', default='en', choices=[ Choice('en', name='English'), Choice('de', name='German'), Choice('fr', name='French'), Choice('it', name='Italian'), Choice('pl', name='Polish'), ] ).execute() activeCountryCode = inquirer.select( message='Enter the country code to use.', default='EN', choices=commons.COUNTRY_CODES ).execute() releaseType = inquirer.select( message='What releases do you want to receive? If you are unsure, leave this to Stable releases!', default='master', choices=[ Choice('master', name='Stable releases'), Choice('rc', name='Release candidates'), Choice('beta', name='Beta releases'), Choice('alpha', name='Alpha releases') ] ).execute() audioDevice = inquirer.select( message='Select your audio hardware if listed', default='respeaker2', choices=[ Choice('respeaker2', name='Respeaker 2 mics'), Choice('respeaker4', name='Respeaker 4 mic array'), Choice('respeaker4MicLinear', name='Respeaker 4 mic linear array'), Choice('respeaker6', name='Respeaker 6 mic array'), Choice('respeaker7', name='Respeaker 7'), Choice('respeakerCoreV2', name='Respeaker Core version 2'), Choice('googleAIY', name='Google AIY'), Choice('googleAIY2', name='Google AIY 2'), Choice('matrixCreator', name='Matrix Creator'), Choice('matrixVoice', name='Matrix Voice'), Choice('ps3eye', name='PS3 Eye'), Choice('jabra410', name='Jabra 410'), Choice(None) ] ).execute() soundInstalled = inquirer.confirm( message='Did you already install your sound hardware using Alice CLI or confirmed it to be working?', default=False ).execute() installHLC = inquirer.confirm( message='Do you want to install HLC? HLC can pilot leds such as the ones on Respeakers to provide visual feedback.', default=False ).execute() advancedConfigs = inquirer.confirm( message='Do you want to set more advanced configs? If you do, DO NOT ABORT IN THE MIDDLE!', default=False ).execute() asr = 'coqui' tts = 'pico' awsAccessKey = '' awsSecretKey = '' googleServiceFile = '' shortReplies = False devMode = False githubUsername = '' githubToken = '' enableDataStoring = True skillAutoUpdate = True if advancedConfigs: asr = inquirer.select( message='Select the ASR engine you want to use', default='coqui', choices=[ Choice('coqui', name='Coqui'), Choice('snips', name='Snips (English only!)'), Choice('google', name='Google (Online!)'), Choice('deepspeech', name='Deepspeech'), Choice('pocketsphinx', name='PocketSphinx') ] ).execute() tts = inquirer.select( message='Select the TTS engine you want to use', default='pico', choices=[ Choice('pico', name='Coqui'), Choice('mycroft', name='Mycroft'), Choice('amazon', name='Amazon'), Choice('google', name='Google'), Choice('watson', name='Watson') ] ).execute() if tts == 'amazon': awsAccessKey = inquirer.secret( message='Enter your AWS access key', validate=EmptyInputValidator(commons.NO_EMPTY), transformer=lambda _: commons.HIDDEN ).execute() awsSecretKey = inquirer.secret( message='Enter your AWS secret key', validate=EmptyInputValidator(commons.NO_EMPTY), transformer=lambda _: commons.HIDDEN ).execute() if tts == 'google' or asr == 'google': googleServiceFile = inquirer.filepath( message='Enter your Google service file path', default='~/', validate=PathValidator(is_file=True, message='Input is not a file') ).execute() shortReplies = inquirer.confirm( message='Do you want Alice to use short replies?', default=False ).execute() devMode = inquirer.confirm( message='Do you want to activate the developer mode?', default=False ).execute() if devMode: githubUsername = inquirer.text( message='Enter your Github username. This is required for Dev Mode.', validate=EmptyInputValidator(commons.NO_EMPTY) ).execute() githubToken = inquirer.secret( message='Enter your Github access token. This is required for Dev Mode.', validate=EmptyInputValidator(commons.NO_EMPTY), transformer=lambda _: commons.HIDDEN ).execute() enableDataStoring = inquirer.confirm( message='Enable telemetry data storing?', default=True ).execute() skillAutoUpdate = inquirer.confirm( message='Enable skill auto update?', default=True ).execute() commons.waitAnimation() confFile = Path(Path.home(), '.pacli/projectalice.yaml') confFile.parent.mkdir(parents=True, exist_ok=True) updateSource = commons.getUpdateSource(releaseType) try: with requests.get(url=f'https://raw.githubusercontent.com/project-alice-assistant/ProjectAlice/{updateSource}/ProjectAlice.yaml', stream=True) as r: r.raise_for_status() with confFile.open('wb') as fp: for chunk in r.iter_content(chunk_size=8192): if chunk: fp.write(chunk) except Exception as e: commons.printError(f'Failed downloading ProjectAlice.yaml {e}') commons.returnToMainMenu(ctx, pause=True) with confFile.open(mode='r') as f: try: confs = yaml.safe_load(f) except yaml.YAMLError as e: commons.printError(f'Failed reading projectalice.yaml {e}') commons.returnToMainMenu(ctx, pause=True) confs['adminPinCode'] = str(int(adminPinCode)).zfill(4) confs['mqttHost'] = mqttHost confs['mqttPort'] = int(mqttPort) confs['activeLanguage'] = activeLanguage confs['activeCountryCode'] = activeCountryCode confs['useHLC'] = installHLC confs['aliceUpdateChannel'] = releaseType confs['skillsUpdateChannel'] = releaseType confs['ttsLanguage'] = f'{activeLanguage}-{activeCountryCode}' if soundInstalled: confs['installSound'] = False if audioDevice: confs['audioHardware'][audioDevice] = True else: confs['installSound'] = True confs['asr'] = asr confs['awsAccessKey'] = awsAccessKey confs['awsSecretKey'] = awsSecretKey confs['tts'] = tts confs['shortReplies'] = shortReplies confs['devMode'] = devMode confs['githubUsername'] = githubUsername confs['githubToken'] = githubToken confs['enableDataStoring'] = enableDataStoring confs['skillAutoUpdate'] = skillAutoUpdate if googleServiceFile and Path(googleServiceFile).exists(): confs['googleServiceFile'] = Path(googleServiceFile).read_text() if asr == 'google': confs['keepASROffline'] = False if tts in ['amazon', 'google', 'watson']: confs['keepTTSOffline'] = False with confFile.open(mode='w') as f: yaml.dump(confs, f) commons.printSuccess('Generated ProjectAlice.yaml') commons.printInfo('Updating system') sshCmd('sudo apt-get update') sshCmd('sudo apt-get install git -y') sshCmd('git config --global user.name "Han Oter"') sshCmd('git config --global user.email "*****@*****.**"') commons.printInfo('Cloning Alice') sshCmd('git clone https://github.com/project-alice-assistant/ProjectAlice.git ~/ProjectAlice') sftp = commons.SSH.open_sftp() sftp.put(str(confFile), '/home/pi/ProjectAlice/ProjectAlice.yaml') sftp.close() sshCmd('sudo rm /boot/ProjectAlice.yaml') sshCmd('sudo cp ~/ProjectAlice/ProjectAlice.yaml /boot/ProjectAlice.yaml') commons.printInfo('Start install process') sshCmd('cd ~/ProjectAlice/ && python3 main.py') commons.printSuccess('Alice has completed the basic installation! She\'s now working further to complete the installation, let\'s see what she does!') ctx.invoke(systemLogs)
def _join_game(self): token_validator_sock = WSock(8766) sock = WSock() settings = UserSettings(**get_config()) priv_topic = settings.private_topic sock.subscribe(priv_topic) settings = UserSettingsSchema().dumps(settings) print( 'In order to join a match, you need to get an alphanumeric token. Ex: a56n1d' ) while (True): tkn = inquirer.text( message='Input token here:', validate=lambda text: len(text) == 6 and text.isalnum(), invalid_message= 'Please enter a valid 6 character, alphanumeric token... ' ).execute() message = json.dumps({ 'action': 'validate-token', 'topic': tkn, 'private_token': priv_topic }) token_validator_sock.send_json(message) topic_exist = '' while (True): topic_exist = token_validator_sock.recv_json(priv_topic) if (topic_exist.private_token == priv_topic): topic_exist = topic_exist.response break if (topic_exist == 'topic-non-existent'): print( f'The token "{tkn}" does not have a server attached to it. Please enter a valid token!' ) else: break sock.send_json(settings, tkn) verification = sock.recv_str(priv_topic) if (verification == 'declined'): print('Request to join was declined by host ...') return 'declined' else: return 'accepted'
def init(dirname: str = typer.Argument(".")): dirname = Path(dirname) basemap_zoom = 18 # TODO: Fix if Path(dirname.joinpath(FILENAME)).exists(): typer.Abort() if not dirname.is_dir(): typer.Abort() shortdirname = dirname.resolve().name uid = inquirer.text(message="Twin ID:", default=shortdirname).execute() location_keywords = None location = None bbox = [] default_name = "" while True: location_keywords = inquirer.text( message="Location keywords (leave blank to skip):", ).execute() if not location_keywords: break geolocator = Nominatim(user_agent="owntwin-cli") location_candidates = geolocator.geocode( location_keywords, exactly_one=False, limit=5 ) if not location_candidates: typer.echo("Not found. Please Try again.") continue location = inquirer.select( message="Select nearby location:", choices=list( map(lambda x: {"name": x.address, "value": x}, location_candidates) ) + [Separator(), {"name": "(Back)", "value": False}], ).execute() if location: break if not location_keywords: def validate(text): try: return len(tuple(map(lambda x: float(x.strip()), text.split(",")))) == 2 except: return False location_coordinate = inquirer.text( message="Location coordinate [latitude, longitude] (leave blank to skip):", validate=validate, filter=lambda text: tuple(map(lambda x: float(x.strip()), text.split(","))), ).execute() location = namedtuple("location", ["latitude", "longitude", "address"]) location.latitude, location.longitude = location_coordinate location.address = "" if location: lat, lng = location.latitude, location.longitude # print(location, lat, lng) size = inquirer.text( message="Side length (meter):", filter=lambda x: float(x), validate=NumberValidator(float_allowed=True), ).execute() # bbox = [ # lng + utils.meter_to_lng(size, lat, lng), # east # lat - utils.meter_to_lat(size, lat, lng), # south # lng - utils.meter_to_lng(size, lat, lng), # west # lat + utils.meter_to_lat(size, lat, lng), # north # ] bbox = [ lng - utils.meter_to_lng(size, lat, lng), # west lat - utils.meter_to_lat(size, lat, lng), # south lng + utils.meter_to_lng(size, lat, lng), # east lat + utils.meter_to_lat(size, lat, lng), # north ] tiles = mercantile.tiles(*bbox, basemap_zoom) tiles = list(tiles) basemap_bbox = utils.tiles_bounds(tiles) bbox = basemap_bbox typer.echo( " Left (lng): {}\n Bottom (lat): {}\n Right (lng): {}\n Top (lat): {}".format( *bbox ) ) typer.confirm("Is this OK?", default=True, abort=True) default_name = location.address name = inquirer.text(message="Twin name:", default=default_name).execute() type = inquirer.text(message="Twin type:", default="").execute() iri = inquirer.text( message="IRI or URL:", default=f"https://beta.owntwin.com/twin/{uid}" ).execute() description = inquirer.text(message="Description:", default="").execute() twin = { "id": uid, "name": name, "type": type, "type_label": type, "iri": iri, "description": description, "bbox": bbox, "canvas": { "width": 1024, "height": 1024, }, "terrain": { "path": "assets/levelmap.json", }, "building": { "path": "assets/buildings.json", }, "modules": {}, } # twin = { # "name": name, # ... # "terrain": "levelmap.json", # "objects": { # "building": "building.json", # }, # "modules": {}, # } typer.echo(f"About to create {FILENAME}:\n") typer.echo(json.dumps(twin, ensure_ascii=False, indent=2)) typer.confirm("Is this OK?", default=True, abort=True) if not dirname.exists(): dirname.mkdir() save_config(twin, dirname.joinpath(FILENAME))
def connect(ctx: click.Context, ip_address: str, port: int, user: str, password: str, return_to_main_menu: bool, noExceptHandling: bool = False) -> Optional[paramiko.SSHClient]: # NOSONAR global SSH, IP_REGEX, CONNECTED_TO remoteAuthorizedKeysFile = '~/.ssh/authorized_keys' confFile = Path(Path.home(), '.pacli/configs.json') confFile.parent.mkdir(parents=True, exist_ok=True) if not confFile.exists(): confs = dict() confs['servers'] = dict() confFile.write_text(json.dumps(confs)) else: confs = json.loads(confFile.read_text()) if not ip_address: ip_address = inquirer.text( message='Please enter the device IP address', validate=lambda ip: IP_REGEX.match(ip) is not None ).execute() data = confs['servers'].get(ip_address, dict()).get('keyFile') if data: user = confs['servers'][ip_address]['user'] keyFile = Path(Path.home(), f".ssh/{confs['servers'][ip_address]['keyFile']}") if not keyFile.exists(): printError('Declared server is using a non existing RSA key file, removing entry and asking for password.') confs['servers'].pop(ip_address, None) keyFile = None else: keyFile = None if not keyFile and not user: user = inquirer.text( message='Please enter username', validate=lambda answer: len(answer) > 0, invalid_message='Cannot be empty' ).execute() if not keyFile and not password: password = inquirer.secret( message='Please enter the connection password', transformer=lambda _: HIDDEN ).execute() try: if SSH: disconnect() ssh = paramiko.SSHClient() ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy) waitAnimation() if password: ssh.connect(hostname=ip_address, port=port, username=user, password=password) else: key = paramiko.RSAKey.from_private_key_file(str(keyFile)) ssh.connect(hostname=ip_address, port=port, username=user, pkey=key) except Exception as e: if not noExceptHandling: printError(f'Failed connecting to device: {e}') if ip_address in confs['servers'] and not password: confs['servers'].pop(ip_address, None) confFile.write_text(json.dumps(confs)) ctx.invoke(connect, ip_address=ip_address, user=user, return_to_main_menu=return_to_main_menu) return else: raise else: printSuccess('Successfully connected to device') SSH = ssh CONNECTED_TO = ip_address if ip_address not in confs['servers']: filename = f'id_rsa_{str(uuid.uuid4())}' keyFile = Path(Path.home(), f'.ssh/{filename}') confs['servers'][ip_address] = { 'keyFile': filename, 'user' : user } confFile.write_text(json.dumps(confs)) key = paramiko.RSAKey.generate(4096) key.write_private_key_file(filename=str(keyFile)) pubKeyFile = keyFile.with_suffix('.pub') pubKeyFile.write_text(key.get_base64()) sshCmd(f"echo \"ssh-rsa {pubKeyFile.read_text()} Project Alice RSA key\" | exec sh -c 'cd ; umask 077 ; mkdir -p .ssh && cat >> {remoteAuthorizedKeysFile} || exit 1 ; if type restorecon >/dev/null 2>&1 ; then restorecon -F .ssh ${remoteAuthorizedKeysFile} ; fi'") if not return_to_main_menu: return ssh if return_to_main_menu: returnToMainMenu(ctx)
calibration_dir = helpers.create_calibration_dir() helpers.check_existing_calibration(calibration_dir, my_loadcell) if my_loadcell.is_calibrated is not True: helpers.calibrate_loadcell(my_loadcell, calibration_dir) elif result == 'manual': helpers.start_manual_mode(my_controller, my_loadcell, speed=3, mode_button_pin=22, up_button_pin=17, down_button_pin=27) elif result == 'monotonic' or result == 'cyclic': adjustment_position = float( inquirer.text( message='Specify the crossbar initial position [mm]:', default='50', validate=validator.NumberValidator( float_allowed=True)).execute()) helpers.calibrate_controller(my_controller=my_controller) if my_controller.is_calibrated: helpers.adjust_crossbar_position( my_controller=my_controller, adjustment_position=adjustment_position) calibration_dir = helpers.create_calibration_dir() helpers.check_existing_calibration(calibration_dir, my_loadcell) if my_loadcell.is_calibrated is not True: helpers.calibrate_loadcell(my_loadcell, calibration_dir) helpers.start_manual_mode(my_controller,
def damage_facility(database): facility_id = iq.text("Facility id:").execute() facilityCrud.damage_facility(database, facility_id)
def _create_game(self): token = uuid.uuid4().hex[:6] # Start server server = Server(server_token=token) sock = WSock() sock.bind(token) sock.subscribe(token) print( 'In order for someone to join, they have to use this token below:\n' ) print(token) def _get_requests(): while (True): try: opponent_info = vars(sock.recv_json(token)) except ConnectionResetError as e: if (str( e ) == '[WinError 10054] An existing connection was forcibly closed by the remote host' ): continue self._user_requesting.append(opponent_info) Thread(target=_get_requests, daemon=True, name='Game._create_game._get_requests()').start() # Add carriage return so we can replace this line print('\rWaiting for a user to connect ...', end='') while (True): if (len(self._user_requesting) == 0): continue opponent_info = self._user_requesting[0] user = UserSettingsSchema().load(opponent_info) allow_user = inquirer.text( message= f'\nThe user "{user.username}" is requesting to join, accept request?', validate=lambda text: text.lower() in ['y', 'yes', 'n', 'no'], invalid_message='Please answer with a yes or no (y/n)' ).execute() if (allow_user.lower() in ['yes', 'y']): self._opponent = user sock.send_str('accepted', user.private_topic) break else: sock.send_str('declined', user.private_topic) print(f'The user "{user.username}" is declined ...') print('\rWaiting for a user to connect ...', end='') del self._user_requesting[0] continue
def prepareSdCard(ctx: click.Context): # NOSONAR if not commons.isAdmin(): commons.returnToMainMenu(ctx=ctx, pause=True, message='You need admin rights for this, please restart Alice CLI with admin elevated rights.') return operatingSystem = platform.system().lower() balenaExecutablePath = getBalenaPath() flasherAvailable = balenaExecutablePath != None downloadsPath = Path.home() / 'Downloads' doFlash = inquirer.confirm( message='Do you want to flash your SD card with Raspberry PI OS?', default=False ).execute() installBalena = False if not flasherAvailable: installBalena = inquirer.confirm( message='balena-cli was not found on your system. It is required for working with SD cards, do you want to install it?', default=True ) if not flasherAvailable and not installBalena: commons.returnToMainMenu(ctx, pause=True, message='Well then, I cannot work with your SD card without the appropriate tool to do it') return elif not flasherAvailable and installBalena: commons.printInfo('Installing Balena-cli, please wait...') balenaVersion = 'v13.1.1' if operatingSystem == 'windows': url = f'https://github.com/balena-io/balena-cli/releases/download/{balenaVersion}/balena-cli-{balenaVersion}-windows-x64-installer.exe' elif operatingSystem == 'linux': url = f'https://github.com/balena-io/balena-cli/releases/download/{balenaVersion}/balena-cli-{balenaVersion}-linux-x64-standalone.zip' else: url = f'https://github.com/balena-io/balena-cli/releases/download/{balenaVersion}/balena-cli-{balenaVersion}-macOS-x64-installer.pkg' destination = downloadsPath / url.split('/')[-1] if destination.exists(): commons.printInfo(f'Skipping download, using existing: {destination}') else: commons.printInfo('Downloading...') doDownload(url=url, destination=destination) if operatingSystem == 'windows': commons.printInfo("Starting the installation, please follow the instructions and come back when it's done!") subprocess.Popen(str(destination).split(), shell=True) click.pause('Press a key when the installation process is done! Please close your terminal and restart it to continue the flashing process') exit(0) elif operatingSystem == 'linux': executablePath = Path(balenaExecutablePath) commons.printInfo(f"Install dir: {executablePath.parent}") commons.printInfo(f'Extracting {destination} to {executablePath.name}...') archive = zipfile.ZipFile(destination) archive.extractall() # extract to ./balena-cli/ i.e. sub dir of working directory. commons.printInfo('Setting ./balena-cli/balena as executable...') # set executable permission # from https://stackoverflow.com/questions/12791997/how-do-you-do-a-simple-chmod-x-from-within-python executablePath.chmod(509) # now shell `./balena-cli/balena version` works commons.printInfo('Adding ./balena-cli to PATH...') os.environ['PATH'] += os.pathsep + str(executablePath.parent) sysPath = os.environ['PATH'] commons.printInfo(f'New PATH: {sysPath}') click.pause('Installation Done. Press a key') else: click.pause('I have no idea how to install stuff on Mac, so I have downloaded the tool for you, please install it. Oh, and contact Psycho to let him know how to install a pkg file on Mac ;-)') exit(0) if doFlash: images = list() commons.printInfo('Checking for Raspberry PI OS images, please wait....') # Potential local files downloadsPath = Path.home() / 'Downloads' for file in downloadsPath.glob('*raspi*.zip'): images.append(str(file)) images.append('https://downloads.raspberrypi.org/raspios_lite_armhf/images/raspios_lite_armhf-2021-05-28/2021-05-07-raspios-buster-armhf-lite.zip') # Deactivated for now, we enforce Buster only! # directories = list() # Get a list of available images online # url = 'https://downloads.raspberrypi.org/raspios_lite_armhf/images/' # page = requests.get(url) # if page.status_code == 200: # soup = BeautifulSoup(page.text, features='html.parser') # directories = [url + node.get('href') for node in soup.find_all('a') if node.get('href').endswith('/')] # if directories: # directories.pop(0) # This is the return link, remove it... # # for directory in directories: # page = requests.get(directory) # if page.status_code == 200: # soup = BeautifulSoup(page.text, features='html.parser') # images.extend([directory + node.get('href') for node in soup.find_all('a') if node.get('href').endswith('.zip')]) commons.printInfo('Checking for available SD card drives, please wait....') drives = list() sdCards = getSdCards() for sdCard in sdCards: drives.append(Choice(sdCard, name=sdCard)) if not drives: commons.returnToMainMenu(ctx, pause=True, message='Please insert your SD card first') return image = inquirer.select( message='Select the image you want to flash. Keep in mind we only officially support the "Buster" Raspberry pi OS distro!', choices=images ).execute() drive = inquirer.select( message='Select your SD card drive', choices=drives ).execute() commons.printInfo("Flashing SD card, please wait") if image.startswith('https'): file = downloadsPath / image.split('/')[-1] doDownload(url=image, destination=file) else: file = image if operatingSystem == 'windows' or operatingSystem == 'linux': if operatingSystem == 'linux': # this only works on distros with "sudo" support. balenaCommand = f'sudo {balenaExecutablePath} local flash {str(file)} --drive {drive} --yes' else: balenaCommand = f'balena local flash {str(file)} --drive {drive} --yes'.split() subprocess.run(balenaCommand, shell=True) time.sleep(5) else: commons.returnToMainMenu(ctx, pause=True, message='Flashing only supported on Windows and Linux systems for now. If you have the knowledge to implement it on other systems, feel free to pull request!') return click.pause('Flashing complete. Please eject, unplug and replug your SD back, then press any key to continue...') ssid = inquirer.text( message='Enter the name of your Wifi network', validate=EmptyInputValidator(commons.NO_EMPTY) ).execute() password = inquirer.secret( message='Enter your Wifi network\'s key', transformer=lambda _: commons.HIDDEN ).execute() country = inquirer.select( message='Select your country. This is used for your Wi-Fi settings!', default='EN', choices=commons.COUNTRY_CODES ).execute() drives = list() drive = '' if operatingSystem == 'linux': # typically, boot partition is the first increment of SD device # e.g. on /dev/sda drive /dev/sda1 is "boot" and /dev/sda2 is "rootfs" # Lookup up the boot mount point path via lsblk sdCards = getSdCards() command = f'sudo lsblk -o PATH,FSTYPE,LABEL,MOUNTPOINT --json' output = subprocess.run(command, capture_output=True, shell=True).stdout.decode() blkDevices = json.loads(output) for device in blkDevices['blockdevices']: if device["path"].startswith(tuple(sdCards)) and device['fstype'] == 'vfat' and device['label'] == 'boot': drives.append(Choice(value=device, name=device['path'])) if len(drives) == 0: commons.printError(f'For some reason I cannot find the SD boot partition mount point {drive}.') commons.returnToMainMenu(ctx, pause=True, message="I'm really sorry, but I just can't continue without this info, sorry for wasting your time...") if len(drives) == 1: device = drives[0].value commons.printInfo(f'Auto-selected {device["path"]}.') drive = device else: j = 0 while len(drives) <= 0: j += 1 for dp in psutil.disk_partitions(): if 'rw,removable' not in dp.opts.lower(): continue drives.append(dp.device) if not drives: if j < 3: drives = list() commons.printError('For some reason I cannot find any writable SD partition. Please eject then unplug, replug your SD back and press any key to continue') click.pause() else: break if not drive: drive = inquirer.select( message='Please select the correct SD `boot` partition', choices=drives ).execute() needToUnmount = False mountDir = '' if operatingSystem == 'linux': # if device has not been mounted yet, mount in temp directory if drive['mountpoint'] is None: needToUnmount = True mountDir = tempfile.mkdtemp(prefix='alice-cli-mount-') command = f"sudo mount {drive['path']} {mountDir}" result = subprocess.run(command, capture_output=True, shell=True) if not result.returncode == 0: commons.printError(f"Could not mount {drive['path']} to {mountDir}.") commons.returnToMainMenu(ctx, pause=True) drive['mountpoint'] = mountDir commons.printInfo(f"Mounted {drive['path']} to {mountDir} temporarily.") else: commons.printInfo(f"{drive['path']} is already mounted to {drive['mountpoint']}.") drive = drive['mountpoint'] # Now let's enable SSH and Wi-Fi on boot. commons.printInfo('Adding ssh & wifi to SD boot....') sshFile = Path(drive, 'ssh') sshFile.unlink(missing_ok=True) sshFile.touch() content = f'country={country}\n' content += 'ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev\n' content += 'update_config=1\n' content += 'network={\n' content += f'\tssid="{ssid}"\n' content += '\tscan_ssid=1\n' content += f'\tpsk="{password}"\n' content += '\tkey_mgmt=WPA-PSK\n' content += '}' Path(drive, 'wpa_supplicant.conf').write_text(content) if operatingSystem == 'linux' and needToUnmount and mountDir: command = f'sudo umount {drive}' result = subprocess.run(command, capture_output=True, shell=True) if not result.returncode == 0: commons.printError(f'Could not unmount {drive}.') commons.returnToMainMenu(ctx, pause=True) commons.printInfo(f'Unmounted {drive}') # only deletes empty dirs, so if unmounting failed for whatever reasons, we don't destroy anything os.rmdir(mountDir) commons.returnToMainMenu(ctx, pause=True, message='SD card is ready. Please plug it in your device and boot it!')
def downgrade_facility(database): facility_id = iq.text("Facility id:").execute() facilityCrud.downgrade_facility(database, facility_id)
def destroy_ship(database): ship_id = iq.text("Ship id:").execute() shipCrud.destroy_ship(database, ship_id)
def restore_single_facility(database): facility_id = iq.text("Facility id:").execute() facilityCrud.restore_single_facility(database, facility_id)
def damage_ship(database): ship_id = iq.text("Ship id:").execute() damage = int(iq.text("Damage:").execute()) shipCrud.damage_ship(database, ship_id, damage)