1
0
mirror of https://github.com/EDCD/EDMarketConnector.git synced 2025-04-13 07:47:14 +03:00

Drop support for interaction log

This commit is contained in:
Jonathan Harris 2017-11-24 08:59:50 +00:00
parent ac37c81792
commit e3323f8f6f
21 changed files with 5 additions and 288 deletions

View File

@ -62,7 +62,6 @@ import prefs
import plug
from hotkey import hotkeymgr
from monitor import monitor
from interactions import interactions
from theme import theme
@ -275,7 +274,6 @@ class AppWindow:
self.w.bind('<KP_Enter>', self.getandsend)
self.w.bind_all('<<Invoke>>', self.getandsend) # Hotkey monitoring
self.w.bind_all('<<JournalEvent>>', self.journal_event) # Journal monitoring
self.w.bind_all('<<InteractionEvent>>', self.interaction_event) # cmdrHistory monitoring
self.w.bind_all('<<PluginError>>', self.plugin_error) # Statusbar
self.w.bind_all('<<Quit>>', self.onexit) # Updater
@ -333,8 +331,6 @@ class AppWindow:
# (Re-)install log monitoring
if not monitor.start(self.w):
self.status['text'] = 'Error: Check %s' % _('E:D journal file location') # Location of the new Journal file in E:D 2.2
elif monitor.started and not interactions.start(self.w, monitor.started):
self.status['text'] = 'Error: Check %s' % _('E:D interaction log location') # Setting for the log file that contains recent interactions with other Cmdrs
if dologin:
self.login() # Login if not already logged in with this Cmdr
@ -636,11 +632,6 @@ class AppWindow:
if not config.getint('hotkey_mute'):
hotkeymgr.play_bad()
if entry['event'] in ['StartUp', 'LoadGame'] and monitor.started:
# Can start interaction monitoring
if not interactions.start(self.w, monitor.started):
self.status['text'] = 'Error: Check %s' % _('E:D interaction log location') # Setting for the log file that contains recent interactions with other Cmdrs
# Don't send to EDDN while on crew
if monitor.state['Captain']:
return
@ -692,20 +683,6 @@ class AppWindow:
if not config.getint('hotkey_mute'):
hotkeymgr.play_bad()
# Handle interaction event(s) from cmdrHistory
def interaction_event(self, event):
while True:
entry = interactions.get_entry()
if not entry:
return
# Currently we don't do anything with these events
err = plug.notify_interaction(monitor.cmdr, monitor.is_beta, entry)
if err:
self.status['text'] = err
if not config.getint('hotkey_mute'):
hotkeymgr.play_bad()
# Display asynchronous error from plugin
def plugin_error(self, event=None):
if plug.last_error.get('msg'):
@ -807,7 +784,6 @@ class AppWindow:
config.set('geometry', '+{1}+{2}'.format(*self.w.geometry().split('+')))
self.w.withdraw() # Following items can take a few seconds, so hide the main window while they happen
hotkeymgr.unregister()
interactions.close()
monitor.close()
plug.notify_stop()
self.eddn.close()

View File

@ -136,9 +136,6 @@
/* Empire rank. [stats.py] */
"Duke" = "Duke";
/* Setting for the log file that contains recent interactions with other Cmdrs. [EDMarketConnector.py] */
"E:D interaction log location" = "Umístění E:D logu interakcí";
/* Location of the new Journal file in E:D 2.2. [EDMarketConnector.py] */
"E:D journal file location" = "E:D umístění souboru deníku";

View File

@ -136,9 +136,6 @@
/* Empire rank. [stats.py] */
"Duke" = "Herzog";
/* Setting for the log file that contains recent interactions with other Cmdrs. [EDMarketConnector.py] */
"E:D interaction log location" = "E:D Speicherort Interaktions-Log";
/* Location of the new Journal file in E:D 2.2. [EDMarketConnector.py] */
"E:D journal file location" = "E:D Journal Dateispeicherort";

