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()])
def get_latest_mission_from_github(): """ Downloads the latest mission from a Github repository The repository needs to have releases (tagged) The function will download the first MIZ file found in the latest release """ if core.CTX.dcs_auto_mission: LOGGER.debug('getting latest mission from Github') commands.DCS.block_start('loading mission') if DCSConfig.DCS_AUTO_MISSION_GH_OWNER( ) and DCSConfig.DCS_AUTO_MISSION_GH_REPO(): LOGGER.debug('looking for newer mission file') latest_version, asset_name, download_url = utils.get_latest_release( DCSConfig.DCS_AUTO_MISSION_GH_OWNER(), DCSConfig.DCS_AUTO_MISSION_GH_REPO()) LOGGER.debug('latest release: %s', latest_version) local_file = MissionPath(Path(_get_mission_folder(), asset_name)) if not local_file: LOGGER.info('downloading new mission: %s', asset_name) req = requests.get(download_url) if req.ok: local_file.path.write_bytes(req.content) local_file.set_as_active() else: LOGGER.error('failed to download latest mission') else: LOGGER.warning('no config values given for [auto mission]') commands.DCS.unblock_start('loading mission') else: LOGGER.debug('skipping mission update')
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)
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
async def _monitor_server_startup(self): await asyncio.sleep(0.1) if CTX.listener_monitor_server_startup: if self.startup_age is None: self.startup_age = time.time() if time.time( ) - self.startup_age > DCSConfig.DCS_START_GRACE_PERIOD(): LOGGER.error( f'DCS is taking more than %s seconds to start a ' 'multiplayer server.\n' 'Something is wrong ...', DCSConfig.DCS_START_GRACE_PERIOD()) CTX.listener_monitor_server_startup = False
async def _ask_politely(): if not self.app or not self.app.is_running(): return True LOGGER.debug('sending socket command to DCS for graceful exit') commands.LISTENER.exit_dcs() await asyncio.sleep(1) LOGGER.debug( 'waiting on DCS to close itself (grace period: %s seconds)', DCSConfig.DCS_CLOSE_GRACE_PERIOD()) now_ = utils.now() while self.app.is_running(): await asyncio.sleep(1) if utils.now() - now_ > DCSConfig.DCS_CLOSE_GRACE_PERIOD(): LOGGER.debug('grace period time out!') return False LOGGER.info('DCS closed itself, nice') return True
def monitor_cpu_usage(self): """ Gets the CPU usage of "DCS.exe" over 5 seconds, and sends an alert if the given threshold is exceeded Threshold is set via the config value "DCS_HIGH_CPU_USAGE", and it defaults to 80% """ while not core.CTX.exit: try: if self.app and self.app.is_running(): cpu_usage = int( self.app.cpu_percent( DCSConfig.DCS_HIGH_CPU_USAGE_INTERVAL())) mem_usage = int(self.app.memory_percent()) core.Status.dcs_cpu_usage = f'{cpu_usage}%' if core.CTX.dcs_show_cpu_usage or core.CTX.dcs_show_cpu_usage_once: commands.DISCORD.say(f'DCS cpu usage: {cpu_usage}%') core.CTX.dcs_show_cpu_usage_once = False if DCSConfig.DCS_HIGH_CPU_USAGE(): if cpu_usage > DCSConfig.DCS_HIGH_CPU_USAGE( ) and not core.Status.paused: LOGGER.warning( 'DCS cpu usage has been higher than %s%% for %s seconds', DCSConfig.DCS_HIGH_CPU_USAGE(), DCSConfig.DCS_HIGH_CPU_USAGE_INTERVAL(), ) now_ = utils.now() core.CTX.dcs_mem_history.append((now_, mem_usage)) core.CTX.dcs_cpu_history.append((now_, cpu_usage)) except psutil.NoSuchProcess: pass # I didn't think it could, happen, but of course it did ... # See https://github.com/132nd-vWing/ESST/issues/59 except AttributeError: pass
def set_affinity(self): """ Sets the DCS process CPU affinity to the CFG value """ def _command(): if list(self._app.cpu_affinity()) != list( DCSConfig.DCS_CPU_AFFINITY()): LOGGER.debug('setting DCS process affinity to: %s', DCSConfig.DCS_CPU_AFFINITY()) self._app.cpu_affinity(list(DCSConfig.DCS_CPU_AFFINITY())) while True: if DCSConfig.DCS_CPU_AFFINITY(): if core.CTX.exit: return self._work_with_dcs_process(_command) else: LOGGER.warning('no CPU affinity given in config file') return time.sleep(30)
def _command(): if list(self._app.cpu_affinity()) != list( DCSConfig.DCS_CPU_AFFINITY()): LOGGER.debug('setting DCS process affinity to: %s', DCSConfig.DCS_CPU_AFFINITY()) self._app.cpu_affinity(list(DCSConfig.DCS_CPU_AFFINITY()))
def _init_dcs_path(): from esst import DCSConfig FS.dcs_path = check_dir(DCSConfig.DCS_PATH()) LOGGER.debug('DCS path: %s', FS.dcs_path)
def _get_me_auth_path() -> Path: me_auth_path = Path(DCSConfig.DCS_PATH(), 'MissionEditor/modules/me_authorization.lua') if not me_auth_path.exists(): raise FileNotFoundError(str(me_auth_path)) return me_auth_path
def main(debug: bool): # pylint: disable=too-many-locals """ Main entry point Args: debug: show more verbose console output """ from esst import __version__, LOGGER, LOGGING_CONSOLE_HANDLER, config config.init() from esst.core import CTX from esst import ESSTConfig, DiscordBotConfig, DCSConfig, ListenerConfig, ServerConfig from esst.sentry.sentry import SENTRY SENTRY.register_context('App context', CTX) CTX.sentry = SENTRY _setup_logging_debug(__version__, LOGGER, LOGGING_CONSOLE_HANDLER, debug, ESSTConfig.DEBUG()) LOGGER.debug('instantiating main event loop') loop = asyncio.get_event_loop() CTX.loop = loop _check_wan_and_start_wan_monitor(loop, LOGGER, CTX) CTX.start_discord_loop = DiscordBotConfig.DISCORD_START_BOT() CTX.start_server_loop = ServerConfig.SERVER_START_LOOP() CTX.start_dcs_loop = DCSConfig.DCS_START_LOOP() CTX.start_listener_loop = ListenerConfig.LISTENER_START_LOOP() if not DCSConfig.DCS_CAN_START(): CTX.dcs_blocker.append('config') CTX.dcs_setup_dedi_config = DCSConfig.DCS_INSTALL_DEDICATED_CONFIG() CTX.dcs_install_hooks = DCSConfig.DCS_INSTALL_HOOKS() CTX.dcs_auto_mission = DCSConfig.DCS_AUTO_MISSION_ENABLE() loop = asyncio.get_event_loop() # loop.set_debug(True) CTX.discord_msg_queue = queue.Queue() _set_console_title(__version__) from esst import FS FS.init() from esst.utils import clean_all_folder, assign_ports clean_all_folder() assign_ports() _init_atis_module() import esst.discord_bot.discord_bot discord_loop = esst.discord_bot.discord_bot.App() from esst.dcs import dcs dcs_loop = dcs.App() from esst.server import server server_loop = server.App() from esst.listener.listener import DCSListener listener_loop = DCSListener() futures = asyncio.gather( loop.create_task(discord_loop.run()), loop.create_task(dcs_loop.run()), loop.create_task(listener_loop.run()), loop.create_task(server_loop.run()), loop.create_task(watch_for_exceptions()), ) import signal signal.signal(signal.SIGINT, sigint_handler) loop.run_until_complete(futures) LOGGER.debug('main loop is done, killing DCS') futures = asyncio.gather( # type: ignore loop.create_task(dcs_loop.kill_running_app()), loop.create_task(listener_loop.run_until_dcs_is_closed()), ) loop.run_until_complete(futures) LOGGER.debug('all done !')