From 3e7b21c2ef2b259b4e014aa93a287a2f60cc092a Mon Sep 17 00:00:00 2001 From: Calin Crisan Date: Sun, 18 Oct 2015 17:49:46 +0300 Subject: [PATCH] mjpgclient & smbctl now have their own start() functions so they won't start with relayevent, sendmail or webhook --- motioneye/mjpgclient.py | 90 ++++++++++++++++++++--------------------- motioneye/motionctl.py | 22 +++++----- motioneye/server.py | 69 +++++++++++-------------------- motioneye/smbctl.py | 82 +++++++++++++++++++------------------ 4 files changed, 123 insertions(+), 140 deletions(-) diff --git a/motioneye/mjpgclient.py b/motioneye/mjpgclient.py index 01186e6..933df2d 100644 --- a/motioneye/mjpgclient.py +++ b/motioneye/mjpgclient.py @@ -210,6 +210,51 @@ class MjpgClient(iostream.IOStream): self._seek_content_length() +def start(): + # schedule the garbage collector + io_loop = ioloop.IOLoop.instance() + io_loop.add_timeout(datetime.timedelta(seconds=settings.MJPG_CLIENT_TIMEOUT), _garbage_collector) + + +def get_jpg(camera_id): + if camera_id not in MjpgClient.clients: + # mjpg client not started yet for this camera + + logging.debug('creating mjpg client for camera %(camera_id)s' % { + 'camera_id': camera_id}) + + camera_config = config.get_camera(camera_id) + if not camera_config['@enabled'] or not utils.local_motion_camera(camera_config): + logging.error('could not start mjpg client for camera id %(camera_id)s: not enabled or not local' % { + 'camera_id': camera_id}) + + return None + + port = camera_config['stream_port'] + username, password = None, None + if camera_config.get('stream_auth_method') > 0: + username, password = camera_config.get('stream_authentication', ':').split(':') + + client = MjpgClient(camera_id, port, username, password) + client.connect() + + MjpgClient.last_access[camera_id] = datetime.datetime.utcnow() + + return MjpgClient.last_jpgs.get(camera_id) + + +def close_all(invalidate=False): + for client in MjpgClient.clients.values(): + client.close() + + if invalidate: + MjpgClient.clients = {} + MjpgClient.last_jpgs = {} + MjpgClient.last_jpg_moment = {} + MjpgClient.last_access = {} + MjpgClient.last_erroneous_close_time = 0 + + def _garbage_collector(): logging.debug('running garbage collector for mjpg clients...') @@ -258,48 +303,3 @@ def _garbage_collector(): client.close() continue - - -def get_jpg(camera_id): - if camera_id not in MjpgClient.clients: - # mjpg client not started yet for this camera - - logging.debug('creating mjpg client for camera %(camera_id)s' % { - 'camera_id': camera_id}) - - camera_config = config.get_camera(camera_id) - if not camera_config['@enabled'] or not utils.local_motion_camera(camera_config): - logging.error('could not start mjpg client for camera id %(camera_id)s: not enabled or not local' % { - 'camera_id': camera_id}) - - return None - - port = camera_config['stream_port'] - username, password = None, None - if camera_config.get('stream_auth_method') > 0: - username, password = camera_config.get('stream_authentication', ':').split(':') - - client = MjpgClient(camera_id, port, username, password) - client.connect() - - MjpgClient.last_access[camera_id] = datetime.datetime.utcnow() - - return MjpgClient.last_jpgs.get(camera_id) - - -def close_all(invalidate=False): - for client in MjpgClient.clients.values(): - client.close() - - if invalidate: - MjpgClient.clients = {} - MjpgClient.last_jpgs = {} - MjpgClient.last_jpg_moment = {} - MjpgClient.last_access = {} - MjpgClient.last_erroneous_close_time = 0 - - -def start_gc(): - # schedule the garbage collector - io_loop = ioloop.IOLoop.instance() - io_loop.add_timeout(datetime.timedelta(seconds=settings.MJPG_CLIENT_TIMEOUT), _garbage_collector) diff --git a/motioneye/motionctl.py b/motioneye/motionctl.py index 3385e90..58e8266 100644 --- a/motioneye/motionctl.py +++ b/motioneye/motionctl.py @@ -72,17 +72,6 @@ def find_motion(): return _motion_binary_cache -def _disable_initial_motion_detection(): - for camera_id in config.get_camera_ids(): - camera_config = config.get_camera(camera_id) - if not utils.local_motion_camera(camera_config): - continue - - if not camera_config['@motion_detection']: - logging.debug('motion detection disabled by config for camera with id %s' % camera_id) - set_motion_detection(camera_id, False) - - def start(deferred=False): if deferred: return IOLoop.instance().add_callback(start, deferred=False) @@ -323,6 +312,17 @@ def thread_id_to_camera_id(thread_id): return None +def _disable_initial_motion_detection(): + for camera_id in config.get_camera_ids(): + camera_config = config.get_camera(camera_id) + if not utils.local_motion_camera(camera_config): + continue + + if not camera_config['@motion_detection']: + logging.debug('motion detection disabled by config for camera with id %s' % camera_id) + set_motion_detection(camera_id, False) + + def _get_pid(): motion_pid_path = os.path.join(settings.RUN_PATH, 'motion.pid') diff --git a/motioneye/server.py b/motioneye/server.py index 6e27608..19b8db7 100644 --- a/motioneye/server.py +++ b/motioneye/server.py @@ -25,6 +25,7 @@ import sys import time from tornado.web import Application +from tornado.ioloop import IOLoop import handlers import settings @@ -181,13 +182,11 @@ handler_mapping = [ def configure_signals(): def bye_handler(signal, frame): - import tornado.ioloop - logging.info('interrupt signal received, shutting down...') # shut down the IO loop if it has been started - ioloop = tornado.ioloop.IOLoop.instance() - ioloop.stop() + io_loop = IOLoop.instance() + io_loop.stop() def child_handler(signal, frame): # this is required for the multiprocessing mechanism to work @@ -217,12 +216,12 @@ def test_requirements(): if os.geteuid() != 0: if settings.SMB_SHARES: - print('SMB_SHARES require root privileges') - return False + logging.fatal('smb shares require root privileges') + sys.exit(-1) if settings.ENABLE_REBOOT: - print('reboot requires root privileges') - return False + logging.fatal('reboot requires root privileges') + sys.exit(-1) try: import tornado # @UnusedImport @@ -312,34 +311,6 @@ def start_motion(): ioloop.add_timeout(datetime.timedelta(seconds=settings.MOTION_CHECK_INTERVAL), checker) -def start_cleanup(): - import cleanup - - cleanup.start() - logging.info('cleanup started') - - -def start_wsswitch(): - import wsswitch - - wsswitch.start() - logging.info('wsswitch started') - - -def start_thumbnailer(): - import thumbnailer - - thumbnailer.start() - logging.info('thumbnailer started') - - -def start_mjpg_client_gc(): - import mjpgclient - - mjpgclient.start_gc() - logging.info('mjpg client garbage collector started') - - def parse_options(parser, args): parser.add_argument('-b', help='start the server in background (daemonize)', action='store_true', dest='background', default=False) @@ -349,11 +320,12 @@ def parse_options(parser, args): def run(): import cleanup + import mjpgclient import motionctl import motioneye import smbctl import thumbnailer - import tornado.ioloop + import wsswitch configure_signals() logging.info('hello! this is motionEye server %s' % motioneye.VERSION) @@ -361,7 +333,6 @@ def run(): test_requirements() if settings.SMB_SHARES: - stop, start = smbctl.update_mounts() # @UnusedVariable if start: start_motion() @@ -370,15 +341,23 @@ def run(): start_motion() if settings.CLEANUP_INTERVAL: - start_cleanup() + cleanup.start() + logging.info('cleanup started') - start_wsswitch() + wsswitch.start() + logging.info('wsswitch started') if settings.THUMBNAILER_INTERVAL: - start_thumbnailer() + thumbnailer.start() + logging.info('thumbnailer started') if settings.MJPG_CLIENT_TIMEOUT: - start_mjpg_client_gc() + mjpgclient.start() + logging.info('mjpg client garbage collector started') + + if settings.SMB_SHARES: + smbctl.start() + logging.info('smb mounts started') template.add_context('static_path', settings.BASE_PATH + '/static/') @@ -388,7 +367,7 @@ def run(): application.listen(settings.PORT, settings.LISTEN) logging.info('server started') - tornado.ioloop.IOLoop.instance().start() + IOLoop.instance().start() logging.info('server stopped') @@ -405,8 +384,8 @@ def run(): logging.info('motion stopped') if settings.SMB_SHARES: - smbctl.umount_all() - logging.info('SMB shares unmounted') + smbctl.stop() + logging.info('smb mounts stopped') logging.info('bye!') diff --git a/motioneye/smbctl.py b/motioneye/smbctl.py index 12e4505..936c04b 100644 --- a/motioneye/smbctl.py +++ b/motioneye/smbctl.py @@ -28,6 +28,15 @@ import config import settings +def start(): + io_loop = ioloop.IOLoop.instance() + io_loop.add_timeout(datetime.timedelta(seconds=settings.MOUNT_CHECK_INTERVAL), _check_mounts) + + +def stop(): + _umount_all() + + def find_mount_cifs(): try: return subprocess.check_output('which mount.cifs', shell=True).strip() @@ -50,11 +59,6 @@ def make_mount_point(server, share, username): return mount_point -def _is_motioneye_mount(mount_point): - mount_point_root = os.path.join(settings.SMB_MOUNT_ROOT, 'motioneye_') - return bool(re.match('^' + mount_point_root + '\w+$', mount_point)) - - def list_mounts(): logging.debug('listing smb mounts...') @@ -108,7 +112,34 @@ def list_mounts(): return mounts -def mount(server, share, username, password): +def update_mounts(): + network_shares = config.get_network_shares() + + mounts = list_mounts() + mounts = dict(((m['server'], m['share'], m['username'] or ''), False) for m in mounts) + + should_stop = False # indicates that motion should be stopped immediately + should_start = True # indicates that motion can be started afterwards + for network_share in network_shares: + key = (network_share['server'], network_share['share'], network_share['username'] or '') + if key in mounts: # found + mounts[key] = True + + else: # needs to be mounted + should_stop = True + if not _mount(network_share['server'], network_share['share'], network_share['username'], network_share['password']): + should_start = False + + # unmount the no longer necessary mounts + for (server, share, username), required in mounts.items(): + if not required: + _umount(server, share, username) + should_stop = True + + return (should_stop, should_start) + + +def _mount(server, share, username, password): mount_point = make_mount_point(server, share, username) logging.debug('making sure mount point "%s" exists' % mount_point) @@ -153,7 +184,7 @@ def mount(server, share, username, password): return mount_point -def umount(server, share, username): +def _umount(server, share, username): mount_point = make_mount_point(server, share, username) logging.debug('unmounting "//%s/%s" from "%s"' % (server, share, mount_point)) @@ -176,36 +207,14 @@ def umount(server, share, username): return True -def update_mounts(): - network_shares = config.get_network_shares() - - mounts = list_mounts() - mounts = dict(((m['server'], m['share'], m['username'] or ''), False) for m in mounts) - - should_stop = False # indicates that motion should be stopped immediately - should_start = True # indicates that motion can be started afterwards - for network_share in network_shares: - key = (network_share['server'], network_share['share'], network_share['username'] or '') - if key in mounts: # found - mounts[key] = True - - else: # needs to be mounted - should_stop = True - if not mount(network_share['server'], network_share['share'], network_share['username'], network_share['password']): - should_start = False - - # unmount the no longer necessary mounts - for (server, share, username), required in mounts.items(): - if not required: - umount(server, share, username) - should_stop = True - - return (should_stop, should_start) +def _is_motioneye_mount(mount_point): + mount_point_root = os.path.join(settings.SMB_MOUNT_ROOT, 'motioneye_') + return bool(re.match('^' + mount_point_root + '\w+$', mount_point)) -def umount_all(): +def _umount_all(): for mount in list_mounts(): - umount(mount['server'], mount['share'], mount['username']) + _umount(mount['server'], mount['share'], mount['username']) def _check_mounts(): @@ -223,8 +232,3 @@ def _check_mounts(): io_loop = ioloop.IOLoop.instance() io_loop.add_timeout(datetime.timedelta(seconds=settings.MOUNT_CHECK_INTERVAL), _check_mounts) - -if settings.SMB_SHARES: - # schedule the mount checker - io_loop = ioloop.IOLoop.instance() - io_loop.add_timeout(datetime.timedelta(seconds=settings.MOUNT_CHECK_INTERVAL), _check_mounts) -- 2.39.5