View File

@ -121,9 +121,6 @@
/* Empire rank. [stats.py] */
"Duke" = "Duke";
/* Setting for the log file that contains recent interactions with other Cmdrs. [EDMarketConnector.py] */
"E:D interaction log location" = "E:D interaction log location";
/* Location of the new Journal file in E:D 2.2. [EDMarketConnector.py] */
"E:D journal file location" = "E:D journal file location";

View File

@ -136,9 +136,6 @@
/* Empire rank. [stats.py] */
"Duke" = "Duque";
/* Setting for the log file that contains recent interactions with other Cmdrs. [EDMarketConnector.py] */
"E:D interaction log location" = "Localización del log de interacción de E:D";
/* Location of the new Journal file in E:D 2.2. [EDMarketConnector.py] */
"E:D journal file location" = "Localización del archivo de Journal de E:D";

View File

@ -121,9 +121,6 @@
/* Empire rank. [stats.py] */
"Duke" = "Duke";
/* Setting for the log file that contains recent interactions with other Cmdrs. [EDMarketConnector.py] */
"E:D interaction log location" = "E:D toimintolokin sijainti";
/* Location of the new Journal file in E:D 2.2. [EDMarketConnector.py] */
"E:D journal file location" = "E:D lokikirjan tiedostosijainti";

View File

@ -136,9 +136,6 @@
/* Empire rank. [stats.py] */
"Duke" = "Archiduc";
/* Setting for the log file that contains recent interactions with other Cmdrs. [EDMarketConnector.py] */
"E:D interaction log location" = "Emplacement des fichiers d'interaction E:D";
/* Location of the new Journal file in E:D 2.2. [EDMarketConnector.py] */
"E:D journal file location" = "Emplacement du journal E:D";

View File

@ -127,9 +127,6 @@
/* Empire rank. [stats.py] */
"Duke" = "Duke";
/* Setting for the log file that contains recent interactions with other Cmdrs. [EDMarketConnector.py] */
"E:D interaction log location" = "locazione del file E:D interazione";
/* Location of the new Journal file in E:D 2.2. [EDMarketConnector.py] */
"E:D journal file location" = "locazione del file E:D journal";

View File

@ -136,9 +136,6 @@
/* Empire rank. [stats.py] */
"Duke" = "Duke";
/* Setting for the log file that contains recent interactions with other Cmdrs. [EDMarketConnector.py] */
"E:D interaction log location" = "E:Dゲームクライアントのインタラクションログ出力先";
/* Location of the new Journal file in E:D 2.2. [EDMarketConnector.py] */
"E:D journal file location" = "E:Dゲームクライアントのジャーナルファイル出力先";

View File

@ -121,9 +121,6 @@
/* Empire rank. [stats.py] */
"Duke" = "Duke";
/* Setting for the log file that contains recent interactions with other Cmdrs. [EDMarketConnector.py] */
"E:D interaction log location" = "E:D interactie log bestand locatie";
/* Location of the new Journal file in E:D 2.2. [EDMarketConnector.py] */
"E:D journal file location" = "E:D journaal bestand locatie";

View File

@ -136,9 +136,6 @@
/* Empire rank. [stats.py] */
"Duke" = "Duke";
/* Setting for the log file that contains recent interactions with other Cmdrs. [EDMarketConnector.py] */
"E:D interaction log location" = "Miejsce składowania logu inerakcji z E:D";
/* Location of the new Journal file in E:D 2.2. [EDMarketConnector.py] */
"E:D journal file location" = "E:D Lokacja pliku dziennika";

View File

@ -136,9 +136,6 @@
/* Empire rank. [stats.py] */
"Duke" = "Arqui-Duque";
/* Setting for the log file that contains recent interactions with other Cmdrs. [EDMarketConnector.py] */
"E:D interaction log location" = "Local de registro de interação E:D";
/* Location of the new Journal file in E:D 2.2. [EDMarketConnector.py] */
"E:D journal file location" = "Localização do arquivo de diário E:D";

