scon/monitor.py
Gabor Guzmics e43065cc00 * implemented chat protocol, explanation mechanics, reviewed marker for
already unpacked logs
* started to disect log parsers for using streams in future
* Qt Client started
* logstream planned.
2015-04-10 20:33:55 +02:00

161 lines
5.7 KiB
Python

#!/usr/bin/python
# -*- coding: utf-8 -*-
"""
Monitor a StarConflict Log Directory.
"""
import sys, os
import time
import logging
from watchdog.observers import Observer
from watchdog.events import LoggingEventHandler
class SconEventHandler(LoggingEventHandler):
def __init__(self, monitor, *args, **kwargs):
self.monitor = monitor
return super(SconEventHandler, self).__init__(*args, **kwargs)
def on_moved(self, event):
super(SconEventHandler, self).on_moved(event)
if not event.is_directory:
self.monitor.close(event.src_path)
self.monitor.notify_event('moved', {'src': event.src_path,
'is_dir': event.is_directory,
'dest': event.dest_path})
def on_created(self, event):
super(SconEventHandler, self).on_created(event)
if not event.is_directory:
self.monitor.open(event.src_path)
self.monitor.notify_event('created', {'src': event.src_path,
'is_dir': event.is_directory})
def on_deleted(self, event):
super(SconEventHandler, self).on_deleted(event)
if not event.is_directory:
self.monitor.close(event.src_path)
self.monitor.notify_event('deleted', {'src': event.src_path,
'is_dir': event.is_directory})
def on_modified(self, event):
super(SconEventHandler, self).on_modified(event)
self.monitor.notify_event('modified', {'src': event.src_path,
'is_dir': event.is_directory})
class SconMonitor(object):
def notify(self, filename, lines):
# notify somebody, filename has a few lines.
# this is basicly the function you want to overwrite.
# @see: self.run for how to integrate monitor into your main loop.
if self.notifier is not None:
self.notifier.notify(filename, lines)
def notify_event(self, event_type, data):
if self.notifier is not None:
self.notifier.notify_event(event_type, data)
def __init__(self, path=None, notifier=None):
# if you initialize path directly, you lose success boolean.
# albeit atm. this is always true.
if path is not None:
self.initialize(path)
self.notifier = notifier
def initialize(self, path):
# initialize the monitor with a path to observe.
self.files = {}
self.event_handler = SconEventHandler(self)
self.observer = Observer()
self.observer.schedule(self.event_handler,
path,
recursive=True)
return True
def open(self, filename=None):
# open a logfile and add it to the read-list...
f = open(filename, 'r')
new_file = { 'file': f,
'cursor': f.tell() }
self.files[filename] = new_file
return new_file
def close(self, filename):
# close a single file by key, does not do anything if not found.
if filename in self.files.keys():
close_file = self.files.pop(filename)
close_file['file'].close()
del close_file
def close_all(self):
""" closes all open files in the monitor """
for key in self.files.keys():
self.close(key)
def read_line(self, afile):
# read a single line in a file.
f = afile.get('file', None)
if f is None:
return
afile['cursor'] = f.tell()
line = f.readline()
if not line:
f.seek(afile['cursor'])
return None
else:
return line
def do(self):
''' Monitor main task handler, call this in your mainloop in ~1 sec intervals '''
# read all file changes.
for key, value in self.files.items():
lines = []
data = self.read_line(value)
while data is not None:
lines.append(data)
data = self.read_line(value)
if lines:
self.notify(key, lines)
#
def initialize_loop(self):
''' initializes the main loop for the monitor '''
self.observer.start()
def break_loop(self):
''' call this if you want to break the monitors tasks '''
self.observer.stop()
def end_loop(self):
''' always call this before exiting your main loop '''
self.close_all()
self.observer.join()
def run(self):
''' Basic Standalone Main Loop implementation, do not call this in your app. '''
# if you want to run this on its own.
# everytime any logfile is updated, print it.
self.initialize_loop()
try:
while True:
self.do()
time.sleep(1)
except KeyboardInterrupt:
self.break_loop()
self.end_loop()
if __name__ == '__main__':
monitor = SconMonitor()
logging.basicConfig(level=logging.INFO,
format='%(asctime)s - %(message)s',
datefmt='%Y-%m-%d %H:%M:%S')
path = os.path.join(os.path.expanduser('~'),
'Documents',
'My Games',
'StarConflict',
'logs'
)
if monitor.initialize(path) is True:
monitor.run()