1
0
mirror of https://github.com/EDCD/EDMarketConnector.git synced 2025-06-15 14:52:15 +03:00

Merge tag 'Release/4.0.4' into releases

Release 4.0.4
This commit is contained in:
Athanasius 2020-08-02 20:20:04 +01:00
commit 405edfacb6
29 changed files with 211 additions and 87 deletions

View File

@ -1,6 +1,26 @@
This is the master changelog for Elite Dangerous Market Connector. Entries are in reverse chronological order (latest first). This is the master changelog for Elite Dangerous Market Connector. Entries are in reverse chronological order (latest first).
--- ---
Release 4.0.4
===
* Built using Python 3.7.8. Prior 4.0.x releases used 3.7.7.
* Don't crash if no non-default Journal Directory has been set.
* Only send to Inara API at most once every 30 seconds. This should avoid
the "Inara 400 Too much requests, slow down, cowboy. ;) ..." message and
being locked out from the API for an hour as a result. Any events that
require data to be sent during the 30s cooldown will be queued and sent when
that timer expires.
This was caused by previous changes in an attempt to send cargo events
to Inara more often. This fix retains that enhancement.
Note that if you log out and stop EDMC within 30 seconds you might have
some events not sent. If we tried to force a send then it might hit the
limit when you want to log back in and continue playing. As it is you can
re-run EDMC and log back into the game to ensure Inara is synchronised
properly.
Release 4.0.3 Release 4.0.3
=== ===

View File

@ -235,7 +235,7 @@
/* Appearance setting prompt. [prefs.py] */ /* Appearance setting prompt. [prefs.py] */
"Language" = "Jazyk"; "Language" = "Jazyk";
/* [EDMarketConnector.py] */ /* [EDMarketConnector.py] - Leave '{HH}:{MM}:{SS}' as-is */
"Last updated at {HH}:{MM}:{SS}" = "Poslední aktualizace {HH}:{MM}:{SS}"; "Last updated at {HH}:{MM}:{SS}" = "Poslední aktualizace {HH}:{MM}:{SS}";
/* Federation rank. [stats.py] */ /* Federation rank. [stats.py] */

View File

@ -235,7 +235,7 @@
/* Appearance setting prompt. [prefs.py] */ /* Appearance setting prompt. [prefs.py] */
"Language" = "Sprache"; "Language" = "Sprache";
/* [EDMarketConnector.py] */ /* [EDMarketConnector.py] - Leave '{HH}:{MM}:{SS}' as-is */
"Last updated at {HH}:{MM}:{SS}" = "Zuletzt aktualisiert um {HH}:{MM}:{SS}"; "Last updated at {HH}:{MM}:{SS}" = "Zuletzt aktualisiert um {HH}:{MM}:{SS}";
/* Federation rank. [stats.py] */ /* Federation rank. [stats.py] */

View File

@ -490,6 +490,9 @@
/* Update button in main window. [EDMarketConnector.py] */ /* Update button in main window. [EDMarketConnector.py] */
"Update" = "Update"; "Update" = "Update";
/* Option to use alternate URL method on shipyard links [prefs.py] */
"Use alternate URL method" = "Use alternate URL method";
/* Status dialog subtitle - CR value of ship. [stats.py] */ /* Status dialog subtitle - CR value of ship. [stats.py] */
"Value" = "Value"; "Value" = "Value";

View File

@ -235,7 +235,7 @@
/* Appearance setting prompt. [prefs.py] */ /* Appearance setting prompt. [prefs.py] */
"Language" = "Idioma"; "Language" = "Idioma";
/* [EDMarketConnector.py] */ /* [EDMarketConnector.py] - Leave '{HH}:{MM}:{SS}' as-is */
"Last updated at {HH}:{MM}:{SS}" = "Última actualización: {HH}:{MM}:{SS}"; "Last updated at {HH}:{MM}:{SS}" = "Última actualización: {HH}:{MM}:{SS}";
/* Federation rank. [stats.py] */ /* Federation rank. [stats.py] */

View File

@ -235,7 +235,7 @@
/* Appearance setting prompt. [prefs.py] */ /* Appearance setting prompt. [prefs.py] */
"Language" = "Kieli"; "Language" = "Kieli";
/* [EDMarketConnector.py] */ /* [EDMarketConnector.py] - Leave '{HH}:{MM}:{SS}' as-is */
"Last updated at {HH}:{MM}:{SS}" = "Päivitetty viimeksi {HH}:{MM}:{SS}"; "Last updated at {HH}:{MM}:{SS}" = "Päivitetty viimeksi {HH}:{MM}:{SS}";
/* Federation rank. [stats.py] */ /* Federation rank. [stats.py] */

