@@ -4,6 +4,7 @@ import winston = require("winston");
44import { nodered_settings } from "./nodered_settings" ;
55import { Config } from "./Config" ;
66import { WebSocketClient , NoderedUtil } from "openflow-api" ;
7+ import * as nodered from "node-red" ;
78// tslint:disable-next-line: class-name
89export class noderedcontribopenflowstorage {
910
@@ -20,7 +21,9 @@ export class noderedcontribopenflowstorage {
2021 public saveSessions : any ;
2122 public getLibraryEntry : any ;
2223 public saveLibraryEntry : any ;
24+ public RED : nodered . Red = null ;
2325 constructor ( logger : winston . Logger , socket : WebSocketClient ) {
26+ this . RED = nodered ;
2427 this . _logger = logger ;
2528 this . socket = socket ;
2629 this . getFlows = ( this . _getFlows . bind ( this ) ) ;
@@ -33,6 +36,146 @@ export class noderedcontribopenflowstorage {
3336 this . saveSessions = ( this . _saveSessions . bind ( this ) ) ;
3437 // this.getLibraryEntry = (this._getLibraryEntry.bind(this));
3538 // this.saveLibraryEntry = (this._saveLibraryEntry.bind(this));
39+ setTimeout ( this . CheckUpdates . bind ( this ) , Config . flow_refresh_interval ) ;
40+ }
41+
42+ // compare contents of two objects and return a list of differences
43+ // returns an array where each element is also an array in the form:
44+ // [accessor, diffType, leftValue, rightValue ]
45+ //
46+ // diffType is one of the following:
47+ // value: when primitive values at that index are different
48+ // undefined: when values in that index exist in one object but don't in
49+ // another; one of the values is always undefined
50+ // null: when a value in that index is null or undefined; values are
51+ // expressed as boolean values, indicated wheter they were nulls
52+ // type: when values in that index are of different types; values are
53+ // expressed as types
54+ // length: when arrays in that index are of different length; values are
55+ // the lengths of the arrays
56+ //
57+
58+ DiffObjects ( o1 , o2 ) {
59+ // choose a map() impl.
60+ // you may use $.map from jQuery if you wish
61+ var map = Array . prototype . map ?
62+ function ( a ) { return Array . prototype . map . apply ( a , Array . prototype . slice . call ( arguments , 1 ) ) ; } :
63+ function ( a , f ) {
64+ var ret = new Array ( a . length ) , value ;
65+ for ( var i = 0 , length = a . length ; i < length ; i ++ )
66+ ret [ i ] = f ( a [ i ] , i ) ;
67+ return ret . concat ( ) ;
68+ } ;
69+
70+ // shorthand for push impl.
71+ var push = Array . prototype . push ;
72+
73+ // check for null/undefined values
74+ if ( ( o1 == null ) || ( o2 == null ) ) {
75+ if ( o1 != o2 )
76+ return [ [ "" , "null" , o1 != null , o2 != null ] ] ;
77+
78+ return undefined ; // both null
79+ }
80+ // compare types
81+ if ( ( o1 . constructor != o2 . constructor ) ||
82+ ( typeof o1 != typeof o2 ) ) {
83+ return [ [ "" , "type" , Object . prototype . toString . call ( o1 ) , Object . prototype . toString . call ( o2 ) ] ] ; // different type
84+
85+ }
86+
87+ // compare arrays
88+ if ( Object . prototype . toString . call ( o1 ) == "[object Array]" ) {
89+ if ( o1 . length != o2 . length ) {
90+ return [ [ "" , "length" , o1 . length , o2 . length ] ] ; // different length
91+ }
92+ var diff = [ ] ;
93+ for ( var i = 0 ; i < o1 . length ; i ++ ) {
94+ // per element nested diff
95+ var innerDiff = this . DiffObjects ( o1 [ i ] , o2 [ i ] ) ;
96+ if ( innerDiff ) { // o1[i] != o2[i]
97+ // merge diff array into parent's while including parent object name ([i])
98+ push . apply ( diff , map ( innerDiff , function ( o , j ) { o [ 0 ] = "[" + i + "]" + o [ 0 ] ; return o ; } ) ) ;
99+ }
100+ }
101+ // if any differences were found, return them
102+ if ( diff . length )
103+ return diff ;
104+ // return nothing if arrays equal
105+ return undefined ;
106+ }
107+
108+ // compare object trees
109+ if ( Object . prototype . toString . call ( o1 ) == "[object Object]" ) {
110+ var diff = [ ] ;
111+ // check all props in o1
112+ for ( var prop in o1 ) {
113+ // the double check in o1 is because in V8 objects remember keys set to undefined
114+ if ( ( typeof o2 [ prop ] == "undefined" ) && ( typeof o1 [ prop ] != "undefined" ) ) {
115+ // prop exists in o1 but not in o2
116+ diff . push ( [ "[" + prop + "]" , "undefined" , o1 [ prop ] , undefined ] ) ; // prop exists in o1 but not in o2
117+
118+ }
119+ else {
120+ // per element nested diff
121+ var innerDiff = this . DiffObjects ( o1 [ prop ] , o2 [ prop ] ) ;
122+ if ( innerDiff ) { // o1[prop] != o2[prop]
123+ // merge diff array into parent's while including parent object name ([prop])
124+ push . apply ( diff , map ( innerDiff , function ( o , j ) { o [ 0 ] = "[" + prop + "]" + o [ 0 ] ; return o ; } ) ) ;
125+ }
126+
127+ }
128+ }
129+ for ( var prop in o2 ) {
130+ // the double check in o2 is because in V8 objects remember keys set to undefined
131+ if ( ( typeof o1 [ prop ] == "undefined" ) && ( typeof o2 [ prop ] != "undefined" ) ) {
132+ // prop exists in o2 but not in o1
133+ diff . push ( [ "[" + prop + "]" , "undefined" , undefined , o2 [ prop ] ] ) ; // prop exists in o2 but not in o1
134+
135+ }
136+ }
137+ // if any differences were found, return them
138+ if ( diff . length )
139+ return diff ;
140+ // return nothing if objects equal
141+ return undefined ;
142+ }
143+ // if same type and not null or objects or arrays
144+ // perform primitive value comparison
145+ if ( o1 != o2 )
146+ return [ [ "" , "value" , o1 , o2 ] ] ;
147+
148+ // return nothing if values are equal
149+ return undefined ;
150+ }
151+
152+ private _flows : any [ ] = null ;
153+ public async CheckUpdates ( ) {
154+ try {
155+ let flows : any [ ] = await this . _getFlows ( ) ;
156+ if ( this . _flows != null ) {
157+ let update : boolean = false ;
158+ if ( flows . length != this . _flows . length ) {
159+ update = true ;
160+ } else {
161+ for ( let i = 0 ; i < flows . length ; i ++ ) {
162+ if ( this . DiffObjects ( flows [ i ] , this . _flows [ i ] ) ) {
163+ update = true ;
164+ break ;
165+ }
166+ }
167+ }
168+ if ( update ) {
169+ this . _flows = flows ;
170+ await this . RED . nodes . loadFlows ( true ) ;
171+ }
172+ } else {
173+ this . _flows = flows ;
174+ }
175+ } catch ( error ) {
176+ this . _logger . error ( error ) ;
177+ }
178+ setTimeout ( this . CheckUpdates . bind ( this ) , Config . flow_refresh_interval ) ;
36179 }
37180 public async init ( settings : any ) : Promise < boolean > {
38181 this . _logger . silly ( "noderedcontribopenflowstorage::init" ) ;
@@ -96,6 +239,7 @@ export class noderedcontribopenflowstorage {
96239 result [ 0 ] . flows = JSON . stringify ( flows ) ;
97240 await NoderedUtil . UpdateOne ( "nodered" , null , result [ 0 ] , 1 , true , null ) ;
98241 }
242+ this . _flows = flows ;
99243 } catch ( error ) {
100244 if ( error . message ) { this . _logger . error ( error . message ) ; }
101245 else { this . _logger . error ( error ) ; }
0 commit comments