cc-4105: added wrapper around pyinotify. added some stubs and todos
This commit is contained in:
parent
493f93c425
commit
f044cd91e3
|
@ -441,6 +441,7 @@ class AirtimeApiClient():
|
|||
return []
|
||||
|
||||
def list_all_watched_dirs(self):
|
||||
# Does this include the stor directory as well?
|
||||
logger = self.logger
|
||||
try:
|
||||
url = "http://%s:%s/%s/%s" % (self.config["base_url"], str(self.config["base_port"]), self.config["api_base"], self.config["list_all_watched_dirs"])
|
||||
|
|
|
@ -61,7 +61,11 @@ class Bootstrapper(Loggable):
|
|||
# need the correct watch channel signal to call delete
|
||||
if watch_dir in signal_by_path:
|
||||
dispatcher.send(signal=signal_by_path[watch_dir], sender=self, event=DeleteFile(f))
|
||||
os.remove(to_delete)
|
||||
# TODO : get rid of this, we should never delete files from
|
||||
# the FS even if they are deleted in airtime. Instead we
|
||||
# should put this file on a global ignore list until it's
|
||||
# re-added or something
|
||||
# os.remove(to_delete)
|
||||
deleted += 1
|
||||
else:
|
||||
self.logger.error("Could not find the signal corresponding to path: '%s'" % watch_dir)
|
||||
|
|
|
@ -38,6 +38,12 @@ class OrganizeListener(BaseListener, pyinotify.ProcessEvent):
|
|||
# got cookie
|
||||
def process_IN_MOVED_TO(self, event): self.process_to_organize(event)
|
||||
|
||||
def flush_events(self, path):
|
||||
"""organize the whole directory at path. (pretty much by doing what
|
||||
handle does to every file"""
|
||||
# TODO : implement me
|
||||
pass
|
||||
|
||||
@IncludeOnly(mmp.supported_extensions)
|
||||
def process_to_organize(self, event):
|
||||
dispatcher.send(signal=self.signal, sender=self, event=OrganizeFile(event))
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
import pyinotify
|
||||
|
||||
from media.monitor.log import Loggable
|
||||
from media.monitor.listeners import StoreWatchListener, OrganizeListener
|
||||
from media.monitor.organizer import Organizer
|
||||
|
||||
class Manager(Loggable):
|
||||
"""
|
||||
An abstraction over media monitors core pyinotify functions. These include
|
||||
adding watched,store, organize directories, etc. Basically composes over
|
||||
WatchManager from pyinotify
|
||||
"""
|
||||
all_signals = set(['add_watch', 'remove_watch'])
|
||||
# TODO : get rid of config object being passed? It's not actually being
|
||||
# used
|
||||
def __init__(self,config):
|
||||
|
||||
self.wm = pyinotify.WatchManager()
|
||||
# These two instance variables are assumed to be constant
|
||||
self.watch_channel = 'watch'
|
||||
self.organize_channel = 'organize'
|
||||
|
||||
self.watch_listener = StoreWatchListener(self.watch_channel)
|
||||
|
||||
self.organize = {
|
||||
'organize_path' : None,
|
||||
'store_path' : None,
|
||||
# This guy doesn't need to be changed, always the same.
|
||||
# Gets hooked by wm to different directories
|
||||
'organize_listener' : OrganizeListener(self.organize_channel),
|
||||
# Also stays the same as long as its target, the directory
|
||||
# which the "organized" files go to, isn't changed.
|
||||
'organizer' : None,
|
||||
}
|
||||
|
||||
self.watched_directories = set([])
|
||||
|
||||
def __remove_watch(self,path):
|
||||
old_watch = self.wm.get_wd(path)
|
||||
if old_watch: # only delete if dir is actually being watched
|
||||
self.rm_watch(old_watch, rec=True)
|
||||
|
||||
def __create_organizer(self, target_path):
|
||||
return Organizer(channel=self.organize_channel,target_path=target_path)
|
||||
|
||||
def set_organize_path(self, new_path):
|
||||
# if we are already organizing a particular directory we remove the
|
||||
# watch from it first before organizing another directory
|
||||
self.__remove_watch(self.organize['organize_path'])
|
||||
self.organize['organize_path'] = new_path
|
||||
# the OrganizeListener instance will walk path and dispatch an organize
|
||||
# event for every file in that directory
|
||||
self.organize['organize_listener'].flush_events(new_path)
|
||||
self.wm.add_watch(new_path, pyinotify.ALL_EVENTS, rec=True, auto_add=True,
|
||||
proc_fun=self.organize['organize_listener'])
|
||||
|
||||
def set_store_path(self,new_path):
|
||||
"""set the directory where organized files go to"""
|
||||
self.__remove_watch(self.organize['store_path'])
|
||||
self.organize['store_path'] = new_path
|
||||
self.organize['organizer'] = self.__create_organizer(new_path)
|
||||
# flush all the files in the new store_directory. this is done so that
|
||||
# new files are added to the database. Note that we are not responsible
|
||||
# for removing songs in the old store directory from the database
|
||||
# we assume that this is already done for us.
|
||||
self.watch_listener.flush_events(new_path)
|
||||
self.wm.add_watch(new_path, pyinotify.ALL_EVENTS, rec=True, auto_add=True,
|
||||
proc_fun=self.watch_listener)
|
||||
|
||||
def add_watch_directory(self, new_dir):
|
||||
if new_dir in self.watched_directories:
|
||||
self.logger.info("Cannot add '%s' to watched directories. It's \
|
||||
already being watched" % new_dir)
|
||||
else:
|
||||
self.logger.info("Adding watched directory: '%s'" % new_dir)
|
||||
self.watched_directories.add(new_dir)
|
||||
self.wm.add_watch(new_dir, pyinotify.ALL_EVENTS, rec=True, auto_add=True,
|
||||
proc_fun=self.watch_listener)
|
||||
|
||||
def remove_watch_directory(self, watch_dir):
|
||||
if watch_dir in self.watched_directories:
|
||||
self.watched_directories.remove(watch_dir)
|
||||
self.logger.info("Removing watched directory: '%s'", watch_dir)
|
||||
self.__remove_watch(watch_dir)
|
||||
else:
|
||||
self.logger.info("'%s' is not being watched, henced cannot be removed"
|
||||
% watch_dir)
|
||||
|
||||
def loop(self):
|
||||
pyinotify.Notifier(self.wm).loop()
|
|
@ -6,6 +6,13 @@ from media.monitor.log import Loggable
|
|||
from media.monitor.exceptions import BadSongFile
|
||||
|
||||
class Organizer(ReportHandler,Loggable):
|
||||
"""
|
||||
Organizer is responsible to to lisenting to OrganizeListener events and
|
||||
committing the appropriate changes to the filesystem. It does not in any
|
||||
interact with WatchSyncer's even when the the WatchSyncer is a "storage
|
||||
directory". The "storage" directory picks up all of its events through
|
||||
pyinotify. (These events are fed to it through StoreWatchListener)
|
||||
"""
|
||||
def __init__(self, channel, target_path):
|
||||
self.channel = channel
|
||||
self.target_path = target_path
|
||||
|
@ -22,4 +29,9 @@ class Organizer(ReportHandler,Loggable):
|
|||
# probably general error in mmp.magic.move...
|
||||
except Exception as e:
|
||||
self.report_problem_file(event=event, exception=e)
|
||||
def flush_events(self, path):
|
||||
"""organize the whole directory at path. (pretty much by doing what
|
||||
handle does to every file"""
|
||||
# TODO : implement me
|
||||
pass
|
||||
|
||||
|
|
|
@ -47,7 +47,8 @@ class TimeoutWatcher(threading.Thread,Loggable):
|
|||
# Note that this isn't strictly necessary since RequestSync threads
|
||||
# already chain themselves
|
||||
if self.watcher.requests_in_queue():
|
||||
self.logger.info("We got %d requests waiting to be launched" % self.watcher.requests_left_count())
|
||||
self.logger.info("We got %d requests waiting to be launched" %
|
||||
self.watcher.requests_left_count())
|
||||
self.watcher.request_do()
|
||||
# Same for events, this behaviour is mandatory however.
|
||||
if self.watcher.events_in_queue():
|
||||
|
@ -73,14 +74,12 @@ class WatchSyncer(ReportHandler,Loggable):
|
|||
|
||||
@property
|
||||
def target_path(self): return self.channel.path
|
||||
@property
|
||||
def signal(self): return self.channel.signal
|
||||
|
||||
def handle(self, sender, event):
|
||||
"""We implement this abstract method from ReportHandler"""
|
||||
# Using isinstance like this is usually considered to be bad style
|
||||
# because you are supposed to use polymorphism instead however we would
|
||||
# separate event handling itself from the events so there seems to be
|
||||
# no better way to do this
|
||||
# TODO : more types of events need to be handled here
|
||||
if isinstance(event, NewFile):
|
||||
try:
|
||||
self.logger.info("'%s' : New file added: '%s'" % (self.target_path, event.path))
|
||||
|
|
|
@ -94,6 +94,7 @@ for watch_dir in sdb.list_directories():
|
|||
|
||||
# The stor directory is the first directory in the watched directories list
|
||||
org = Organizer(channel=channels['org'],target_path=channels['watch'][0].path)
|
||||
# TODO : this is wrong
|
||||
watches = [ WatchSyncer(channel=pc) for pc in channels['watch'] ]
|
||||
problem_files = ProblemFileHandler(channel=channels['badfile'])
|
||||
|
||||
|
|
Loading…
Reference in New Issue