View File

@ -235,7 +235,7 @@
/* Appearance setting prompt. [prefs.py] */ /* Appearance setting prompt. [prefs.py] */
"Language" = "Langue"; "Language" = "Langue";
/* [EDMarketConnector.py] */ /* [EDMarketConnector.py] - Leave '{HH}:{MM}:{SS}' as-is */
"Last updated at {HH}:{MM}:{SS}" = "Dernière mise à jour à {HH}:{MM}:{SS}"; "Last updated at {HH}:{MM}:{SS}" = "Dernière mise à jour à {HH}:{MM}:{SS}";
/* Federation rank. [stats.py] */ /* Federation rank. [stats.py] */

View File

@ -232,7 +232,7 @@
/* Appearance setting prompt. [prefs.py] */ /* Appearance setting prompt. [prefs.py] */
"Language" = "Nyelv"; "Language" = "Nyelv";
/* [EDMarketConnector.py] */ /* [EDMarketConnector.py] - Leave '{HH}:{MM}:{SS}' as-is */
"Last updated at {HH}:{MM}:{SS}" = "Utoljára frissítve {HH}:{MM}:{SS}"; "Last updated at {HH}:{MM}:{SS}" = "Utoljára frissítve {HH}:{MM}:{SS}";
/* Federation rank. [stats.py] */ /* Federation rank. [stats.py] */

View File

@ -235,7 +235,7 @@
/* Appearance setting prompt. [prefs.py] */ /* Appearance setting prompt. [prefs.py] */
"Language" = "Lingua"; "Language" = "Lingua";
/* [EDMarketConnector.py] */ /* [EDMarketConnector.py] - Leave '{HH}:{MM}:{SS}' as-is */
"Last updated at {HH}:{MM}:{SS}" = "Ultimo aggiornamento alle {HH}:{MM}:{SS}"; "Last updated at {HH}:{MM}:{SS}" = "Ultimo aggiornamento alle {HH}:{MM}:{SS}";
/* Federation rank. [stats.py] */ /* Federation rank. [stats.py] */

View File

@ -235,7 +235,7 @@
/* Appearance setting prompt. [prefs.py] */ /* Appearance setting prompt. [prefs.py] */
"Language" = "言語"; "Language" = "言語";
/* [EDMarketConnector.py] */ /* [EDMarketConnector.py] - Leave '{HH}:{MM}:{SS}' as-is */
"Last updated at {HH}:{MM}:{SS}" = "最終更新時間 {HH}:{MM}:{SS}"; "Last updated at {HH}:{MM}:{SS}" = "最終更新時間 {HH}:{MM}:{SS}";
/* Federation rank. [stats.py] */ /* Federation rank. [stats.py] */

View File

@ -217,7 +217,7 @@
/* Appearance setting prompt. [prefs.py] */ /* Appearance setting prompt. [prefs.py] */
"Language" = "Valoda"; "Language" = "Valoda";
/* [EDMarketConnector.py] */ /* [EDMarketConnector.py] - Leave '{HH}:{MM}:{SS}' as-is */
"Last updated at {HH}:{MM}:{SS}" = "Pēdējo reizi atjaunināts {HH}:{MM}:{SS}"; "Last updated at {HH}:{MM}:{SS}" = "Pēdējo reizi atjaunināts {HH}:{MM}:{SS}";
/* Federation rank. [stats.py] */ /* Federation rank. [stats.py] */

View File

@ -235,7 +235,7 @@
/* Appearance setting prompt. [prefs.py] */ /* Appearance setting prompt. [prefs.py] */
"Language" = "Taal"; "Language" = "Taal";
/* [EDMarketConnector.py] */ /* [EDMarketConnector.py] - Leave '{HH}:{MM}:{SS}' as-is */
"Last updated at {HH}:{MM}:{SS}" = "Voor het laatst bijgewerkt om {HH}:{MM}:{SS}"; "Last updated at {HH}:{MM}:{SS}" = "Voor het laatst bijgewerkt om {HH}:{MM}:{SS}";
/* Federation rank. [stats.py] */ /* Federation rank. [stats.py] */
@ -490,6 +490,9 @@
/* Update button in main window. [EDMarketConnector.py] */ /* Update button in main window. [EDMarketConnector.py] */
"Update" = "Bijwerken"; "Update" = "Bijwerken";
/* Option to use alternate URL method on shipyard links [prefs.py] */
"Use alternate URL method" = "Gebruik andere URL methode";
/* Status dialog subtitle - CR value of ship. [stats.py] */ /* Status dialog subtitle - CR value of ship. [stats.py] */
"Value" = "Waarde"; "Value" = "Waarde";

