]> www.vanbest.org Git - motioneye-debian/commitdiff
fixed compatibility issue with older tornado versions (where no
authorCalin Crisan <ccrisan@gmail.com>
Thu, 16 Jan 2014 16:14:10 +0000 (18:14 +0200)
committerCalin Crisan <ccrisan@gmail.com>
Thu, 16 Jan 2014 16:14:10 +0000 (18:14 +0200)
IOStream.error attribute is available)

src/handlers.py
src/mjpgclient.py
src/remote.py
static/js/main.js

index 81e86de6fce931aa8e19f06bb0dad373fa4c505e..94adaff9a804cdaa7dfe89e6256e11aa4b1670d5 100644 (file)
@@ -16,6 +16,7 @@
 # along with this program.  If not, see <http://www.gnu.org/licenses/>. 
 
 import base64
+import functools
 import json
 import logging
 import os
@@ -189,47 +190,38 @@ class ConfigHandler(BaseHandler):
             self.finish_json(ui_config)
     
     @BaseHandler.auth(admin=True)
-    def set_config(self, camera_id, ui_config=None, no_finish=False):
-        if ui_config is None:
-            try:
-                ui_config = json.loads(self.request.body)
-                
-            except Exception as e:
-                logging.error('could not decode json: %(msg)s' % {'msg': unicode(e)})
-                
-                raise
+    def set_config(self, camera_id):
+        try:
+            ui_config = json.loads(self.request.body)
+            
+        except Exception as e:
+            logging.error('could not decode json: %(msg)s' % {'msg': unicode(e)})
             
-        reload = False
+            raise
         
-        if camera_id is not None:
-            if camera_id == 0:
-                logging.debug('setting multiple configs')
-                
-                for key, cfg in ui_config.items():
-                    if key == 'main':
-                        reload = self.set_config(None, cfg, no_finish=True) or reload
-                        
-                    else:
-                        reload = self.set_config(int(key), cfg, no_finish=True) or reload
-
-                return self.finish_json({'reload': reload})
-                 
-            logging.debug('setting config for camera %(id)s' % {'id': camera_id})
+        camera_ids = config.get_camera_ids()
+        
+        def set_camera_config(camera_id, ui_config, on_finish):
+            logging.debug('setting config for camera %(id)s...' % {'id': camera_id})
             
-            camera_ids = config.get_camera_ids()
             if camera_id not in camera_ids:
                 raise HTTPError(404, 'no such camera')
             
             local_config = config.get_camera(camera_id)
             if local_config['@proto'] == 'v4l2':
-#                 ui_config.setdefault('device', local_config.get('videodevice', '')) TODO needed?
-#                 ui_config.setdefault('proto', local_config['@proto'])
-#                 ui_config.setdefault('enabled', local_config['@enabled'])
+                # overwrite some fields whose values should not be changed this way
+                ui_config['device_uri'] = local_config['videodevice']
+                ui_config['proto'] = 'v4l2'
+                ui_config['host'] = ''
+                ui_config['port'] = ''
+                ui_config.setdefault('enabled', True)
                 
                 local_config = config.camera_ui_to_dict(ui_config)
                 config.set_camera(camera_id, local_config)
-                
-            else:  # remote camera
+            
+                on_finish(None, True) # (no error, motion needs restart)
+        
+            else:
                 # update the camera locally
                 local_config['@enabled'] = ui_config['enabled']
                 config.set_camera(camera_id, local_config)
@@ -238,27 +230,20 @@ class ConfigHandler(BaseHandler):
                 # the camera was probably disabled due to errors
 
                 if ui_config.has_key('device_uri'):
-                    # remove the fields that should not get to the remote side
+                    # delete some fields that should not get to the remote side as they are
                     del ui_config['device_uri']
                     del ui_config['proto']
                     del ui_config['host']
                     del ui_config['port']
                     del ui_config['enabled']
                     
-                    try:
-                        remote.set_config(local_config, ui_config)
-                        
-                    except Exception as e:
-                        logging.error('failed to set remote camera config: %(msg)s' % {'msg': unicode(e)})
-                        
-                        if not no_finish:
-                            return self.finish_json({'error': unicode(e)})
-                
-                elif not no_finish:
-                    return self.finish_json({'error': unicode(e)})       
+                    def on_finish_wrapper(error):
+                        return on_finish(error, False)
+                    
+                    remote.set_config(local_config, ui_config, on_finish_wrapper)
 
-        else:
-            logging.debug('setting main config')
+        def set_main_config(ui_config):
+            logging.debug('setting main config...')
             
             old_main_config = config.get_main()
             old_admin_credentials = old_main_config.get('@admin_username', '') + ':' + old_main_config.get('@admin_password', '')
