diff --git a/EDMarketConnector.py b/EDMarketConnector.py index c88fd162..f8c676df 100755 --- a/EDMarketConnector.py +++ b/EDMarketConnector.py @@ -1228,10 +1228,15 @@ class AppWindow(object): if err: play_bad = True - # Export market data - if not self.export_market_data(capi_response.capi_data): - err = 'Error: Exporting Market data' - play_bad = True + should_return, new_data = killswitch.check_killswitch('capi.request./market', {}) + if should_return: + logger.warning("capi.request./market has been disabled by killswitch. Returning.") + + else: + # Export market data + if not self.export_market_data(capi_response.capi_data): + err = 'Error: Exporting Market data' + play_bad = True self.capi_query_holdoff_time = capi_response.query_time + companion.capi_query_cooldown diff --git a/PLUGINS.md b/PLUGINS.md index dc23752d..dd71ca28 100644 --- a/PLUGINS.md +++ b/PLUGINS.md @@ -910,10 +910,9 @@ constants. ### Commander Data from Frontier CAPI If a plugin has a `cmdr_data()` function it gets called when the application -has just fetched fresh Cmdr and station data from Frontier's servers, **but not -for the Legacy galaxy**. See `cmdr_data_legacy()` below for Legacy data -handling. - +has just fetched fresh Cmdr and station data from Frontier's CAPI servers, +**but not for the Legacy galaxy**. See `cmdr_data_legacy()` below for Legacy +data handling. ```python from companion import CAPIData, SERVER_LIVE, SERVER_LEGACY, SERVER_BETA @@ -948,6 +947,16 @@ have extra properties, such as `source_host`, as shown above. Plugin authors are free to use *that* property, **but MUST NOT rely on any other extra properties present in `CAPIData`, they are for internal use only.** +The contents of `data` will always have at least the data returned by a CAPI +`/profile` query. If the player is docked at a station, and the relevant +services are available then the `lastStarport` key's value will have been +augmented with `/market` and/or `/shipyard` data. **But do not assume this +will always be the case**. + +If there is a killswitch in effect for some of the CAPI endpoints, then the +data passed to this function might not be as complete as you expect. Code +defensively. + #### CAPI data for Legacy When CAPI data has been retrieved from the separate CAPI host for the Legacy diff --git a/companion.py b/companion.py index b8b0a662..9c1ec02c 100644 --- a/companion.py +++ b/companion.py @@ -601,7 +601,7 @@ class EDMCCAPIFailedRequest(EDMCCAPIReturn): ): super().__init__(query_time=query_time, play_sound=play_sound, auto_update=auto_update) self.message: str = message # User-friendly reason for failure. - self.exception: int = exception # Exception that recipient should raise. + self.exception: BaseException = exception # Exception that recipient should raise. class Session(object): @@ -772,7 +772,12 @@ class Session(object): :param timeout: requests query timeout to use. :return: The resulting CAPI data, of type CAPIData. """ - capi_data: CAPIData + capi_data: CAPIData = CAPIData() + should_return, new_data = killswitch.check_killswitch('capi.request.' + capi_endpoint, {}) + if should_return: + logger.warning(f"capi.request.{capi_endpoint} has been disabled by killswitch. Returning.") + return capi_data + try: logger.trace_if('capi.worker', 'Sending HTTP request...') if conf_module.capi_pretend_down: @@ -854,6 +859,10 @@ class Session(object): """ station_data = capi_single_query(capi_host, self.FRONTIER_CAPI_PATH_PROFILE, timeout=timeout) + if not station_data.get('commander'): + # If even this doesn't exist, probably killswitched. + return station_data + if not station_data['commander'].get('docked') and not monitor.state['OnFoot']: return station_data @@ -894,6 +903,10 @@ class Session(object): if services.get('commodities'): market_data = capi_single_query(capi_host, self.FRONTIER_CAPI_PATH_MARKET, timeout=timeout) + if not market_data.get('id'): + # Probably killswitched + return station_data + if last_starport_id != int(market_data['id']): logger.warning(f"{last_starport_id!r} != {int(market_data['id'])!r}") raise ServerLagging() @@ -904,6 +917,10 @@ class Session(object): if services.get('outfitting') or services.get('shipyard'): shipyard_data = capi_single_query(capi_host, self.FRONTIER_CAPI_PATH_SHIPYARD, timeout=timeout) + if not shipyard_data.get('id'): + # Probably killswitched + return station_data + if last_starport_id != int(shipyard_data['id']): logger.warning(f"{last_starport_id!r} != {int(shipyard_data['id'])!r}") raise ServerLagging() diff --git a/plugins/eddn.py b/plugins/eddn.py index 2f2ccc78..afe54047 100644 --- a/plugins/eddn.py +++ b/plugins/eddn.py @@ -636,6 +636,16 @@ class EDDN: :param data: a dict containing the starport data :param is_beta: whether or not we're currently in beta mode """ + should_return, new_data = killswitch.check_killswitch('capi.request./market', {}) + if should_return: + logger.warning("capi.request./market has been disabled by killswitch. Returning.") + return + + should_return, new_data = killswitch.check_killswitch('eddn.capi_export.commodities', {}) + if should_return: + logger.warning("eddn.capi_export.commodities has been disabled by killswitch. Returning.") + return + modules, ships = self.safe_modules_and_ships(data) horizons: bool = capi_is_horizons( data['lastStarport'].get('economies', {}), @@ -757,6 +767,16 @@ class EDDN: :param data: dict containing the outfitting data :param is_beta: whether or not we're currently in beta mode """ + should_return, new_data = killswitch.check_killswitch('capi.request./shipyard', {}) + if should_return: + logger.warning("capi.request./shipyard has been disabled by killswitch. Returning.") + return + + should_return, new_data = killswitch.check_killswitch('eddn.capi_export.outfitting', {}) + if should_return: + logger.warning("eddn.capi_export.outfitting has been disabled by killswitch. Returning.") + return + modules, ships = self.safe_modules_and_ships(data) # Horizons flag - will hit at least Int_PlanetApproachSuite other than at engineer bases ("Colony"), @@ -813,6 +833,16 @@ class EDDN: :param data: dict containing the shipyard data :param is_beta: whether or not we are in beta mode """ + should_return, new_data = killswitch.check_killswitch('capi.request./shipyard', {}) + if should_return: + logger.warning("capi.request./shipyard has been disabled by killswitch. Returning.") + return + + should_return, new_data = killswitch.check_killswitch('eddn.capi_export.shipyard', {}) + if should_return: + logger.warning("eddn.capi_export.shipyard has been disabled by killswitch. Returning.") + return + modules, ships = self.safe_modules_and_ships(data) horizons: bool = capi_is_horizons( @@ -1857,7 +1887,7 @@ class EDDN: match = self.CANONICALISE_RE.match(item) return match and match.group(1) or item - def capi_gameversion_from_host_endpoint(self, capi_host: str, capi_endpoint: str) -> str: + def capi_gameversion_from_host_endpoint(self, capi_host: Optional[str], capi_endpoint: str) -> str: """ Return the correct CAPI gameversion string for the given host/endpoint.