LCOV - code coverage report
Current view: top level - lib/src - wilt_change_notification.dart (source / functions) Hit Total Coverage
Test: coverage.lcov Lines: 43 57 75.4 %
Date: 2017-07-19 Functions: 0 0 -

          Line data    Source code
       1             : /*
       2             :  * Packge : Wilt
       3             :  * Author : S. Hamblett <steve.hamblett@linux.com>
       4             :  * Date   : 07/01/2014
       5             :  * Copyright :  S.Hamblett@OSCF
       6             :  *
       7             :  * Change notification control class
       8             :  * 
       9             :  * This class when constructed initiates change notification processing with either
      10             :  * a default set of change notification parameters or one supplied by the client.
      11             :  * When destroyed, change notification ceases.
      12             :  * 
      13             :  * 
      14             :  * The resulting notifications are turned into notification events and streamed to
      15             :  * the notification consumer. as a stream of WiltChangeNotificationEvent objects, see 
      16             :  * this class for further details.
      17             :  * 
      18             :  * CouchDb is initialized to supply the change notification stream in 'normal' mode, hence
      19             :  * this class requests the updates manually on a timed basis dependent on the heartberat period.
      20             :  * 
      21             :  * Note that as form CouchDB 1.6.1 you must auth as an administrator with CouchDb
      22             :  * to allow notificatons to work, if you do not supply auth credentials before 
      23             :  * starting notifications an exception is raised. 
      24             :  */
      25             : 
      26             : part of wilt;
      27             : 
      28             : class _WiltChangeNotification {
      29             :   _WiltChangeNotification(
      30             :       this._host, this._port, this._scheme, this._httpAdapter,
      31           1 :       [this._dbName, this._parameters]) {
      32           1 :     if (_parameters == null) {
      33           2 :       _parameters = new WiltChangeNotificationParameters();
      34             :     }
      35             : 
      36           3 :     _sequence = _parameters.since;
      37             : 
      38             :     /**
      39             :      * Start the heartbeat timer
      40             :      */
      41             :     final Duration heartbeat =
      42           3 :         new Duration(milliseconds: _parameters.heartbeat);
      43           3 :     _timer = new Timer.periodic(heartbeat, _requestChanges);
      44             : 
      45             :     /**
      46             :      * Start change notifications
      47             :      */
      48           2 :     _requestChanges(_timer);
      49             :   }
      50             : 
      51             :   /// Parameters set
      52             :   WiltChangeNotificationParameters _parameters = null;
      53           0 :   WiltChangeNotificationParameters get parameters => _parameters;
      54             :   set parameters(WiltChangeNotificationParameters parameters) =>
      55           0 :       _parameters = parameters;
      56             : 
      57             :   /// Database name
      58             :   String _dbName = null;
      59             : 
      60             :   /// Host name
      61             :   String _host = null;
      62             : 
      63             :   /// Port number
      64             :   String _port = null;
      65             : 
      66             :   /// HTTP scheme
      67             :   String _scheme = null;
      68             : 
      69             :   /// Timer
      70             :   Timer _timer = null;
      71             : 
      72             :   /// Since sequence number
      73             :   int _sequence = 0;
      74             : 
      75             :   /// Paused indicator
      76             :   bool _paused = false;
      77           1 :   bool get pause => _paused;
      78           1 :   set pause(bool flag) => _paused = flag;
      79             : 
      80             :   WiltHTTPAdapter _httpAdapter = null;
      81             : 
      82             :   /// Change notification stream controller
      83             :   ///
      84             :   /// Populated with WiltChangeNotificationEvent events
      85             :   final StreamController _changeNotification = new StreamController.broadcast();
      86           1 :   StreamController get changeNotification => _changeNotification;
      87             : 
      88             :   /// Request the change notifications
      89             :   void _requestChanges(Timer timer) {
      90             :     /**
      91             :      * If paused return
      92             :      */
      93           1 :     if (_paused) return;
      94             : 
      95             :     /**
      96             :      * Create the URL from the parameters
      97             :      */
      98           2 :     final String sequence = _sequence.toString();
      99           2 :     final String path = "$_dbName/_changes?" +
     100           1 :         "&since=$sequence" +
     101           3 :         "&descending=${_parameters.descending}" +
     102           3 :         "&include_docs=${_parameters.includeDocs}" +
     103           3 :         "&attachments=${_parameters.includeAttachments}";
     104             : 
     105           5 :     final String url = "$_scheme$_host:${_port.toString()}/$path";
     106             : 
     107             :     /**
     108             :      * Open the request
     109             :      */
     110             :     try {
     111           2 :       _httpAdapter.getString(url)
     112           1 :         ..then((result) {
     113             :           /**
     114             :         * Process the change notification
     115             :         */
     116             :           try {
     117           1 :             final Map dbChange = JSON.decode(result);
     118           1 :             processDbChange(dbChange);
     119             :           } catch (e) {
     120             :             /**
     121             :           * Recoverable error, send the client an error event
     122             :           */
     123           0 :             print(
     124           0 :                 "WiltChangeNotification::MonitorChanges JSON decode fail ${e.toString()}");
     125             :             final WiltChangeNotificationEvent notification =
     126           0 :                 new WiltChangeNotificationEvent.decodeError(
     127           0 :                     result, e.toString());
     128             : 
     129           0 :             _changeNotification.add(notification);
     130             :           }
     131             :         });
     132             :     } catch (e) {
     133             :       /**
     134             :        * Unrecoverable error, send the client an abort event
     135             :        */
     136           0 :       print(
     137           0 :           "WiltChangeNotification::MonitorChanges unable to contact CouchDB Error is ${e.toString()}");
     138             :       final WiltChangeNotificationEvent notification =
     139           0 :           new WiltChangeNotificationEvent.abort(e.toString());
     140             : 
     141           0 :       _changeNotification.add(notification);
     142             :     }
     143             :   }
     144             : 
     145             :   /// Database change updates
     146             :   void processDbChange(Map change) {
     147             :     /**
     148             :      * Check for an error response
     149             :      */
     150           1 :     if (change.containsKey('error')) {
     151             :       final WiltChangeNotificationEvent notification =
     152           0 :           new WiltChangeNotificationEvent.couchDbError(
     153           0 :               change['error'], change['reason']);
     154             : 
     155           0 :       _changeNotification.add(notification);
     156             : 
     157             :       return;
     158             :     }
     159             : 
     160             :     /**
     161             :      * Update the last sequence number
     162             :      */
     163           2 :     _sequence = change['last_seq'];
     164             : 
     165             :     /**
     166             :      * Process the result list
     167             :      */
     168           1 :     final List results = change['results'];
     169           1 :     if (results.isEmpty) {
     170             :       final WiltChangeNotificationEvent notification =
     171           2 :           new WiltChangeNotificationEvent.sequence(_sequence);
     172             : 
     173           2 :       _changeNotification.add(notification);
     174             : 
     175             :       return;
     176             :     }
     177             : 
     178           1 :     results.forEach((Map result) {
     179           2 :       final Map changes = result['changes'][0];
     180             : 
     181             :       /**
     182             :        * Check for delete or update
     183             :        */
     184           1 :       if (result.containsKey('deleted')) {
     185             :         final WiltChangeNotificationEvent notification =
     186           1 :             new WiltChangeNotificationEvent.delete(
     187           3 :                 result['id'], changes['rev'], result['seq']);
     188             : 
     189           2 :         _changeNotification.add(notification);
     190             :       } else {
     191             :         jsonobject.JsonObject document = null;
     192           1 :         if (result.containsKey('doc')) {
     193           2 :           document = new jsonobject.JsonObject.fromMap(result['doc']);
     194             :         }
     195             :         final WiltChangeNotificationEvent notification =
     196           1 :             new WiltChangeNotificationEvent.update(
     197           3 :                 result['id'], changes['rev'], result['seq'], document);
     198             : 
     199           2 :         _changeNotification.add(notification);
     200             :       }
     201             :     });
     202             :   }
     203             : 
     204             :   /// Stop change notifications
     205             :   void stopNotifications() {
     206           2 :     _timer.cancel();
     207             :   }
     208             : 
     209             :   /// Restart change notifications
     210             :   void restartChangeNotifications() {
     211             :     /**
     212             :      * Start the heartbeat timer
     213             :      */
     214             :     final Duration heartbeat =
     215           3 :         new Duration(milliseconds: _parameters.heartbeat);
     216           3 :     _timer = new Timer.periodic(heartbeat, _requestChanges);
     217             : 
     218             :     /**
     219             :      * Start change notifications
     220             :      */
     221           2 :     _requestChanges(_timer);
     222             :   }
     223             : }

Generated by: LCOV version 1.10