mirror of
https://github.com/EDCD/EDMarketConnector.git
synced 2025-04-12 15:27:14 +03:00
135 lines
4.8 KiB
Python
135 lines
4.8 KiB
Python
import json
|
|
from calendar import timegm
|
|
from operator import itemgetter
|
|
from os import listdir
|
|
from os.path import isdir, isfile, join, getsize
|
|
from sys import platform
|
|
import time
|
|
|
|
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
|
|
|
|
|
|
# Status.json handler
|
|
class Dashboard(FileSystemEventHandler):
|
|
|
|
_POLL = 1 # 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.status = {} # Current status for communicating status back to main thread
|
|
|
|
def start(self, root, started):
|
|
self.root = root
|
|
self.session_start = started
|
|
|
|
logdir = config.get('journaldir') or config.default_journal_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 = 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 Dashboard "%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(int(self._POLL * 1000/2), self.poll, True)
|
|
|
|
return True
|
|
|
|
def stop(self):
|
|
if __debug__:
|
|
print('Stopping monitoring Dashboard')
|
|
self.currentdir = None
|
|
if self.observed:
|
|
self.observed = None
|
|
self.observer.unschedule_all()
|
|
self.status = {}
|
|
|
|
def close(self):
|
|
self.stop()
|
|
if self.observer:
|
|
self.observer.stop()
|
|
if self.observer:
|
|
self.observer.join()
|
|
self.observer = None
|
|
|
|
def poll(self, first_time=False):
|
|
if not self.currentdir:
|
|
# Stopped
|
|
self.status = {}
|
|
else:
|
|
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 (isfile(event.src_path) and getsize(event.src_path)): # 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.
|
|
def process(self, logfile=None):
|
|
try:
|
|
with open(join(self.currentdir, 'Status.json'), 'rb') as h:
|
|
data = h.read().strip()
|
|
if data: # Can be empty if polling while the file is being re-written
|
|
entry = json.loads(data)
|
|
|
|
# Status file is shared between beta and live. So filter out status not in this game session.
|
|
if (timegm(time.strptime(entry['timestamp'], '%Y-%m-%dT%H:%M:%SZ')) >= self.session_start and
|
|
self.status != entry):
|
|
self.status = entry
|
|
self.root.event_generate('<<DashboardEvent>>', when="tail")
|
|
except:
|
|
if __debug__: print_exc()
|
|
|
|
# singleton
|
|
dashboard = Dashboard()
|