View File

@ -121,9 +121,6 @@
/* Empire rank. [stats.py] */
"Duke" = "Герцог";
/* Setting for the log file that contains recent interactions with other Cmdrs. [EDMarketConnector.py] */
"E:D interaction log location" = "Расположение лога отношений с игроками.";
/* Location of the new Journal file in E:D 2.2. [EDMarketConnector.py] */
"E:D journal file location" = "Расположение файла журнала E:D";

View File

@ -136,9 +136,6 @@
/* Empire rank. [stats.py] */
"Duke" = "Duke";
/* Setting for the log file that contains recent interactions with other Cmdrs. [EDMarketConnector.py] */
"E:D interaction log location" = "Lokacija loga o E:D interakcijama";
/* Location of the new Journal file in E:D 2.2. [EDMarketConnector.py] */
"E:D journal file location" = "Lokacija E:D Journal fajlova";

View File

@ -136,9 +136,6 @@
/* Empire rank. [stats.py] */
"Duke" = "Герцог";
/* Setting for the log file that contains recent interactions with other Cmdrs. [EDMarketConnector.py] */
"E:D interaction log location" = "Росташування журналу взаємодії пілотів E:D";
/* Location of the new Journal file in E:D 2.2. [EDMarketConnector.py] */
"E:D journal file location" = "Розташування файлу-журналу E:D";

View File