@@ -271,14 +256,51 @@ class ConfigHandler(BaseHandler):
             if admin_credentials != old_admin_credentials:
                 logging.debug('admin credentials changed, reload needed')
                 
-                reload = True 
+                return True # needs browser reload
+                
+            return False
+        
+        reload = False # indicates that browser should reload the page
+        restart = [False]  # indicates that the local motion instance was modified and needs to be restarted
+        error = [None]
+        
+        def finish():
+            if restart[0]:
+                logging.debug('motion needs to be restarted')
+                motionctl.restart()
 
-        motionctl.restart() # TODO should not be restarted unless a local camera was changed
+            self.finish({'reload': reload, 'error': error[0]})
         
-        if not no_finish:
-            self.finish_json()
+        if camera_id is not None:
+            if camera_id == 0: # multiple camera configs
+                logging.debug('setting multiple configs')
+                
+                so_far = [0]
+                def check_finished(e, r):
+                    restart[0] = restart[0] or r
+                    error[0] = error[0] or e
+                    so_far[0] += 1
+                    
+                    if so_far[0] >= len(ui_config): # finished
+                        finish()
         
-        return reload
+                for key, cfg in ui_config.items():
+                    if key == 'main':
+                        reload = set_main_config(cfg) or reload
+                        
+                    else:
+                        set_camera_config(int(key), cfg, check_finished)
+            
+            else: # single camera config
+                def on_finish(e, r):
+                    error[0] = e
+                    restart[0] = r
+                    finish()
+
+                set_camera_config(camera_id, ui_config, on_finish)
+
+        else: # main config
+            reload = set_main_config(ui_config)
 
     @BaseHandler.auth(admin=True)
     def set_preview(self, camera_id):
index 73a5d92ad9a2fa8974becd3a9c4af351b7cc165e..33609c2e221f8b087d05c31d727552be8b57f11c 100644 (file)
@@ -70,10 +70,11 @@ class MjpgClient(iostream.IOStream):
             
             return True
             
-        if self.error is None:
+        error = getattr(self, 'error', None)
+        if error is None:
             return False
         
-        self._error(self.error)
+        self._error(error)
         
         return True
      
index cbcde73cfa79d15c3a7eec94e12fe8f3d3ea5bc6..53a27e89e84ef9e54d25ba09f696e6d74a1f48fb 100644 (file)
@@ -18,7 +18,7 @@
 import json
 import logging
 
-from tornado.httpclient import AsyncHTTPClient, HTTPClient, HTTPRequest
+from tornado.httpclient import AsyncHTTPClient, HTTPRequest
 
 import settings
 
@@ -126,7 +126,7 @@ def get_config(local_config, callback):
     http_client.fetch(request, on_response)
     
 
-def set_config(local_config, camera_config):
+def set_config(local_config, ui_config, callback):
     host = local_config.get('@host', local_config.get('host')) 
     port = local_config.get('@port', local_config.get('port'))
     username = local_config.get('@username', local_config.get('username'))
@@ -138,24 +138,24 @@ def set_config(local_config, camera_config):
             'host': host,
             'port': port})
     
-    camera_config = json.dumps(camera_config)
+    ui_config = json.dumps(ui_config)
     
-    request = _make_request(host, port, username, password, '/config/%(id)s/set/' % {'id': camera_id}, method='POST', data=camera_config)
+    request = _make_request(host, port, username, password, '/config/%(id)s/set/' % {'id': camera_id}, method='POST', data=ui_config)
     
-    try:
-        http_client = HTTPClient()
-        response = http_client.fetch(request)
+    def on_response(response):
         if response.error:
-            raise Exception(unicode(response.error)) 
-    
-    except Exception as e:
-        logging.error('failed to set config for remote camera %(id)s on %(host)s:%(port)s: %(msg)s' % {
-                'id': camera_id,
-                'host': host,
-                'port': port,
-                'msg': unicode(e)})
-        
-        raise
+            logging.error('failed to set config for remote camera %(id)s on %(host)s:%(port)s: %(msg)s' % {
+                    'id': camera_id,
+                    'host': host,
+                    'port': port,
+                    'msg': unicode(response.error)})
+            
+            return callback(response.error)
+    
+        callback(None)
+
+    http_client = AsyncHTTPClient()
+    http_client.fetch(request, on_response)
 
 
 def set_preview(local_config, controls, callback):
