Skip to content

Commit

Permalink
fixed email notifications not being sent; reorganized imports; added
Browse files Browse the repository at this point in the history
settings for more subprocess timeouts
  • Loading branch information
ccrisan committed Oct 20, 2015
1 parent c6b37a5 commit fc19628
Show file tree
Hide file tree
Showing 16 changed files with 189 additions and 144 deletions.
6 changes: 6 additions & 0 deletions extra/motioneye.conf.sample
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,14 @@ enable_reboot false
# timeout in seconds to use when talking to the SMTP server
smtp_timeout 60

# timeout in seconds to wait media files list
list_media_timeout 120

# timeout in seconds to wait for zip file creation
zip_timeout 500

# timeout in seconds to wait for timelapse creation
timelapse_timeout 500

# enable adding and removing cameras from UI
add_remove_cameras true
13 changes: 7 additions & 6 deletions motioneye/cleanup.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@
import multiprocessing
import os
import signal
import tornado

from tornado.ioloop import IOLoop

import mediafiles
import settings
Expand All @@ -35,8 +36,8 @@ def start():
return

# schedule the first call a bit later to improve performance at startup
ioloop = tornado.ioloop.IOLoop.instance()
ioloop.add_timeout(datetime.timedelta(seconds=min(settings.CLEANUP_INTERVAL, 60)), _run_process)
io_loop = IOLoop.instance()
io_loop.add_timeout(datetime.timedelta(seconds=min(settings.CLEANUP_INTERVAL, 60)), _run_process)


def stop():
Expand All @@ -63,17 +64,17 @@ def running():
def _run_process():
global _process

ioloop = tornado.ioloop.IOLoop.instance()
io_loop = IOLoop.instance()

if thumbnailer.running():
# postpone if thumbnailer is currently running
ioloop.add_timeout(datetime.timedelta(seconds=60), _run_process)
io_loop.add_timeout(datetime.timedelta(seconds=60), _run_process)

return

else:
# schedule the next call
ioloop.add_timeout(datetime.timedelta(seconds=settings.CLEANUP_INTERVAL), _run_process)
io_loop.add_timeout(datetime.timedelta(seconds=settings.CLEANUP_INTERVAL), _run_process)

if not running(): # check that the previous process has finished
logging.debug('running cleanup process...')
Expand Down
13 changes: 6 additions & 7 deletions motioneye/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,6 @@
import utils
import v4l2ctl

from utils import OrderedDict


_CAMERA_CONFIG_FILE_NAME = 'thread-%(id)s.conf'
_MAIN_CONFIG_FILE_NAME = 'motion.conf'
Expand Down Expand Up @@ -1326,7 +1324,8 @@ def restore(content):
def later():
powerctl.reboot()

IOLoop.instance().add_timeout(datetime.timedelta(seconds=2), later)
io_loop = IOLoop.instance()
io_loop.add_timeout(datetime.timedelta(seconds=2), later)

else:
logging.info('invalidating config cache')
Expand Down Expand Up @@ -1428,7 +1427,7 @@ def _python_to_value(value):


def _conf_to_dict(lines, list_names=[], no_convert=[]):
data = OrderedDict()
data = utils.OrderedDict()

for line in lines:
line = line.strip()
Expand Down Expand Up @@ -1467,7 +1466,7 @@ def _conf_to_dict(lines, list_names=[], no_convert=[]):

def _dict_to_conf(lines, data, list_names=[]):
conf_lines = []
remaining = OrderedDict(data)
remaining = utils.OrderedDict(data)
processed = set()

# parse existing lines and replace the values
Expand Down Expand Up @@ -1677,7 +1676,7 @@ def get_additional_structure(camera, separators=False):
'with' if separators else 'without'))

# gather sections
sections = OrderedDict()
sections = utils.OrderedDict()
for func in _additional_section_funcs:
result = func()
if not result:
Expand All @@ -1694,7 +1693,7 @@ def get_additional_structure(camera, separators=False):

logging.debug('additional config section: %s' % result['name'])

configs = OrderedDict()
configs = utils.OrderedDict()
for func in _additional_config_funcs:
result = func()
if not result:
Expand Down
12 changes: 7 additions & 5 deletions motioneye/handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@
import socket
import subprocess