View File

@ -235,7 +235,7 @@
/* Appearance setting prompt. [prefs.py] */ /* Appearance setting prompt. [prefs.py] */
"Language" = "Język"; "Language" = "Język";
/* [EDMarketConnector.py] */ /* [EDMarketConnector.py] - Leave '{HH}:{MM}:{SS}' as-is */
"Last updated at {HH}:{MM}:{SS}" = "Ostatnia aktualizacja {HH}:{MM}:{SS}"; "Last updated at {HH}:{MM}:{SS}" = "Ostatnia aktualizacja {HH}:{MM}:{SS}";
/* Federation rank. [stats.py] */ /* Federation rank. [stats.py] */

View File

@ -235,7 +235,7 @@
/* Appearance setting prompt. [prefs.py] */ /* Appearance setting prompt. [prefs.py] */
"Language" = "Idioma"; "Language" = "Idioma";
/* [EDMarketConnector.py] */ /* [EDMarketConnector.py] - Leave '{HH}:{MM}:{SS}' as-is */
"Last updated at {HH}:{MM}:{SS}" = "Última atualização {HH}:{MM}:{SS}"; "Last updated at {HH}:{MM}:{SS}" = "Última atualização {HH}:{MM}:{SS}";
/* Federation rank. [stats.py] */ /* Federation rank. [stats.py] */

View File

@ -235,7 +235,7 @@
/* Appearance setting prompt. [prefs.py] */ /* Appearance setting prompt. [prefs.py] */
"Language" = "Linguagem"; "Language" = "Linguagem";
/* [EDMarketConnector.py] */ /* [EDMarketConnector.py] - Leave '{HH}:{MM}:{SS}' as-is */
"Last updated at {HH}:{MM}:{SS}" = "Última actualização: {HH}:{MM}:{SS}"; "Last updated at {HH}:{MM}:{SS}" = "Última actualização: {HH}:{MM}:{SS}";
/* Federation rank. [stats.py] */ /* Federation rank. [stats.py] */

View File

@ -235,7 +235,7 @@
/* Appearance setting prompt. [prefs.py] */ /* Appearance setting prompt. [prefs.py] */
"Language" = "Язык"; "Language" = "Язык";
/* [EDMarketConnector.py] */ /* [EDMarketConnector.py] - Leave '{HH}:{MM}:{SS}' as-is */
"Last updated at {HH}:{MM}:{SS}" = "Последнее обновление в {HH}:{MM}:{SS}"; "Last updated at {HH}:{MM}:{SS}" = "Последнее обновление в {HH}:{MM}:{SS}";
/* Federation rank. [stats.py] */ /* Federation rank. [stats.py] */

View File

@ -184,7 +184,7 @@
/* Appearance setting prompt. [prefs.py] */ /* Appearance setting prompt. [prefs.py] */
"Language" = "Jezik"; "Language" = "Jezik";
/* [EDMarketConnector.py] */ /* [EDMarketConnector.py] - Leave '{HH}:{MM}:{SS}' as-is */
"Last updated at {HH}:{MM}:{SS}" = "Zadnja osvežitev podatkov {HH}:{MM}:{SS} "; "Last updated at {HH}:{MM}:{SS}" = "Zadnja osvežitev podatkov {HH}:{MM}:{SS} ";
/* Federation rank. [stats.py] */ /* Federation rank. [stats.py] */

View File

@ -235,7 +235,7 @@
/* Appearance setting prompt. [prefs.py] */ /* Appearance setting prompt. [prefs.py] */
"Language" = "Jezik"; "Language" = "Jezik";
/* [EDMarketConnector.py] */ /* [EDMarketConnector.py] - Leave '{HH}:{MM}:{SS}' as-is */
"Last updated at {HH}:{MM}:{SS}" = "Posljednji put osvježeno {HH}:{MM}:{SS}"; "Last updated at {HH}:{MM}:{SS}" = "Posljednji put osvježeno {HH}:{MM}:{SS}";
/* Federation rank. [stats.py] */ /* Federation rank. [stats.py] */

View File