index a8043090289a68d474b789bc80691fa557d605ae..ba24f1ed48f094c16c42e296adbb7d6278c697a4 100644 (file)
@@ -752,7 +752,7 @@ function beginProgress(cameraIds) {
     /* show the camera progress indicators */
     if (cameraIds) {
         cameraIds.forEach(function (cameraId) {
-            $('div.camera-frame#' + cameraId + ' div.camera-progress').css('opacity', '0.5');
+            $('div.camera-frame#camera' + cameraId + ' div.camera-progress').css('opacity', '0.5');
         });
     }
     else {
@@ -830,7 +830,32 @@ function doApply() {
         return;
     }
     
-    beginProgress();
+    /* gather the affected motion instances */
+    var affectedInstances = {};
+    Object.keys(pushConfigs).forEach(function (key) {
+        var config = pushConfigs[key];
+        if (key === 'main') {
+            return;
+        }
+        
+        var instance = config.host || '';
+        if (config.port) {
+            instance += ':' + config.port;
+        }
+        
+        affectedInstances[instance] = true;
+    });
+    affectedInstances = Object.keys(affectedInstances);
+    
+    /* compute the affected camera ids */ 
+    var cameraIdsByInstance = getCameraIdsByInstance();
+    var affectedCameraIds = [];
+    
+    affectedInstances.forEach(function (instance) {
+        affectedCameraIds = affectedCameraIds.concat(cameraIdsByInstance[instance] || []);
+    });
+    
+    beginProgress(affectedCameraIds);
     
     ajax('POST', '/config/0/set/', pushConfigs, function (data) {
         if (data == null || data.error) {
@@ -1078,7 +1103,20 @@ function pushPreview(control) {
 }
 
 function getCameraIdsByInstance() {
+    /* a motion instance is identified by the (host, port) pair;
+     * the local instance has both the host and the port set to empty string */
+    
+    var cameraIdsByInstance = {};
+    $('div.camera-frame').each(function () {
+        var instance = this.config.host || '';
+        if (this.config.port) {
+            instance += ':' + this.config.port;
+        }
+        
+        (cameraIdsByInstance[instance] = cameraIdsByInstance[instance] || []).push(this.config.id);
+    });
     
+    return cameraIdsByInstance;
 }
 
 
@@ -1632,16 +1670,18 @@ function runMediaDialog(cameraId, mediaType) {
 
     /* camera frames */
 
-function addCameraFrameUi(cameraId, cameraName, framerate) {
+function addCameraFrameUi(cameraConfig, framerate) {
     var pageContainer = $('div.page-container');
     
-    if (cameraId == null) {
+    if (cameraConfig == null) {
         var cameraFrameDivPlaceHolder = $('<div class="camera-frame-place-holder"></div>');
         pageContainer.append(cameraFrameDivPlaceHolder);
         
         return;
     }
     
+    var cameraId = cameraConfig.id;
+    
     var cameraFrameDiv = $(
             '<div class="camera-frame">' +
                 '<div class="camera-top-bar">' +
@@ -1650,7 +1690,6 @@ function addCameraFrameUi(cameraId, cameraName, framerate) {
                         '<div class="button camera-button mouse-effect media-pictures" title="pictures"></div>' +
                         '<div class="button camera-button mouse-effect media-movies" title="movies"></div>' +
                         '<div class="button camera-button mouse-effect configure" title="configure"></div>' +
-//                        '<div class="button camera-button mouse-effect full-screen" title="full screen"></div>' +
                     '</div>' +
                 '</div>' +
                 '<div class="camera-container">' +
@@ -1678,7 +1717,8 @@ function addCameraFrameUi(cameraId, cameraName, framerate) {
     cameraFrameDiv.attr('id', 'camera' + cameraId);
     cameraFrameDiv[0].framerate = framerate;
     cameraFrameDiv[0].refreshDivider = 0;
-    nameSpan.html(cameraName);
+    cameraFrameDiv[0].config = cameraConfig;
+    nameSpan.html(cameraConfig.name);
     progressImg.attr('src', staticUrl + 'img/camera-progress.gif');
     
     cameraProgress.click(function () {
@@ -1789,7 +1829,7 @@ function recreateCameraFrames(cameras) {
         /* add camera frames */
         for (i = 0; i < cameras.length; i++) {
             camera = cameras[i];
-            addCameraFrameUi(camera.id, camera.name, Math.min(camera.streaming_framerate, camera.framerate));
+            addCameraFrameUi(camera, Math.min(camera.streaming_framerate, camera.framerate));
         }
         
         if ($('#videoDeviceSelect').find('option').length < 2 && user === 'admin' && $('#motionEyeSwitch')[0].checked) {