from tornado.web import RequestHandler, HTTPError, asynchronous
from tornado.ioloop import IOLoop
from tornado.web import RequestHandler, HTTPError, asynchronous

import config
import mediafiles
Expand Down Expand Up @@ -356,8 +356,8 @@ def finish():
def call_reboot():
powerctl.reboot()

ioloop = IOLoop.instance()
ioloop.add_timeout(datetime.timedelta(seconds=2), call_reboot)
io_loop = IOLoop.instance()
io_loop.add_timeout(datetime.timedelta(seconds=2), call_reboot)
return self.finish({'reload': False, 'reboot': True, 'error': None})

else:
Expand Down Expand Up @@ -1438,10 +1438,12 @@ def post(self, op):
self.reboot()

def shut_down(self):
IOLoop.instance().add_timeout(datetime.timedelta(seconds=2), powerctl.shut_down)
io_loop = IOLoop.instance()
io_loop.add_timeout(datetime.timedelta(seconds=2), powerctl.shut_down)

def reboot(self):
IOLoop.instance().add_timeout(datetime.timedelta(seconds=2), powerctl.reboot)
io_loop = IOLoop.instance()
io_loop.add_timeout(datetime.timedelta(seconds=2), powerctl.reboot)


class VersionHandler(BaseHandler):
Expand Down
49 changes: 33 additions & 16 deletions motioneye/mediafiles.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,15 @@
import multiprocessing
import os.path
import re
import signal
import stat
import StringIO
import subprocess
import time
import tornado
import zipfile

from PIL import Image
from tornado import ioloop
from tornado.ioloop import IOLoop

import config
import settings
Expand Down Expand Up @@ -326,17 +326,22 @@ def read_media_list():
media_list.append(parent_pipe.recv())

def poll_process():
ioloop = tornado.ioloop.IOLoop.instance()
io_loop = IOLoop.instance()
if process.is_alive(): # not finished yet
now = datetime.datetime.now()
delta = now - started
if delta.seconds < 120:
ioloop.add_timeout(datetime.timedelta(seconds=0.5), poll_process)
if delta.seconds < settings.LIST_MEDIA_TIMEOUT:
io_loop.add_timeout(datetime.timedelta(seconds=0.5), poll_process)
read_media_list()

else: # process did not finish within 2 minutes
else: # process did not finish in time
logging.error('timeout waiting for the media listing process to finish')
try:
os.kill(process.pid, signal.SIGTERM)

except:
pass # nevermind

callback(None)

else: # finished
Expand Down Expand Up @@ -430,15 +435,20 @@ def do_zip(pipe):
started = datetime.datetime.now()

def poll_process():
ioloop = tornado.ioloop.IOLoop.instance()
io_loop = IOLoop.instance()
if working.value:
now = datetime.datetime.now()
delta = now - started
if delta.seconds < settings.ZIP_TIMEOUT:
ioloop.add_timeout(datetime.timedelta(seconds=0.5), poll_process)
io_loop.add_timeout(datetime.timedelta(seconds=0.5), poll_process)

else: # process did not finish within 2 minutes
else: # process did not finish in time
logging.error('timeout waiting for the zip process to finish')
try:
os.kill(process.pid, signal.SIGTERM)

except:
pass # nevermind

callback(None)

Expand Down Expand Up @@ -492,17 +502,22 @@ def read_media_list():
media_list.append(parent_pipe.recv())

def poll_media_list_process():
ioloop = tornado.ioloop.IOLoop.instance()
io_loop = IOLoop.instance()
if _timelapse_process.is_alive(): # not finished yet
now = datetime.datetime.now()
delta = now - started[0]
if delta.seconds < 300: # the subprocess has 5 minutes to complete its job
ioloop.add_timeout(datetime.timedelta(seconds=0.5), poll_media_list_process)
if delta.seconds < settings.TIMELAPSE_TIMEOUT: # the subprocess has limited time to complete its job
io_loop.add_timeout(datetime.timedelta(seconds=0.5), poll_media_list_process)
read_media_list()

else: # process did not finish within 2 minutes
else: # process did not finish in time
logging.error('timeout waiting for the media listing process to finish')
try:
os.kill(_timelapse_process.pid, signal.SIGTERM)

except:
pass # nevermind