@ -235,7 +235,7 @@
/* Appearance setting prompt. [prefs.py] */ /* Appearance setting prompt. [prefs.py] */
"Language" = "Jezik"; "Language" = "Jezik";
/* [EDMarketConnector.py] */ /* [EDMarketConnector.py] - Leave '{HH}:{MM}:{SS}' as-is */
"Last updated at {HH}:{MM}:{SS}" = "Poslednji put osveženo {HH}:{MM}:{SS}"; "Last updated at {HH}:{MM}:{SS}" = "Poslednji put osveženo {HH}:{MM}:{SS}";
/* Federation rank. [stats.py] */ /* Federation rank. [stats.py] */

View File

@ -235,7 +235,7 @@
/* Appearance setting prompt. [prefs.py] */ /* Appearance setting prompt. [prefs.py] */
"Language" = "Språk"; "Language" = "Språk";
/* [EDMarketConnector.py] */ /* [EDMarketConnector.py] - Leave '{HH}:{MM}:{SS}' as-is */
"Last updated at {HH}:{MM}:{SS}" = "Senaste uppdatering: {HH}:{MM}:{SS}"; "Last updated at {HH}:{MM}:{SS}" = "Senaste uppdatering: {HH}:{MM}:{SS}";
/* Federation rank. [stats.py] */ /* Federation rank. [stats.py] */

View File

@ -235,7 +235,7 @@
/* Appearance setting prompt. [prefs.py] */ /* Appearance setting prompt. [prefs.py] */
"Language" = "Мова"; "Language" = "Мова";
/* [EDMarketConnector.py] */ /* [EDMarketConnector.py] - Leave '{HH}:{MM}:{SS}' as-is */
"Last updated at {HH}:{MM}:{SS}" = "Останнє оновлення було {HH}:{MM}:{SS}"; "Last updated at {HH}:{MM}:{SS}" = "Останнє оновлення було {HH}:{MM}:{SS}";
/* Federation rank. [stats.py] */ /* Federation rank. [stats.py] */
@ -490,6 +490,9 @@
/* Update button in main window. [EDMarketConnector.py] */ /* Update button in main window. [EDMarketConnector.py] */
"Update" = "Оновлення"; "Update" = "Оновлення";
/* Option to use alternate URL method on shipyard links [prefs.py] */
"Use alternate URL method" = "Використовувати альтернативний URL-метод";
/* Status dialog subtitle - CR value of ship. [stats.py] */ /* Status dialog subtitle - CR value of ship. [stats.py] */
"Value" = "Вартість"; "Value" = "Вартість";

View File

@ -232,7 +232,7 @@
/* Appearance setting prompt. [prefs.py] */ /* Appearance setting prompt. [prefs.py] */
"Language" = "语言"; "Language" = "语言";
/* [EDMarketConnector.py] */ /* [EDMarketConnector.py] - Leave '{HH}:{MM}:{SS}' as-is */
"Last updated at {HH}:{MM}:{SS}" = "最后更新于 {HH}:{MM}:{SS}"; "Last updated at {HH}:{MM}:{SS}" = "最后更新于 {HH}:{MM}:{SS}";
/* Federation rank. [stats.py] */ /* Federation rank. [stats.py] */

View File

