Skip to content

Commit 8e20e4c

Browse files
committed
Add auto refreshing of workflows
1 parent c27ef20 commit 8e20e4c

2 files changed

Lines changed: 146 additions & 0 deletions

File tree

OpenFlowNodeRED/src/Config.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ export class Config {
7777
public static noderedusers: string = Config.getEnv("noderedusers", "");
7878
public static noderedadmins: string = Config.getEnv("noderedadmins", "");
7979

80+
public static flow_refresh_interval: number = parseInt(Config.getEnv("port", "60000"));
81+
8082
public static api_ws_url: string = Config.getEnv("api_ws_url", "ws://localhost:3000");
8183
public static amqp_url: string = Config.getEnv("amqp_url", "amqp://localhost");
8284
// public static amqp_reply_expiration: number = parseInt(Config.getEnv("amqp_reply_expiration", (60 * 1000).toString())); // 1 min

OpenFlowNodeRED/src/node-red-contrib-openflow-storage.ts

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import winston = require("winston");
44
import { nodered_settings } from "./nodered_settings";
55
import { Config } from "./Config";
66
import { WebSocketClient, NoderedUtil } from "openflow-api";
7+
import * as nodered from "node-red";
78
// tslint:disable-next-line: class-name
89
export 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

Comments
 (0)