def _command(): if self.app.nice() != self.valid_priorities[ DCSConfig.DCS_CPU_PRIORITY()]: LOGGER.debug('setting DCS process priority to: %s', DCSConfig.DCS_CPU_PRIORITY()) self.app.nice( self.valid_priorities[DCSConfig.DCS_CPU_PRIORITY()])
async def _run(self): if CTX.discord_can_start: LOGGER.debug('starting Discord client') self._create_client() await self.client.start(DiscordBotConfig.DISCORD_TOKEN()) else: await asyncio.sleep(1)
def set_priority(self): """ Sets the DCS process CPU priority to the CFG value """ def _command(): if self.app.nice() != self.valid_priorities[ DCSConfig.DCS_CPU_PRIORITY()]: LOGGER.debug('setting DCS process priority to: %s', DCSConfig.DCS_CPU_PRIORITY()) self.app.nice( self.valid_priorities[DCSConfig.DCS_CPU_PRIORITY()]) time.sleep(15) while True: if DCSConfig.DCS_CPU_PRIORITY(): if core.CTX.exit: return if DCSConfig.DCS_CPU_PRIORITY( ) not in self.valid_priorities.keys(): LOGGER.error( f'invalid priority: %s\n' f'Choose one of: %s', DCSConfig.DCS_CPU_PRIORITY(), self.valid_priorities.keys(), ) return self._work_with_dcs_process(_command) else: LOGGER.warning( 'no CPU priority given in config file for dcs.exe') return time.sleep(30)
def _write_dedi_config(): dedi_cfg_path = Path(FS.variant_saved_games_path, 'Config/dedicated.lua') if not dedi_cfg_path.exists(): LOGGER.info('writing %s', dedi_cfg_path) dedi_cfg_path.write_text(DEDI_CFG) else: LOGGER.debug('file already exists: %s', dedi_cfg_path)
def init() -> None: """ Makes sure the configuration is valid before starting ESST :raise: SystemExit """ # Setup elib_config elib_config.ELIBConfig.setup( app_version=__version__, app_name='ESST', config_file_path='esst.toml', config_sep_str='__', ) # Write example config file elib_config.write_example_config('esst.toml.example') # Validate config try: elib_config.validate_config() except elib_config.ConfigMissingValueError as error: LOGGER.error('missing mandatory config value: %s', error.value_name) LOGGER.error( 'please read "esst.toml.example" for instructions on how to setup the configuration for ESST' ) sys.exit(1) for config in SentryConfigContext.__subclasses__(): SENTRY.register_context(context_name=config.__name__, context_provider=config)
async def on_ready(self): """ Triggers when the bot is ready. """ if not self.ready: self._user = self.client.user await self._update_profile() LOGGER.debug('Logged in as: %s', self.client.user.name) try: self._server = set(self.client.servers).pop() except KeyError: LOGGER.error('Your discord bot has not server to connect to\n' 'Go to https://discordapp.com/developers/applications/me to create a bot, and note ' 'the client ID.\n' 'Use the client ID in the following URL to join you bot to your Discord server:\n' 'https://discordapp.com/oauth2/authorize?client_id=CLIENT_ID&scope=bot') else: self._member = self.server.get_member(self.user.id) if self.user.display_name != DiscordBotConfig.DISCORD_BOT_NAME(): await self.client.change_nickname(self.member, DiscordBotConfig.DISCORD_BOT_NAME()) await self._update_presence() await self.get_channel() self._ready = True
def _get_server_settings_path() -> Path: if not FS.dcs_server_settings: LOGGER.error('FS.dcs_server_settings undefined') sys.exit(1) if not FS.dcs_server_settings.exists(): LOGGER.error('please start a DCS server at least once before using ESST') sys.exit(1) return FS.dcs_server_settings
def show(): """ Shows ICAO & frequencies for the ATIS """ output = ['List of ATIS frequencies:'] for airfield in ALL_AIRFIELDS: output.append(f'{airfield.icao} {airfield.name}: {airfield.atis_freq.long_freq()}') LOGGER.info('\n'.join(output))
def _get_ur_install_path_from_registry() -> typing.Union[Path, None]: LOGGER.debug('searching for base "Saved Games" folder') try: with winreg.OpenKey(A_REG, r"Software\sSoft\UniversRadio") as key: # noinspection SpellCheckingInspection return Path(winreg.QueryValueEx(key, "Install_Dir")[0]) except FileNotFoundError: return None
def captureException(self, exc_info=None, **kwargs): """Captures an exception""" self.set_context() LOGGER.debug('capturing exception') for k, context_provider in self.registered_contexts.items(): self.extra_context({k: context_provider.get_context()}) super(Sentry, self).captureException(exc_info, **kwargs)
def write_settings_file(self): """ Writes currently known station to UR settings file """ LOGGER.debug('writing UR settings to: %s', FS.ur_voice_settings_file) stations = '\n'.join(self._stations) full_text = f'Start of VSS DB\n{stations}\nEnd of VSS DB' FS.ur_voice_settings_file.write_text(full_text)
def poll(): """ Checks that UR voice service is running """ LOGGER.debug('polling UR voice service') proc = psutil.Process(URVoiceService.pid) if not proc.status() == psutil.STATUS_RUNNING: raise RuntimeError('UR voice service stopped')
async def _try_to_connect_to_existing_dcs_application(self): if self.app and self.app.is_running(): return LOGGER.debug('connecting to existing DCS application') await self._check_if_dcs_is_running() if self.process_pid: self._app = psutil.Process(self.process_pid) await self._wait_for_dcs_to_start()
def external_ip(): """ Returns: external IP of this machine """ try: return requests.get('https://api.ipify.org').text except requests.ConnectionError: LOGGER.error('unable to obtain external IP') return 'unknown'
def reboot(force: bool = False): """Reboots the server computer""" if DCS.there_are_connected_players(): if not force: return 'there are connected players; cannot restart the server now (use "--force" to restart anyway)' LOGGER.warning('forcing restart with connected players') os.system('shutdown /r /t 30 /c "Reboot initialized by ESST"') # nosec return ''
def _queue_kill(queue: Queue): while DCS.there_are_connected_players(): if not queue.empty(): queue.get_nowait() LOGGER.debug('queued DCS kill has been cancelled') return time.sleep(5) LOGGER.info('executing planned DCS restart') DCS.kill()
async def run(self): """ Entry point of the loop """ if not CTX.start_server_loop: LOGGER.debug('skipping server loop') return CTX.loop.run_in_executor(None, self._update_status) LOGGER.debug('end of Server computer loop')
async def _monitor_server(self): await asyncio.sleep(0.1) if self.monitoring: if time.time() - self.last_ping > DCSConfig.DCS_PING_INTERVAL(): LOGGER.error( 'It has been %s seconds since I heard from DCS. ' 'It is likely that the server has crashed.', DCSConfig.DCS_PING_INTERVAL()) CTX.dcs_do_restart = True self.monitoring = False
def start_service(): """ Starts UR voice service """ exe_path = Path(FS.ur_install_path, PROC_NAME) if not exe_path.exists(): raise FileNotFoundError(exe_path) LOGGER.info('starting UR voice service: %s', exe_path) os.startfile(str(exe_path)) # nosec URVoiceService.is_running()
def send_file(file_path: str): """ Sends a file to the active channel Args: file_path: path to the file to send """ LOGGER.debug('sending file to Discord: %s', file_path) CTX.discord_file_queue.put(file_path)
def _work_with_dcs_process(self, func): if core.CTX.exit: return try: func() self._warned = False except (psutil.NoSuchProcess, AttributeError): if not core.CTX.exit and not self._warned: LOGGER.warning('DCS process does not exist') self._warned = True
def check_for_connected_players() -> bool: """ Returns: False if there are connected players """ if DCS.there_are_connected_players(): LOGGER.warning( 'there are connected players; cannot kill the server now') return False return True
def init_atis_module(): """ Initialize the ATIS module """ LOGGER.info('initializing ATIS module') discover_ur_install_path() if CTX.sentry: LOGGER.debug('registering ATIS contexts for Sentry') CTX.sentry.register_context(context_name='ATIS', context_provider=_ATISStatus) CTX.sentry.register_context(context_name='UR', context_provider=_URStatus) elib_wx.Config.dummy_icao_code = ATISConfig.DEFAULT_ICAO()
def sigint_handler(*_): """ Catches exit signal (triggered byu CTRL+C) Args: *_: frame """ from esst import LOGGER, core LOGGER.info('ESST has been interrupted by user request, shutting down') core.CTX.exit = True
def install_game_gui_hooks(): """ Installs the GameGUI hooks in DCS Scripts folder """ _remove_old_file() if CTX.dcs_install_hooks: LOGGER.debug('installing GameGUI hooks') _install_hook() else: LOGGER.debug('skipping installation of GameGUI hooks')
async def _parse_commands(self): await asyncio.sleep(0.1) if not CTX.listener_cmd_queue.empty(): command = CTX.listener_cmd_queue.get_nowait() if command not in KNOWN_COMMANDS: raise ValueError(f'unknown command: {command}') else: command = {'cmd': command} command = json.dumps(command) + '\n' LOGGER.debug('sending command via socket: %s', command) self.cmd_sock.sendto(command.encode(), self.cmd_address)
def __init__(self): LOGGER.info('initializing Sentry') # noinspection SpellCheckingInspection dsn = 'https://*****:*****@sentry.io/206995' self.registered_contexts = {} raven.Client.__init__( self, f'{dsn}?ca_certs={certifi.where()}', release=__version__, ) if self.is_enabled(): LOGGER.info('Sentry is ready')
async def _wait_for_dcs_to_start(self): async def _wait_for_process(): while True: if core.CTX.exit: return await asyncio.sleep(0.1) if self.app.is_running(): break LOGGER.debug('waiting for DCS to spool up') await _wait_for_process() LOGGER.debug('process is ready')
async def _no_more_mr_nice_guy(): if not self.app or not self.app.is_running(): return True LOGGER.debug('killing dcs.exe application') self.app.kill() now_ = utils.now() while self.app.is_running(): await asyncio.sleep(1) if utils.now() - now_ > 10: return False return True
def there_are_connected_players() -> bool: """ Returns: bool indicating if there are connected players """ connected_players = bool(Status.players) if connected_players: LOGGER.debug('there are %s connected player(s)', len(Status.players)) else: LOGGER.debug('there is no connected players') return connected_players