@ -106,7 +106,7 @@ this.status["text"] = "Happy!"
## Events
Once you have created your plugin and EDMC has loaded it there are three other functions you can define to be notified by EDMC when something happens: `journal_entry()`, `interaction()` and `cmdr_data()`.
Once you have created your plugin and EDMC has loaded it there are two other functions you can define to be notified by EDMC when something happens: `journal_entry()` and `cmdr_data()`.
Your events all get called on the main tkinter loop so be sure not to block for very long or the EDMC will appear to freeze. If you have a long running operation then you should take a look at how to do background updates in tkinter - http://effbot.org/zone/tkinter-threads.htm
@ -126,21 +126,6 @@ def journal_entry(cmdr, is_beta, system, station, entry, state):
sys.stderr.write("Arrived at {}\n".format(entry['StarSystem']))
```
### Player Interaction
This gets called when the player interacts with another Cmdr in-game.
If EDMC is started while the game is already running EDMC will send the last few interaction events from the current game session.
```python
def interaction(cmdr, is_beta, entry):
# Log type of interaction, Cmdr name, and local time
sys.stderr.write("{} Cmdr {} at {}\n".format(', '.join(entry['Interactions']),
entry['Name'].encode('utf-8'),
time.strftime('%Y-%m-%dT%H:%M:%S',
time.localtime(entry['Epoch'] - 11644473600))))
```
### Getting Commander Data
This gets called when EDMC has just fetched fresh Cmdr and station data from Frontier's servers.
@ -157,7 +142,7 @@ The data is a dictionary and full of lots of wonderful stuff!
## Error messages
You can display an error in EDMC's status area by returning a string from your `journal_entry()`, `interaction()` or `cmdr_data()` function, or asynchronously (e.g. from a "worker" thread that is performing a long running operation) by calling `plug.show_error()`. Either method will cause the "bad" sound to be played (unless the user has muted sound).
You can display an error in EDMC's status area by returning a string from your `journal_entry()` or `cmdr_data()` function, or asynchronously (e.g. from a "worker" thread that is performing a long running operation) by calling `plug.show_error()`. Either method will cause the "bad" sound to be played (unless the user has muted sound).
The status area is shared between EDMC itself and all other plugins, so your message won't be displayed for very long. Create a dedicated widget if you need to display routine status information.

View File

@ -74,7 +74,7 @@ This app can save a variety of data in a variety of formats:
By default these files will be placed in your Documents folder. Since this app will create a lot of files if you use it for a while you may wish to create a separate folder for the files and tell the app to place them there.
Some options work by reading the Elite: Dangerous game's log files. If you're running this app on a different machine from the Elite: Dangerous game then adjust the “E:D journal file location” and “E:D interaction log location” settings on the Configuration tab to point to the game's log files.
Some options work by reading the Elite: Dangerous game's log files. If you're running this app on a different machine from the Elite: Dangerous game then adjust the “E:D journal file location” setting on the Configuration tab to point to the game's log files.
### EDDN
@ -137,12 +137,9 @@ The Frontier server that supplies the data to this app sometimes fails to supply
This problem is tracked as [Issue #86](https://github.com/Marginal/EDMarketConnector/issues/86).
### Doesn't auto-update and/or persistently gives “Server is lagging” error
This app uses Elite: Dangerous' log files to track the systems and stations that you visit. If you're running this app on a different machine from the Elite: Dangerous game, or if you find that this app isn't automatically tracking the systems that you visit and/or isn't automatically “updating” on docking (if you have that option selected), then adjust the “E:D journal file location” and “E:D interaction log location” settings on the Configuration tab to point to the game's log files.
This app uses Elite: Dangerous' log files to track the systems and stations that you visit. If you're running this app on a different machine from the Elite: Dangerous game, or if you find that this app isn't automatically tracking the systems that you visit and/or isn't automatically “updating” on docking (if you have that option selected), then adjust the “E:D journal file location” setting on the Configuration tab to point to the game's log files.
The default settings on Windows are typically:
- `C:\Users\you\Saved Games\Frontier Developments\EliteDangerous` and
- `C:\Users\you\AppData\Local\Frontier Developments\EliteDangerous\CommanderHistory` respectively.
The default location on Windows is typically `C:\Users\you\Saved Games\Frontier Developments\EliteDangerous`.
### Credentials settings are greyed out
You can't edit your Username/Password or EDSM Commander Name/API Key if:

View File

@ -127,8 +127,6 @@ class Config:
self.default_journal_dir = join(NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, True)[0], 'Frontier Developments', 'Elite Dangerous')
self.default_interaction_dir = join(self.default_journal_dir, 'CommanderHistory')
self.home = expanduser('~')
self.respath = getattr(sys, 'frozen', False) and normpath(join(dirname(sys.executable.decode(sys.getfilesystemencoding())), pardir, 'Resources')) or dirname(__file__)
@ -193,8 +191,6 @@ class Config:
journaldir = KnownFolderPath(FOLDERID_SavedGames)
self.default_journal_dir = journaldir and join(journaldir, 'Frontier Developments', 'Elite Dangerous') or None
self.default_interaction_dir = join(KnownFolderPath(FOLDERID_LocalAppData), 'Frontier Developments', 'Elite Dangerous', 'CommanderHistory')
self.respath = dirname(getattr(sys, 'frozen', False) and sys.executable.decode(sys.getfilesystemencoding()) or __file__)
self.identifier = applongname
@ -290,8 +286,6 @@ class Config:
self.default_journal_dir = None
self.default_interaction_dir = None
self.home = expanduser('~')
self.respath = dirname(__file__)

View File

@ -1,144 +0,0 @@
import json
from operator import itemgetter
from os import listdir, stat
from os.path import getmtime, isdir, join
from sys import platform
if __debug__:
from traceback import print_exc
from config import config
if platform=='darwin':
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
elif platform=='win32':
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
else:
# Linux's inotify doesn't work over CIFS or NFS, so poll
FileSystemEventHandler = object # dummy
# CommanderHistory handler
class Interactions(FileSystemEventHandler):
_POLL = 5 # Fallback polling interval
def __init__(self):
FileSystemEventHandler.__init__(self) # futureproofing - not need for current version of watchdog
self.root = None
self.currentdir = None # The actual logdir that we're monitoring
self.observer = None
self.observed = None # a watchdog ObservedWatch, or None if polling
self.seen = [] # interactions that we've already processed
self.interaction_queue = [] # For communicating interactions back to main thread
def start(self, root, started):
self.root = root
self.session_start = started
logdir = config.get('interactiondir') or config.default_interaction_dir
if not logdir or not isdir(logdir):
self.stop()
return False
if self.currentdir and self.currentdir != logdir:
self.stop()
self.currentdir = logdir
# Set up a watchdog observer.
# File system events are unreliable/non-existent over network drives on Linux.
# We can't easily tell whether a path points to a network drive, so assume
# any non-standard logdir might be on a network drive and poll instead.
polling = bool(config.get('interactiondir')) and platform != 'win32'
if not polling and not self.observer:
self.observer = Observer()
self.observer.daemon = True
self.observer.start()
elif polling and self.observer:
self.observer.stop()
self.observer = None
if not self.observed and not polling:
self.observed = self.observer.schedule(self, self.currentdir)
if __debug__:
print '%s interactions "%s"' % (polling and 'Polling' or 'Monitoring', self.currentdir)
# Even if we're not intending to poll, poll at least once to process pre-existing
# data and to check whether the watchdog thread has crashed due to events not\
# being supported on this filesystem.
self.root.after(self._POLL * 1000/2, self.poll, True)
return True
def stop(self):
if __debug__:
print 'Stopping monitoring interactions'
self.currentdir = None
if self.observed:
self.observed = None
self.observer.unschedule_all()
def close(self):
self.stop()
if self.observer:
self.observer.stop()
self.observer.join()
self.observer = None
def poll(self, first_time=False):
self.process()
if first_time:
# Watchdog thread
emitter = self.observed and self.observer._emitter_for_watch[self.observed] # Note: Uses undocumented attribute
if emitter and emitter.is_alive():
return # Watchdog thread still running - stop polling
self.root.after(self._POLL * 1000, self.poll) # keep polling
def on_modified(self, event):
# watchdog callback - DirModifiedEvent on macOS, FileModifiedEvent on Windows
if event.is_directory or stat(event.src_path).st_size: # Can get on_modified events when the file is emptied
self.process(event.src_path if not event.is_directory else None)
# Can be called either in watchdog thread or, if polling, in main thread. The code assumes not both.
def process(self, logfile=None):
if not logfile:
for logfile in [x for x in listdir(self.currentdir) if x.endswith('.cmdrHistory')]:
if self.session_start and getmtime(join(self.currentdir, logfile)) >= self.session_start:
break
else:
return
try:
# cmdrHistory file is shared between beta and live. So filter out interactions not in this game session.
start = self.session_start + 11644473600 # Game time is 369 years in the future
with open(join(self.currentdir, logfile), 'rb') as h:
current = [x for x in json.load(h)['Interactions'] if x['Epoch'] >= start]
new = [x for x in current if x not in self.seen] # O(n^2) comparison but currently limited to 10x10
self.interaction_queue.extend(sorted(new, key=itemgetter('Epoch'))) # sort by time
self.seen = current
if self.interaction_queue:
self.root.event_generate('<<InteractionEvent>>', when="tail")
except:
if __debug__: print_exc()
def get_entry(self):
if not self.interaction_queue:
return None
else:
return self.interaction_queue.pop(0)
# singleton
interactions = Interactions()

24
plug.py
View File

@ -226,30 +226,6 @@ def notify_journal_entry(cmdr, is_beta, system, station, entry, state):
return error
def notify_interaction(cmdr, is_beta, entry):
"""
Send an interaction entry to each plugin.
:param cmdr: The piloting Cmdr name
:param is_beta: whether the player is in a Beta universe.
:param entry: The interaction entry as a dictionary
:return: Error message from the first plugin that returns one (if any)
"""
error = None
for plugin in PLUGINS:
interaction = plugin._get_func('interaction')
if interaction:
try:
# Pass a copy of the interaction entry in case the callee modifies it
if interaction.func_code.co_argcount == 2:
newerror = interaction(cmdr, dict(entry))
else:
newerror = interaction(cmdr, is_beta, dict(entry))
error = error or newerror
except:
print_exc()
return error
def notify_system_changed(timestamp, system, coordinates):
"""
Send notification data to each plugin when we arrive at a new system.

View File

@ -199,10 +199,6 @@ class PreferencesDialog(tk.Toplevel):
self.logdir.set(config.get('journaldir') or config.default_journal_dir or '')
self.logdir_entry = nb.Entry(configframe, takefocus=False)
self.interactiondir = tk.StringVar()
self.interactiondir.set(config.get('interactiondir') or config.default_interaction_dir or '')
self.interactiondir_entry = nb.Entry(configframe, takefocus=False)
if platform != 'darwin':
# Apple's SMB implementation is way too flaky - no filesystem events and bogus NULLs
nb.Label(configframe, text = _('E:D journal file location')+':').grid(columnspan=4, padx=PADX, sticky=tk.W) # Location of the new Journal file in E:D 2.2
@ -214,15 +210,6 @@ class PreferencesDialog(tk.Toplevel):
if config.default_journal_dir:
nb.Button(configframe, text=_('Default'), command=self.logdir_reset, state = config.get('journaldir') and tk.NORMAL or tk.DISABLED).grid(row=10, column=2, pady=PADY, sticky=tk.EW) # Appearance theme and language setting
nb.Label(configframe, text = _('E:D interaction log location')+':').grid(columnspan=4, padx=PADX, pady=(PADY, 0), sticky=tk.W) # Setting for the log file that contains recent interactions with other Cmdrs
self.interactiondir_entry.grid(columnspan=4, padx=PADX, pady=(0,PADY), sticky=tk.EW)
self.interactionbutton = nb.Button(configframe, text=(platform=='darwin' and _('Change...') or # Folder selection button on OSX
_('Browse...')), # Folder selection button on Windows
command = lambda:self.filebrowse(_('E:D interaction log location'), self.interactiondir))
self.interactionbutton.grid(row=15, column=3, padx=PADX, pady=PADY, sticky=tk.EW)
if config.default_interaction_dir:
nb.Button(configframe, text=_('Default'), command=self.interactiondir_reset, state = config.get('journaldir') and tk.NORMAL or tk.DISABLED).grid(row=15, column=2, pady=PADY, sticky=tk.EW) # Appearance theme and language setting
if platform == 'win32':
ttk.Separator(configframe, orient=tk.HORIZONTAL).grid(columnspan=4, padx=PADX, pady=PADY*4, sticky=tk.EW)
@ -400,7 +387,6 @@ class PreferencesDialog(tk.Toplevel):
def outvarchanged(self, event=None):
self.displaypath(self.outdir, self.outdir_entry)
self.displaypath(self.logdir, self.logdir_entry)
self.displaypath(self.interactiondir, self.interactiondir_entry)
logdir = self.logdir.get()
logvalid = logdir and exists(logdir)
@ -486,11 +472,6 @@ class PreferencesDialog(tk.Toplevel):
self.logdir.set(config.default_journal_dir)
self.outvarchanged()
def interactiondir_reset(self):
if config.default_interaction_dir:
self.interactiondir.set(config.default_interaction_dir)
self.outvarchanged()
def themecolorbrowse(self, index):
(rgb, color) = tkColorChooser.askcolor(self.theme_colors[index], title=self.theme_prompts[index], parent=self.parent)
if color:
@ -581,12 +562,6 @@ class PreferencesDialog(tk.Toplevel):
else:
config.set('journaldir', logdir)
interactiondir = self.interactiondir.get()
if config.default_interaction_dir and interactiondir.lower() == config.default_interaction_dir.lower():
config.set('interactiondir', '') # default location
else:
config.set('interactiondir', interactiondir)
if platform in ['darwin','win32']:
config.set('hotkey_code', self.hotkey_code)
config.set('hotkey_mods', self.hotkey_mods)