From bb22c4cb12f2fa70844f8575dae51031c1f3a14c Mon Sep 17 00:00:00 2001 From: David Sangrey Date: Thu, 10 Aug 2023 18:20:04 -0400 Subject: [PATCH] #2051 Other Core Plugin Pass --- plugins/coriolis.py | 62 ++++++++------- plugins/eddn.py | 124 +++++++++++++++--------------- plugins/edsm.py | 179 ++++++++++++++++++++++---------------------- plugins/edsy.py | 64 ++++++++-------- 4 files changed, 216 insertions(+), 213 deletions(-) diff --git a/plugins/coriolis.py b/plugins/coriolis.py index b82bf2cf3..8fc534b1b 100644 --- a/plugins/coriolis.py +++ b/plugins/coriolis.py @@ -1,27 +1,25 @@ -"""Coriolis ship export.""" +""" +coriolis.py - Coriolis Ship Export. + +Copyright (c) EDCD, All Rights Reserved +Licensed under the GNU General Public License. +See LICENSE file. + +This is an EDMC 'core' plugin. +All EDMC plugins are *dynamically* loaded at run-time. + +We build for Windows using `py2exe`. +`py2exe` can't possibly know about anything in the dynamically loaded core plugins. + +Thus, you **MUST** check if any imports you add in this file are only +referenced in this file (or only in any other core plugin), and if so... + + YOU MUST ENSURE THAT PERTINENT ADJUSTMENTS ARE MADE IN + `build.py` TO ENSURE THE FILES ARE ACTUALLY PRESENT + IN AN END-USER INSTALLATION ON WINDOWS. +""" from __future__ import annotations -# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# -# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# -# -# This is an EDMC 'core' plugin. -# -# All EDMC plugins are *dynamically* loaded at run-time. -# -# We build for Windows using `py2exe`. -# -# `py2exe` can't possibly know about anything in the dynamically loaded -# core plugins. -# -# Thus you **MUST** check if any imports you add in this file are only -# referenced in this file (or only in any other core plugin), and if so... -# -# YOU MUST ENSURE THAT PERTINENT ADJUSTMENTS ARE MADE IN -# `build.py` SO AS TO ENSURE THE FILES ARE ACTUALLY PRESENT -# IN AN END-USER INSTALLATION ON WINDOWS. -# -# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# -# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# import base64 import gzip import io @@ -127,25 +125,33 @@ def plugin_prefs(parent: ttk.Notebook, cmdr: str | None, is_beta: bool) -> tk.Fr def prefs_changed(cmdr: str | None, is_beta: bool) -> None: - """Update URLs.""" + """ + Update URLs and override mode based on user preferences. + + :param cmdr: Commander name, if available + :param is_beta: Whether the game mode is beta + """ global normal_url, beta_url, override_mode + normal_url = normal_textvar.get() beta_url = beta_textvar.get() override_mode = override_textvar.get() - override_mode = { # Convert to unlocalised names + + # Convert to unlocalised names + override_mode = { _('Normal'): 'normal', # LANG: Coriolis normal/beta selection - normal - _('Beta'): 'beta', # LANG: Coriolis normal/beta selection - beta - _('Auto'): 'auto', # LANG: Coriolis normal/beta selection - auto + _('Beta'): 'beta', # LANG: Coriolis normal/beta selection - beta + _('Auto'): 'auto', # LANG: Coriolis normal/beta selection - auto }.get(override_mode, override_mode) if override_mode not in ('beta', 'normal', 'auto'): - logger.warning(f'Unexpected value {override_mode=!r}. defaulting to "auto"') + logger.warning(f'Unexpected value {override_mode=!r}. Defaulting to "auto"') override_mode = 'auto' override_textvar.set(value=_('Auto')) # LANG: 'Auto' label for Coriolis site override selection config.set('coriolis_normal_url', normal_url) config.set('coriolis_beta_url', beta_url) - config.set('coriolis_overide_url_selection', override_mode) + config.set('coriolis_override_url_selection', override_mode) def _get_target_url(is_beta: bool) -> str: diff --git a/plugins/eddn.py b/plugins/eddn.py index fc0f4b332..aaaad7a6d 100644 --- a/plugins/eddn.py +++ b/plugins/eddn.py @@ -1,4 +1,23 @@ -"""Handle exporting data to EDDN.""" +""" +eddn.py - Exporting Data to EDDN. + +Copyright (c) EDCD, All Rights Reserved +Licensed under the GNU General Public License. +See LICENSE file. + +This is an EDMC 'core' plugin. +All EDMC plugins are *dynamically* loaded at run-time. + +We build for Windows using `py2exe`. +`py2exe` can't possibly know about anything in the dynamically loaded core plugins. + +Thus, you **MUST** check if any imports you add in this file are only +referenced in this file (or only in any other core plugin), and if so... + + YOU MUST ENSURE THAT PERTINENT ADJUSTMENTS ARE MADE IN + `build.py` TO ENSURE THE FILES ARE ACTUALLY PRESENT + IN AN END-USER INSTALLATION ON WINDOWS. +""" from __future__ import annotations # ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# @@ -204,10 +223,8 @@ def sqlite_queue_v1(self) -> sqlite3.Connection: db = db_conn.cursor() try: - db.execute( - """ - CREATE TABLE messages - ( + db.execute(""" + CREATE TABLE IF NOT EXISTS messages ( id INTEGER PRIMARY KEY AUTOINCREMENT, created TEXT NOT NULL, cmdr TEXT NOT NULL, @@ -216,26 +233,12 @@ def sqlite_queue_v1(self) -> sqlite3.Connection: game_build TEXT, message TEXT NOT NULL ) - """ - ) + """) - db.execute( - """ - CREATE INDEX messages_created ON messages - ( - created - ) - """ - ) + db.execute("CREATE INDEX IF NOT EXISTS messages_created ON messages (created)") + db.execute("CREATE INDEX IF NOT EXISTS messages_cmdr ON messages (cmdr)") - db.execute( - """ - CREATE INDEX messages_cmdr ON messages - ( - cmdr - ) - """ - ) + logger.info("New 'eddn_queue-v1.db' created") except sqlite3.OperationalError as e: if str(e) != "table messages already exists": @@ -244,12 +247,6 @@ def sqlite_queue_v1(self) -> sqlite3.Connection: db_conn.close() raise e - else: - logger.info("New `eddn_queue-v1.db` created") - - # We return only the connection, so tidy up - db.close() - return db_conn def convert_legacy_file(self): @@ -265,11 +262,10 @@ def convert_legacy_file(self): except FileNotFoundError: return + logger.info("Conversion to `eddn_queue-v1.db` complete, removing `replay.jsonl`") # Best effort at removing the file/contents - # NB: The legacy code assumed it could write to the file. - logger.info("Conversion` to `eddn_queue-v1.db` complete, removing `replay.jsonl`") - replay_file = open(filename, 'w') # Will truncate - replay_file.close() + with open(filename, 'w') as replay_file: + replay_file.truncate() os.unlink(filename) def close(self) -> None: @@ -460,9 +456,8 @@ def send_message(self, msg: str) -> bool: logger.debug(f"EDDN responded '400 Bad Request' to the message, dropping:\n{msg!r}") return True - else: - # This should catch anything else, e.g. timeouts, gateway errors - self.set_ui_status(self.http_error_to_log(e)) + # This should catch anything else, e.g. timeouts, gateway errors + self.set_ui_status(self.http_error_to_log(e)) except requests.exceptions.RequestException as e: logger.debug('Failed sending', exc_info=e) @@ -482,21 +477,26 @@ def queue_check_and_send(self, reschedule: bool = False) -> None: # noqa: CCR00 :param reschedule: Boolean indicating if we should call `after()` again. """ logger.trace_if("plugin.eddn.send", "Called") + # Mutex in case we're already processing - if not self.queue_processing.acquire(blocking=False): - logger.trace_if("plugin.eddn.send", "Couldn't obtain mutex") + if self.queue_processing.acquire(blocking=False): + logger.trace_if("plugin.eddn.send", "Obtained mutex") + + have_rescheduled = False + if reschedule: logger.trace_if("plugin.eddn.send", f"Next run scheduled for {self.eddn.REPLAY_PERIOD}ms from now") self.eddn.parent.after(self.eddn.REPLAY_PERIOD, self.queue_check_and_send, reschedule) + have_rescheduled = True - else: - logger.trace_if("plugin.eddn.send", "NO next run scheduled (there should be another one already set)") + logger.trace_if("plugin.eddn.send", "Mutex released") + self.queue_processing.release() + else: + logger.trace_if("plugin.eddn.send", "Couldn't obtain mutex") - return + if not reschedule: + logger.trace_if("plugin.eddn.send", "NO next run scheduled (there should be another one already set)") - logger.trace_if("plugin.eddn.send", "Obtained mutex") - # Used to indicate if we've rescheduled at the faster rate already. - have_rescheduled = False # We send either if docked or 'Delay sending until docked' not set if this.docked or not config.get_int('output') & config.OUT_EDDN_DELAY: logger.trace_if("plugin.eddn.send", "Should send") @@ -517,7 +517,7 @@ def queue_check_and_send(self, reschedule: bool = False) -> None: # noqa: CCR00 db_cursor.execute( """ SELECT id FROM messages - ORDER BY created ASC + ORDER BY created LIMIT 1 """ ) @@ -587,16 +587,15 @@ def http_error_to_log(exception: requests.exceptions.HTTPError) -> str: # LANG: EDDN has banned this version of our client return _('EDDN Error: EDMC is too old for EDDN. Please update.') - elif status_code == 400: + if status_code == 400: # we a validation check or something else. logger.warning(f'EDDN Error: {status_code} -- {exception.response}') # LANG: EDDN returned an error that indicates something about what we sent it was wrong return _('EDDN Error: Validation Failed (EDMC Too Old?). See Log') - else: - logger.warning(f'Unknown status code from EDDN: {status_code} -- {exception.response}') - # LANG: EDDN returned some sort of HTTP error, one we didn't expect. {STATUS} contains a number - return _('EDDN Error: Returned {STATUS} status code').format(STATUS=status_code) + logger.warning(f'Unknown status code from EDDN: {status_code} -- {exception.response}') + # LANG: EDDN returned some sort of HTTP error, one we didn't expect. {STATUS} contains a number + return _('EDDN Error: Returned {STATUS} status code').format(STATUS=status_code) # TODO: a good few of these methods are static or could be classmethods. they should be created as such. @@ -1124,8 +1123,7 @@ def entry_augment_system_data( logger.warning(f'No system name in entry, and system_name was not set either! entry:\n{entry!r}\n') return "passed-in system_name is empty, can't add System" - else: - entry['StarSystem'] = system_name + entry['StarSystem'] = system_name if 'SystemAddress' not in entry: if this.system_address is None: @@ -1919,7 +1917,7 @@ def capi_gameversion_from_host_endpoint(self, capi_host: Optional[str], capi_end gv = '' ####################################################################### # Base string - if capi_host == companion.SERVER_LIVE or capi_host == companion.SERVER_BETA: + if capi_host in (companion.SERVER_LIVE, companion.SERVER_BETA): gv = 'CAPI-Live-' elif capi_host == companion.SERVER_LEGACY: @@ -2168,7 +2166,7 @@ def prefsvarchanged(event=None) -> None: this.eddn_system_button['state'] = tk.NORMAL # This line will grey out the 'Delay sending ...' option if the 'Send # system and scan data' option is off. - this.eddn_delay_button['state'] = this.eddn_system.get() and tk.NORMAL or tk.DISABLED + this.eddn_delay_button['state'] = tk.NORMAL if this.eddn_system.get() else tk.DISABLED def prefs_changed(cmdr: str, is_beta: bool) -> None: @@ -2325,22 +2323,22 @@ def journal_entry( # noqa: C901, CCR001 if event_name == 'fssdiscoveryscan': return this.eddn.export_journal_fssdiscoveryscan(cmdr, system, state['StarPos'], is_beta, entry) - elif event_name == 'navbeaconscan': + if event_name == 'navbeaconscan': return this.eddn.export_journal_navbeaconscan(cmdr, system, state['StarPos'], is_beta, entry) - elif event_name == 'codexentry': + if event_name == 'codexentry': return this.eddn.export_journal_codexentry(cmdr, state['StarPos'], is_beta, entry) - elif event_name == 'scanbarycentre': + if event_name == 'scanbarycentre': return this.eddn.export_journal_scanbarycentre(cmdr, state['StarPos'], is_beta, entry) - elif event_name == 'navroute': + if event_name == 'navroute': return this.eddn.export_journal_navroute(cmdr, is_beta, entry) - elif event_name == 'fcmaterials': + if event_name == 'fcmaterials': return this.eddn.export_journal_fcmaterials(cmdr, is_beta, entry) - elif event_name == 'approachsettlement': + if event_name == 'approachsettlement': # An `ApproachSettlement` can appear *before* `Location` if you # logged at one. We won't have necessary augmentation data # at this point, so bail. @@ -2355,10 +2353,10 @@ def journal_entry( # noqa: C901, CCR001 entry ) - elif event_name == 'fsssignaldiscovered': + if event_name == 'fsssignaldiscovered': this.eddn.enqueue_journal_fsssignaldiscovered(entry) - elif event_name == 'fssallbodiesfound': + if event_name == 'fssallbodiesfound': return this.eddn.export_journal_fssallbodiesfound( cmdr, system, @@ -2367,7 +2365,7 @@ def journal_entry( # noqa: C901, CCR001 entry ) - elif event_name == 'fssbodysignals': + if event_name == 'fssbodysignals': return this.eddn.export_journal_fssbodysignals( cmdr, system, diff --git a/plugins/edsm.py b/plugins/edsm.py index add21c5f1..84c83bf64 100644 --- a/plugins/edsm.py +++ b/plugins/edsm.py @@ -1,4 +1,10 @@ -"""Show EDSM data in display and handle lookups.""" +""" +edsm.py - Handling EDSM Data and Display. + +Copyright (c) EDCD, All Rights Reserved +Licensed under the GNU General Public License. +See LICENSE file. +""" from __future__ import annotations # TODO: @@ -297,8 +303,8 @@ def plugin_prefs(parent: ttk.Notebook, cmdr: str | None, is_beta: bool) -> tk.Fr :return: An instance of `myNotebook.Frame`. """ PADX = 10 # noqa: N806 - BUTTONX = 12 # indent Checkbuttons and Radiobuttons # noqa: N806 - PADY = 2 # close spacing # noqa: N806 + BUTTONX = 12 # noqa: N806 + PADY = 2 # noqa: N806 frame = nb.Frame(parent) frame.columnconfigure(1, weight=1) @@ -309,63 +315,62 @@ def plugin_prefs(parent: ttk.Notebook, cmdr: str | None, is_beta: bool) -> tk.Fr background=nb.Label().cget('background'), url='https://www.edsm.net/', underline=True - ).grid(columnspan=2, padx=PADX, sticky=tk.W) # Don't translate + ).grid(columnspan=2, padx=PADX, sticky=tk.W) this.log = tk.IntVar(value=config.get_int('edsm_out') and 1) this.log_button = nb.Checkbutton( - # LANG: Settings>EDSM - Label on checkbox for 'send data' - frame, text=_('Send flight log and Cmdr status to EDSM'), variable=this.log, command=prefsvarchanged + frame, + text=_('Send flight log and Cmdr status to EDSM'), + variable=this.log, + command=prefsvarchanged ) - if this.log_button: this.log_button.grid(columnspan=2, padx=BUTTONX, pady=(5, 0), sticky=tk.W) nb.Label(frame).grid(sticky=tk.W) # big spacer - # Section heading in settings + this.label = HyperlinkLabel( frame, - # LANG: Settings>EDSM - Label on header/URL to EDSM API key page text=_('Elite Dangerous Star Map credentials'), background=nb.Label().cget('background'), url='https://www.edsm.net/settings/api', underline=True ) - cur_row = 10 - if this.label: this.label.grid(columnspan=2, padx=PADX, sticky=tk.W) - # LANG: Game Commander name label in EDSM settings - this.cmdr_label = nb.Label(frame, text=_('Cmdr')) # Main window + this.cmdr_label = nb.Label(frame, text=_('Cmdr')) this.cmdr_label.grid(row=cur_row, padx=PADX, sticky=tk.W) + this.cmdr_text = nb.Label(frame) this.cmdr_text.grid(row=cur_row, column=1, padx=PADX, pady=PADY, sticky=tk.W) cur_row += 1 - # LANG: EDSM Commander name label in EDSM settings - this.user_label = nb.Label(frame, text=_('Commander Name')) # EDSM setting + this.user_label = nb.Label(frame, text=_('Commander Name')) this.user_label.grid(row=cur_row, padx=PADX, sticky=tk.W) + this.user = nb.Entry(frame) this.user.grid(row=cur_row, column=1, padx=PADX, pady=PADY, sticky=tk.EW) cur_row += 1 - # LANG: EDSM API key label - this.apikey_label = nb.Label(frame, text=_('API Key')) # EDSM setting + this.apikey_label = nb.Label(frame, text=_('API Key')) this.apikey_label.grid(row=cur_row, padx=PADX, sticky=tk.W) + this.apikey = nb.Entry(frame, show="*", width=50) this.apikey.grid(row=cur_row, column=1, padx=PADX, pady=PADY, sticky=tk.EW) prefs_cmdr_changed(cmdr, is_beta) show_password_var.set(False) # Password is initially masked + show_password_checkbox = nb.Checkbutton( frame, text="Show API Key", variable=show_password_var, - command=toggle_password_visibility, + command=toggle_password_visibility ) show_password_checkbox.grid(columnspan=2, padx=BUTTONX, pady=(5, 0), sticky=tk.W) @@ -430,17 +435,20 @@ def set_prefs_ui_states(state: str) -> None: :param state: the state to set each entry to """ - if ( - this.label and this.cmdr_label and this.cmdr_text and this.user_label and this.user - and this.apikey_label and this.apikey - ): - this.label['state'] = state - this.cmdr_label['state'] = state - this.cmdr_text['state'] = state - this.user_label['state'] = state - this.user['state'] = state - this.apikey_label['state'] = state - this.apikey['state'] = state + elements = [ + this.label, + this.cmdr_label, + this.cmdr_text, + this.user_label, + this.user, + this.apikey_label, + this.apikey + ] + + for element in elements: + if element: + element['state'] = state + def prefs_changed(cmdr: str, is_beta: bool) -> None: @@ -454,7 +462,6 @@ def prefs_changed(cmdr: str, is_beta: bool) -> None: config.set('edsm_out', this.log.get()) if cmdr and not is_beta: - # TODO: remove this when config is rewritten. cmdrs: List[str] = config.get_list('edsm_cmdrs', default=[]) usernames: List[str] = config.get_list('edsm_usernames', default=[]) apikeys: List[str] = config.get_list('edsm_apikeys', default=[]) @@ -495,16 +502,13 @@ def credentials(cmdr: str) -> Optional[Tuple[str, str]]: cmdrs = [cmdr] config.set('edsm_cmdrs', cmdrs) - if (cmdr in cmdrs and (edsm_usernames := config.get_list('edsm_usernames')) - and (edsm_apikeys := config.get_list('edsm_apikeys'))): - idx = cmdrs.index(cmdr) - # The EDSM cmdr and apikey might not exist yet! - if idx >= len(edsm_usernames) or idx >= len(edsm_apikeys): - return None - - logger.trace_if(CMDR_CREDS, f'{cmdr=}: returning ({edsm_usernames[idx]=}, {edsm_apikeys[idx]=})') + edsm_usernames = config.get_list('edsm_usernames') + edsm_apikeys = config.get_list('edsm_apikeys') - return edsm_usernames[idx], edsm_apikeys[idx] + if cmdr in cmdrs and len(cmdrs) == len(edsm_usernames) == len(edsm_apikeys): + idx = cmdrs.index(cmdr) + if idx < len(edsm_usernames) and idx < len(edsm_apikeys): + return edsm_usernames[idx], edsm_apikeys[idx] logger.trace_if(CMDR_CREDS, f'{cmdr=}: returning None') return None @@ -695,16 +699,13 @@ def cmdr_data(data: CAPIData, is_beta: bool) -> Optional[str]: # noqa: CCR001 if this.station_link: if data['commander']['docked'] or this.on_foot and this.station_name: this.station_link['text'] = this.station_name - elif data['lastStarport']['name'] and data['lastStarport']['name'] != "": this.station_link['text'] = STATION_UNDOCKED - else: this.station_link['text'] = '' # Do *NOT* set 'url' here, as it's set to a function that will call # through correctly. We don't want a static string. - this.station_link.update_idletasks() if this.system_link and not this.system_link['text']: @@ -721,13 +722,22 @@ def cmdr_data(data: CAPIData, is_beta: bool) -> Optional[str]: # noqa: CCR001 def get_discarded_events_list() -> None: - """Retrieve the list of to-discard events from EDSM.""" + """ + Retrieve the list of events to discard from EDSM. + + This function queries the EDSM API to obtain the list of events that should be discarded, + and stores them in the `discarded_events` attribute. + + :return: None + """ try: r = this.session.get('https://www.edsm.net/api-journal-v1/discard', timeout=_TIMEOUT) r.raise_for_status() this.discarded_events = set(r.json()) - this.discarded_events.discard('Docked') # should_send() assumes that we send 'Docked' events + # We discard 'Docked' events because should_send() assumes that we send them + this.discarded_events.discard('Docked') + if not this.discarded_events: logger.warning( 'Unexpected empty discarded events list from EDSM: ' @@ -735,16 +745,17 @@ def get_discarded_events_list() -> None: ) except Exception as e: - logger.warning('Exception whilst trying to set this.discarded_events:', exc_info=e) + logger.warning('Exception while trying to set this.discarded_events:', exc_info=e) -def worker() -> None: # noqa: CCR001 C901 # Cant be broken up currently +def worker() -> None: # noqa: CCR001 C901 """ Handle uploading events to EDSM API. - Target function of a thread. + This function is the target function of a thread. It processes events from the queue until the + queued item is None, uploading the events to the EDSM API. - Processes `this.queue` until the queued item is None. + :return: None """ logger.debug('Starting...') pending: List[Mapping[str, Any]] = [] # Unsent events @@ -779,7 +790,7 @@ def worker() -> None: # noqa: CCR001 C901 # Cant be broken up currently else: logger.debug('Empty queue message, setting closing = True') closing = True # Try to send any unsent events before we close - entry = {'event': 'ShutDown'} # Dummy to allow for `uentry['event']` belowt + entry = {'event': 'ShutDown'} # Dummy to allow for `entry['event']` below retrying = 0 while retrying < 3: @@ -842,7 +853,7 @@ def worker() -> None: # noqa: CCR001 C901 # Cant be broken up currently if p['event'] in 'Location': logger.trace_if( 'journal.locations', - f'"Location" event in pending passed should_send(),timestamp: {p["timestamp"]}' + f'"Location" event in pending passed should_send(), timestamp: {p["timestamp"]}' ) creds = credentials(cmdr) @@ -964,54 +975,42 @@ def should_send(entries: List[Mapping[str, Any]], event: str) -> bool: # noqa: :param event: The latest event being processed :return: bool indicating whether or not to send said entries """ - # We MUST flush pending on logout, in case new login is a different Commander + def should_send_entry(entry: Mapping[str, Any]) -> bool: + if entry['event'] == 'Cargo': + return not this.newgame_docked + if entry['event'] == 'Docked': + return True + if this.newgame: + return True + if entry['event'] not in ( + 'CommunityGoal', + 'ModuleBuy', + 'ModuleSell', + 'ModuleSwap', + 'ShipyardBuy', + 'ShipyardNew', + 'ShipyardSwap' + ): + return True + return False + if event.lower() in ('shutdown', 'fileheader'): logger.trace_if(CMDR_EVENTS, f'True because {event=}') - return True - # batch up burst of Scan events after NavBeaconScan if this.navbeaconscan: if entries and entries[-1]['event'] == 'Scan': this.navbeaconscan -= 1 - if this.navbeaconscan: - logger.trace_if(CMDR_EVENTS, f'False because {this.navbeaconscan=}') - - return False - - else: - logger.error( - 'Invalid state NavBeaconScan exists, but passed entries either ' - "doesn't exist or doesn't have the expected content" - ) - this.navbeaconscan = 0 - - for entry in entries: - if (entry['event'] == 'Cargo' and not this.newgame_docked) or entry['event'] == 'Docked': - # Cargo is the last event on startup, unless starting when docked in which case Docked is the last event - this.newgame = False - this.newgame_docked = False - logger.trace_if(CMDR_EVENTS, f'True because {entry["event"]=}') - - return True - - if this.newgame: - pass - - elif entry['event'] not in ( - 'CommunityGoal', # Spammed periodically - 'ModuleBuy', 'ModuleSell', 'ModuleSwap', # will be shortly followed by "Loadout" - 'ShipyardBuy', 'ShipyardNew', 'ShipyardSwap'): # " - logger.trace_if(CMDR_EVENTS, f'True because {entry["event"]=}') - - return True - - else: - logger.trace_if(CMDR_EVENTS, f'{entry["event"]=}, {this.newgame_docked=}') - - logger.trace_if(CMDR_EVENTS, f'False as default: {this.newgame_docked=}') + should_send_result = this.navbeaconscan == 0 + logger.trace_if(CMDR_EVENTS, f'False because {this.navbeaconscan=}' if not should_send_result else '') + return should_send_result + logger.error('Invalid state NavBeaconScan exists, but passed entries either ' + "doesn't exist or doesn't have the expected content") + this.navbeaconscan = 0 - return False + should_send_result = any(should_send_entry(entry) for entry in entries) + logger.trace_if(CMDR_EVENTS, f'False as default: {this.newgame_docked=}' if not should_send_result else '') + return should_send_result def update_status(event=None) -> None: diff --git a/plugins/edsy.py b/plugins/edsy.py index 17b16ef0f..a02d34248 100644 --- a/plugins/edsy.py +++ b/plugins/edsy.py @@ -1,27 +1,25 @@ -"""Export data for ED Shipyard.""" - -# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# -# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# -# -# This is an EDMC 'core' plugin. -# -# All EDMC plugins are *dynamically* loaded at run-time. -# -# We build for Windows using `py2exe`. -# -# `py2exe` can't possibly know about anything in the dynamically loaded -# core plugins. -# -# Thus you **MUST** check if any imports you add in this file are only -# referenced in this file (or only in any other core plugin), and if so... -# -# YOU MUST ENSURE THAT PERTINENT ADJUSTMENTS ARE MADE IN -# `build.py` SO AS TO ENSURE THE FILES ARE ACTUALLY PRESENT IN -# AN END-USER INSTALLATION ON WINDOWS. -# -# -# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# -# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# ! $# +""" +edsy.py - Exporting Data to EDSY. + +Copyright (c) EDCD, All Rights Reserved +Licensed under the GNU General Public License. +See LICENSE file. + +This is an EDMC 'core' plugin. +All EDMC plugins are *dynamically* loaded at run-time. + +We build for Windows using `py2exe`. +`py2exe` can't possibly know about anything in the dynamically loaded core plugins. + +Thus, you **MUST** check if any imports you add in this file are only +referenced in this file (or only in any other core plugin), and if so... + + YOU MUST ENSURE THAT PERTINENT ADJUSTMENTS ARE MADE IN + `build.py` TO ENSURE THE FILES ARE ACTUALLY PRESENT + IN AN END-USER INSTALLATION ON WINDOWS. +""" +from __future__ import annotations + import base64 import gzip import io @@ -40,15 +38,15 @@ def plugin_start3(plugin_dir: str) -> str: # Return a URL for the current ship -def shipyard_url(loadout: Mapping[str, Any], is_beta) -> bool | str: +def shipyard_url(loadout: Mapping[str, Any], is_beta: bool) -> bool | str: """ Construct a URL for ship loadout. - :param loadout: - :param is_beta: - :return: + :param loadout: The ship loadout data. + :param is_beta: Whether the game is in beta. + :return: The constructed URL for the ship loadout. """ - # most compact representation + # Convert loadout to JSON and gzip compress it string = json.dumps(loadout, ensure_ascii=False, sort_keys=True, separators=(',', ':')).encode('utf-8') if not string: return False @@ -57,6 +55,8 @@ def shipyard_url(loadout: Mapping[str, Any], is_beta) -> bool | str: with gzip.GzipFile(fileobj=out, mode='w') as f: f.write(string) - return ( - is_beta and 'http://edsy.org/beta/#/I=' or 'http://edsy.org/#/I=' - ) + base64.urlsafe_b64encode(out.getvalue()).decode().replace('=', '%3D') + # Construct the URL using the appropriate base URL based on is_beta + base_url = 'https://edsy.org/beta/#/I=' if is_beta else 'https://edsy.org/#/I=' + encoded_data = base64.urlsafe_b64encode(out.getvalue()).decode().replace('=', '%3D') + + return base_url + encoded_data