@ -55,6 +55,72 @@ import myNotebook as nb
``` ```
For creating UI elements. For creating UI elements.
---
### Logging
Currently (still in 4.0.3) the only way to provide any logged output from a
plugin is to use `print(...)` statements. When running the application from
the packaged executeable all output is redirected to a log file. See
[Reporting a problem](https://github.com/EDCD/EDMarketConnector/wiki/Troubleshooting#reporting-a-problem)
for the location of this log file.
A future version of EDMC will implement proper logging using the Python
`logging` module. Plugin developers should get their code ready for this by
using the following code instead of simple `print(...)` statements
Insert this at the top-level of your load.py file (so not inside
`plugin_start3()`):
```python
import logging
from config import appname
# This could also be returned from plugin_start3()
plugin_name = os.path.basename(os.path.dirname(__file__))
# A Logger is used per 'found' plugin to make it easy to include the plugin's
# folder name in the logging output format.
logger = logging.getLogger(f'{appname}.{plugin_name}')
# If the Logger has handlers then it was already set up by the core code, else
# it needs setting up here.
if not logger.hasHandlers():
level = logging.INFO # So logger.info(...) is equivalent to print()
logger.setLevel(level)
logger_channel = logging.StreamHandler()
logger_channel.setLevel(level)
logger_formatter = logging.Formatter(f'%(asctime)s - %(name)s - %(levelname)s - %(module)s:%(lineno)d:%(funcName)s: %(message)s')
logger_formatter.default_time_format = '%Y-%m-%d %H:%M:%S'
logger_formatter.default_msec_format = '%s.%03d'
logger_channel.setFormatter(logger_formatter)
logger.addHandler(logger_channel)
```
Then replace `print(...)` statements with one of the following:
```python
logger.info('some info message') # instead of print(...)
logger.debug('something only for debug')
logger.warning('Something needs warning about')
logger.error('Some error happened')
logger.critical('Something went wrong in a critical manner')
try:
...
except Exception:
# This logs at 'ERROR' level.
# Also automatically includes exception information.
logger.exception('An exception occurred')
try:
...
except Exception as e:
logger.debug('Exception we only note in debug output', exc_info=e)
```
--- ---
### Startup ### Startup
@ -363,6 +429,7 @@ If the player has chosen to "Send flight log and Cmdr status to Inara" this
gets called when the player starts the game, enters a new system, docks or gets called when the player starts the game, enters a new system, docks or
undocks. It is called some time after the corresponding `journal_entry()` undocks. It is called some time after the corresponding `journal_entry()`
event. event.
--- ---
```python ```python
def inara_notify_ship(eventData): def inara_notify_ship(eventData):

View File

@ -1,5 +1,6 @@
import numbers import numbers
import sys import sys
import warnings
from os import getenv, makedirs, mkdir, pardir from os import getenv, makedirs, mkdir, pardir
from os.path import expanduser, dirname, exists, isdir, join, normpath from os.path import expanduser, dirname, exists, isdir, join, normpath
from sys import platform from sys import platform
@ -12,7 +13,7 @@ appcmdname = 'EDMC'
# appversion **MUST** follow Semantic Versioning rules: # appversion **MUST** follow Semantic Versioning rules:
# <https://semver.org/#semantic-versioning-specification-semver> # <https://semver.org/#semantic-versioning-specification-semver>
# Major.Minor.Patch(-prerelease)(+buildmetadata) # Major.Minor.Patch(-prerelease)(+buildmetadata)
appversion = '4.0.3' #-rc1+a872b5f' appversion = '4.0.4' #-rc1+a872b5f'
# For some things we want appversion without (possible) +build metadata # For some things we want appversion without (possible) +build metadata
appversion_nobuild = str(semantic_version.Version(appversion).truncate('prerelease')) appversion_nobuild = str(semantic_version.Version(appversion).truncate('prerelease'))
copyright = u'© 2015-2019 Jonathan Harris, 2020 EDCD' copyright = u'© 2015-2019 Jonathan Harris, 2020 EDCD'
@ -367,25 +368,13 @@ class Config(object):
# Common # Common
def get_password(self, account): def get_password(self, account):
try: warnings.warn("password subsystem is no longer supported", DeprecationWarning)
import keyring
return keyring.get_password(self.identifier, account)
except ImportError:
return None
def set_password(self, account, password): def set_password(self, account, password):
try: warnings.warn("password subsystem is no longer supported", DeprecationWarning)
import keyring
keyring.set_password(self.identifier, account, password)
except ImportError:
pass
def delete_password(self, account): def delete_password(self, account):
try: warnings.warn("password subsystem is no longer supported", DeprecationWarning)
import keyring
keyring.delete_password(self.identifier, account)
except:
pass # don't care - silently fail
# singleton # singleton
config = Config() config = Config()

View File

@ -168,11 +168,36 @@
<!-- Windows --> <!-- Windows -->
<item> <item>
<title>Release 4.0.3</title> <title>Release 4.0.4</title>
<description> <description>
<![CDATA[ <![CDATA[
<style>body { font-family:"Segoe UI","Tahoma"; font-size: 75%; } h2 { font-family:"Segoe UI","Tahoma"; font-size: 105%; }</style> <style>body { font-family:"Segoe UI","Tahoma"; font-size: 75%; } h2 { font-family:"Segoe UI","Tahoma"; font-size: 105%; }</style>
<h2>Release 4.0.4</h2>
<ul>
<li>
<p>Built using Python 3.7.8. Prior 4.0.x releases used 3.7.7.</p>
</li>
<li>
<p>Don't crash if no non-default Journal Directory has been set.</p>
</li>
<li>
<p>Only send to Inara API at most once every 30 seconds. This should avoid
the "Inara 400 Too much requests, slow down, cowboy. ;) ..." message and
being locked out from the API for an hour as a result. Any events that
require data to be sent during the 30s cooldown will be queued and sent when
that timer expires.</p>
<p>This was caused by previous changes in an attempt to send cargo events
to Inara more often. This fix retains that enhancement.</p>
<p>Note that if you log out and stop EDMC within 30 seconds you might have
some events not sent. If we tried to force a send then it might hit the
limit when you want to log back in and continue playing. As it is you can
re-run EDMC and log back into the game to ensure Inara is synchronised
properly.</p>
</li>
</ul>
<h2>Release 4.0.3</h2> <h2>Release 4.0.3</h2>
<p><strong>NB: Anyone who installed a 4.0.3-rcX release candidate version should first <p><strong>NB: Anyone who installed a 4.0.3-rcX release candidate version should first
uninstall it before installing this.</strong> uninstall it before installing this.</strong>
@ -578,11 +603,11 @@ If any of your plugins are listed in that section then they will need updating,
]]> ]]>
</description> </description>
<enclosure <enclosure
url="https://github.com/EDCD/EDMarketConnector/releases/download/Release/4.0.3/EDMarketConnector_win_4.0.3.msi" url="https://github.com/EDCD/EDMarketConnector/releases/download/Release/4.0.4/EDMarketConnector_win_4.0.4.msi"
sparkle:os="windows" sparkle:os="windows"
sparkle:installerArguments="/passive LAUNCH=yes" sparkle:installerArguments="/passive LAUNCH=yes"
sparkle:version="4.0.3" sparkle:version="4.0.4"
length="11325440" length="11419648"
type="application/octet-stream" type="application/octet-stream"
/> />
</item> </item>

View File

@ -118,9 +118,14 @@ class EDLogs(FileSystemEventHandler):
def start(self, root): def start(self, root):
self.root = root self.root = root
logdir = expanduser(config.get('journaldir') or config.default_journal_dir) # type: ignore # config is weird journal_dir = config.get('journaldir') or config.default_journal_dir
if not logdir or not isdir(logdir): # type: ignore # config does weird things in its get if journal_dir is None:
journal_dir = ''
logdir = expanduser(journal_dir) # type: ignore # config is weird
if not logdir or not isdir(logdir):
self.stop() self.stop()
return False return False

View File

@ -21,7 +21,6 @@ import plug
if __debug__: if __debug__:
from traceback import print_exc from traceback import print_exc
_TIMEOUT = 20 _TIMEOUT = 20
FAKE = ['CQC', 'Training', 'Destination'] # Fake systems that shouldn't be sent to Inara FAKE = ['CQC', 'Training', 'Destination'] # Fake systems that shouldn't be sent to Inara
CREDIT_RATIO = 1.05 # Update credits if they change by 5% over the course of a session CREDIT_RATIO = 1.05 # Update credits if they change by 5% over the course of a session
@ -50,8 +49,11 @@ this.loadout = None
this.fleet = None this.fleet = None
this.shipswap = False # just swapped ship this.shipswap = False # just swapped ship
this.last_update_time = time.time() # last time we updated (set to now because we're going to update quickly) # last time we updated, if unset in config this is 0, which means an instant update
FLOOD_LIMIT_SECONDS = 45 # minimum time between sending non-major cargo triggered messages LAST_UPDATE_CONF_KEY = 'inara_last_update'
# this.last_update_time = config.getint(LAST_UPDATE_CONF_KEY)
FLOOD_LIMIT_SECONDS = 30 # minimum time between sending events
this.timer_run = True
# Main window clicks # Main window clicks
@ -86,6 +88,10 @@ def plugin_start3(plugin_dir):
this.thread = Thread(target = worker, name = 'Inara worker') this.thread = Thread(target = worker, name = 'Inara worker')
this.thread.daemon = True this.thread.daemon = True
this.thread.start() this.thread.start()
this.timer_thread = Thread(target=call_timer, name='Inara timer')
this.timer_thread.daemon = True
this.timer_thread.start()
return 'Inara' return 'Inara'
def plugin_app(parent): def plugin_app(parent):
@ -97,11 +103,14 @@ def plugin_app(parent):
def plugin_stop(): def plugin_stop():
# Send any unsent events # Send any unsent events
call() call()
time.sleep(0.1) # Sleep for 100ms to allow call to go out, and to force a context switch to our other threads
# Signal thread to close and wait for it # Signal thread to close and wait for it
this.queue.put(None) this.queue.put(None)
this.thread.join() this.thread.join()
this.thread = None this.thread = None
this.timer_run = False
def plugin_prefs(parent, cmdr, is_beta): def plugin_prefs(parent, cmdr, is_beta):
PADX = 10 PADX = 10
@ -189,7 +198,7 @@ def journal_entry(cmdr, is_beta, system, station, entry, state):
# Send any unsent events when switching accounts # Send any unsent events when switching accounts
if cmdr and cmdr != this.cmdr: if cmdr and cmdr != this.cmdr:
call() call(force=True)
this.cmdr = cmdr this.cmdr = cmdr
this.FID = state['FID'] this.FID = state['FID']
@ -246,8 +255,6 @@ def journal_entry(cmdr, is_beta, system, station, entry, state):
if config.getint('inara_out') and not is_beta and not this.multicrew and credentials(cmdr): if config.getint('inara_out') and not is_beta and not this.multicrew and credentials(cmdr):
try: try:
old_events = len(this.events) # Will only send existing events if we add a new event below
# Dump starting state to Inara # Dump starting state to Inara
if (this.newuser or if (this.newuser or
@ -307,6 +314,8 @@ def journal_entry(cmdr, is_beta, system, station, entry, state):
this.loadout = make_loadout(state) this.loadout = make_loadout(state)
add_event('setCommanderShipLoadout', entry['timestamp'], this.loadout) add_event('setCommanderShipLoadout', entry['timestamp'], this.loadout)
call() # Call here just to be sure that if we can send, we do, otherwise it'll get it in the next tick
# Promotions # Promotions
elif entry['event'] == 'Promotion': elif entry['event'] == 'Promotion':
@ -435,35 +444,21 @@ def journal_entry(cmdr, is_beta, system, station, entry, state):
cargo = [OrderedDict([('itemName', k), ('itemCount', state['Cargo'][k])]) for k in sorted(state['Cargo'])] cargo = [OrderedDict([('itemName', k), ('itemCount', state['Cargo'][k])]) for k in sorted(state['Cargo'])]
# if our cargo differers from last we checked, we're at a station, # Send cargo and materials if changed
# and our flood limit isnt covered, queue an update if this.cargo != cargo:
should_poll = this.cargo != cargo and time.time() - this.last_update_time > FLOOD_LIMIT_SECONDS add_event('setCommanderInventoryCargo', entry['timestamp'], cargo)
this.cargo = cargo
# Send event(s) to Inara materials = []
if entry['event'] == 'ShutDown' or len(this.events) > old_events or should_poll: for category in ['Raw', 'Manufactured', 'Encoded']:
materials.extend([ OrderedDict([('itemName', k), ('itemCount', state[category][k])]) for k in sorted(state[category]) ])
# Send cargo and materials if changed if this.materials != materials:
if this.cargo != cargo: add_event('setCommanderInventoryMaterials', entry['timestamp'], materials)
add_event('setCommanderInventoryCargo', entry['timestamp'], cargo) this.materials = materials
this.cargo = cargo
materials = []
for category in ['Raw', 'Manufactured', 'Encoded']:
materials.extend([ OrderedDict([('itemName', k), ('itemCount', state[category][k])]) for k in sorted(state[category]) ])
if this.materials != materials:
add_event('setCommanderInventoryMaterials', entry['timestamp'], materials)
this.materials = materials
# Queue a call to Inara
call()
except Exception as e: except Exception as e:
if __debug__: print_exc() if __debug__: print_exc()
return str(e) return str(e)
#
# Events that don't need to be sent immediately but will be sent on the next mandatory event
#
# Send credits and stats to Inara on startup only - otherwise may be out of date # Send credits and stats to Inara on startup only - otherwise may be out of date
if entry['event'] == 'LoadGame': if entry['event'] == 'LoadGame':
add_event('setCommanderCredits', entry['timestamp'], add_event('setCommanderCredits', entry['timestamp'],
@ -857,14 +852,22 @@ def add_event(name, timestamp, data):
('eventData', data), ('eventData', data),
])) ]))
def call_timer(wait=FLOOD_LIMIT_SECONDS):
while this.timer_run:
time.sleep(wait)
if this.timer_run: # check again in here just in case we're closing and the stars align
call()
# Queue a call to Inara, handled in Worker thread # Queue a call to Inara, handled in Worker thread
def call(callback=None): def call(callback=None, force=False):
if not this.events: if not this.events:
return return
this.last_update_time = time.time() if (time.time() - config.getint(LAST_UPDATE_CONF_KEY)) <= FLOOD_LIMIT_SECONDS and not force:
return
config.set(LAST_UPDATE_CONF_KEY, int(time.time()))
print(f"INARA: {time.asctime()} sending {len(this.events)} entries to inara (call)")
data = OrderedDict([ data = OrderedDict([
('header', OrderedDict([ ('header', OrderedDict([
('appName', applongname), ('appName', applongname),
@ -887,6 +890,8 @@ def worker():
else: else:
(url, data, callback) = item (url, data, callback) = item
print(f"INARA: {time.asctime()} sending {len(data['events'])} entries to inara (worker)")
retrying = 0 retrying = 0
while retrying < 3: while retrying < 3:
try: try:
@ -896,28 +901,35 @@ def worker():
status = reply['header']['eventStatus'] status = reply['header']['eventStatus']
if callback: if callback:
callback(reply) callback(reply)
elif status // 100 != 2: # 2xx == OK (maybe with warnings) elif status // 100 != 2: # 2xx == OK (maybe with warnings)
# Log fatal errors # Log fatal errors
print('Inara\t%s %s' % (reply['header']['eventStatus'], reply['header'].get('eventStatusText', ''))) print('Inara\t%s %s' % (reply['header']['eventStatus'], reply['header'].get('eventStatusText', '')))
print(json.dumps(data, indent=2, separators = (',', ': '))) print(json.dumps(data, indent=2, separators = (',', ': ')))
plug.show_error(_('Error: Inara {MSG}').format(MSG = reply['header'].get('eventStatusText', status))) plug.show_error(_('Error: Inara {MSG}').format(MSG=reply['header'].get('eventStatusText', status)))
else: else:
# Log individual errors and warnings # Log individual errors and warnings
for data_event, reply_event in zip(data['events'], reply['events']): for data_event, reply_event in zip(data['events'], reply['events']):
if reply_event['eventStatus'] != 200: if reply_event['eventStatus'] != 200:
print('Inara\t%s %s\t%s' % (reply_event['eventStatus'], reply_event.get('eventStatusText', ''), json.dumps(data_event))) print('Inara\t%s %s\t%s' % (reply_event['eventStatus'], reply_event.get('eventStatusText', ''), json.dumps(data_event)))
if reply_event['eventStatus'] // 100 != 2: if reply_event['eventStatus'] // 100 != 2:
plug.show_error(_('Error: Inara {MSG}').format(MSG = '%s, %s' % (data_event['eventName'], reply_event.get('eventStatusText', reply_event['eventStatus'])))) plug.show_error(_('Error: Inara {MSG}').format(
if data_event['eventName'] in ['addCommanderTravelCarrierJump', 'addCommanderTravelDock', 'addCommanderTravelFSDJump', 'setCommanderTravelLocation']: MSG=f'{data_event["eventName"]},'
f'{reply_event.get("eventStatusText", reply_event["eventStatus"])}'))
if data_event['eventName'] in ('addCommanderTravelCarrierJump',
'addCommanderTravelDock',
'addCommanderTravelFSDJump',
'setCommanderTravelLocation'):
this.lastlocation = reply_event.get('eventData', {}) this.lastlocation = reply_event.get('eventData', {})
this.system_link.event_generate('<<InaraLocation>>', when="tail") # calls update_location in main thread # calls update_location in main thread
this.system_link.event_generate('<<InaraLocation>>', when="tail")
elif data_event['eventName'] in ['addCommanderShip', 'setCommanderShip']: elif data_event['eventName'] in ['addCommanderShip', 'setCommanderShip']:
this.lastship = reply_event.get('eventData', {}) this.lastship = reply_event.get('eventData', {})
this.system_link.event_generate('<<InaraShip>>', when="tail") # calls update_ship in main thread # calls update_ship in main thread
this.system_link.event_generate('<<InaraShip>>', when="tail")
break break
except: except Exception:
if __debug__: print_exc() logger.debug('Sending events', exc_info=e)
retrying += 1 retrying += 1
else: else:
if callback: if callback:

View File

@ -1,5 +1,4 @@
certifi==2019.9.11 certifi==2019.9.11
keyring==19.2.0
pathtools>=0.1.2
requests>=2.11.1 requests>=2.11.1
watchdog>=0.8.3 watchdog>=0.8.3
semantic-version>=2.8.5

View File

@ -73,7 +73,6 @@ if sys.platform=='darwin':
'optimize': 2, 'optimize': 2,
'packages': [ 'packages': [
'requests', 'requests',
'keyring.backends',
'sqlite3', # Included for plugins 'sqlite3', # Included for plugins
], ],
'includes': [ 'includes': [
@ -119,7 +118,6 @@ elif sys.platform=='win32':
'optimize': 2, 'optimize': 2,
'packages': [ 'packages': [
'requests', 'requests',
'keyring.backends',
'sqlite3', # Included for plugins 'sqlite3', # Included for plugins
], ],
'includes': [ 'includes': [