_timelapse_process.progress = -1

else: # finished
Expand Down Expand Up @@ -573,9 +588,9 @@ def poll_movie_process(pictures):
global _timelapse_process
global _timelapse_data

ioloop = tornado.ioloop.IOLoop.instance()
io_loop = IOLoop.instance()
if _timelapse_process.poll() is None: # not finished yet
ioloop.add_timeout(datetime.timedelta(seconds=0.5), functools.partial(poll_movie_process, pictures))
io_loop.add_timeout(datetime.timedelta(seconds=0.5), functools.partial(poll_movie_process, pictures))

try:
output = _timelapse_process.stdout.read()
Expand Down Expand Up @@ -800,6 +815,8 @@ def clear():
logging.warn('key "%s" was still present in the prepared cache, removed' % key)

timeout = 3600 # the user has 1 hour to download the file after creation
ioloop.IOLoop.instance().add_timeout(datetime.timedelta(seconds=timeout), clear)

io_loop = IOLoop.instance()
io_loop.add_timeout(datetime.timedelta(seconds=timeout), clear)

return key
12 changes: 6 additions & 6 deletions motioneye/meyectl.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,6 @@
import pipes
import sys

from tornado.httpclient import AsyncHTTPClient

# make sure motioneye is on python path
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

Expand Down Expand Up @@ -178,6 +176,8 @@ def configure_logging(cmd, log_to_file=False):


def configure_tornado():
from tornado.httpclient import AsyncHTTPClient

AsyncHTTPClient.configure('tornado.curl_httpclient.CurlAsyncHTTPClient', max_clients=16)


Expand Down Expand Up @@ -242,21 +242,21 @@ def main():
command = sys.argv[1]
arg_parser = make_arg_parser(command)

import relayevent
import sendmail
import server
import webhook

if command in ('startserver', 'stopserver'):
import server
server.main(arg_parser, sys.argv[2:], command[:-6])

elif command == 'sendmail':
import sendmail
sendmail.main(arg_parser, sys.argv[2:])

elif command == 'relayevent':
import relayevent
relayevent.main(arg_parser, sys.argv[2:])

elif command == 'webhook':
import webhook
webhook.main(arg_parser, sys.argv[2:])

else:
Expand Down
13 changes: 7 additions & 6 deletions motioneye/mjpgclient.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,16 @@
import socket
import time

from tornado import iostream, ioloop
from tornado.ioloop import IOLoop
from tornado.iostream import IOStream

import config
import motionctl
import settings
import utils


class MjpgClient(iostream.IOStream):
class MjpgClient(IOStream):
clients = {} # dictionary of clients indexed by camera id
last_jpgs = {} # dictionary of jpg contents indexed by camera id
last_jpg_moment = {} # dictionary of moments of the last received jpeg indexed by camera id
Expand All @@ -45,12 +46,12 @@ def __init__(self, camera_id, port, username, password):
self._auth_digest_state = {}

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
iostream.IOStream.__init__(self, s)
IOStream.__init__(self, s)

self.set_close_callback(self.on_close)

def connect(self):
iostream.IOStream.connect(self, ('localhost', self._port), self._on_connect)
IOStream.connect(self, ('localhost', self._port), self._on_connect)
MjpgClient.clients[self._camera_id] = self

logging.debug('mjpg client for camera %(camera_id)s connecting on port %(port)s...' % {
Expand Down Expand Up @@ -212,7 +213,7 @@ def _on_jpg(self, data):

def start():
# schedule the garbage collector
io_loop = ioloop.IOLoop.instance()
io_loop = IOLoop.instance()
io_loop.add_timeout(datetime.timedelta(seconds=settings.MJPG_CLIENT_TIMEOUT), _garbage_collector)


Expand Down Expand Up @@ -258,7 +259,7 @@ def close_all(invalidate=False):
def _garbage_collector():
logging.debug('running garbage collector for mjpg clients...')

io_loop = ioloop.IOLoop.instance()
io_loop = IOLoop.instance()
io_loop.add_timeout(datetime.timedelta(seconds=settings.MJPG_CLIENT_TIMEOUT), _garbage_collector)

now = datetime.datetime.utcnow()
Expand Down
Loading

0 comments on commit fc19628

Please sign in to comment.