Implement path alias unpacking

This commit is contained in:
Zaid Abdulla committed 2016-07-20 03:29:19 +03:00
1 parent 788bd98c8c
commit 1537603945
7 files changed
+691 -541

No files matched your search

+23
View File
@@ -235,18 +235,22 @@ parseAlias = (pattern, start, res) ->
parsePath = (pattern, start, res) -> parsePath = (pattern, start, res) ->
path = [] path = []
path.wildcard = 0
path.alias = 0
i = start ? 0 i = start ? 0
# Colon separator is needed for parseAlias # Colon separator is needed for parseAlias
if i < pattern.length and pattern[i] != ':' if i < pattern.length and pattern[i] != ':'
while true while true
if pattern[i] == '[' if pattern[i] == '['
path.alias |= 1 << path.length
i = parseAlias(pattern, i + 1, path) + 1 i = parseAlias(pattern, i + 1, path) + 1
else else
j = i j = i
while i < pattern.length and pattern[i] != ':' and pattern[i] != '.' while i < pattern.length and pattern[i] != ':' and pattern[i] != '.'
++ i ++ i
n = pattern.slice(j, i) n = pattern.slice(j, i)
path.wildcard |= 1 << path.length if n == '*'
path.push(n) path.push(n)
if i >= pattern.length or pattern[i] == ':' if i >= pattern.length or pattern[i] == ':'
@@ -256,6 +260,8 @@ parsePath = (pattern, start, res) ->
++ i ++ i
Object.freeze(path)
if not res? if not res?
return path return path
@@ -263,6 +269,22 @@ parsePath = (pattern, start, res) ->
return i return i
addPathMeta = (path) ->
path.alias = 0
path.wildcard = 0
for p, i in path
if typeOf(p) is ARRAY_TYPE
path.alias |= 1 << i
for j in [0...p.length] by 2
addPathMeta(p[j])
else if p == '*'
path.wildcard |= 1 << i
Object.freeze(path)
return path
hammingWeight = (flags) -> hammingWeight = (flags) ->
flags -= ((flags >> 1) & 0x55555555) flags -= ((flags >> 1) & 0x55555555)
flags = (((flags >> 2) & 0x33333333) + (flags & 0x33333333)) flags = (((flags >> 2) & 0x33333333) + (flags & 0x33333333))
@@ -283,4 +305,5 @@ exports.REGEXP_TYPE = REGEXP_TYPE
exports.typeOf = typeOf exports.typeOf = typeOf
exports.pathOverlap = pathOverlap exports.pathOverlap = pathOverlap
exports.parsePath = parsePath exports.parsePath = parsePath
exports.addPathMeta = addPathMeta
exports.hammingWeight = hammingWeight exports.hammingWeight = hammingWeight
+11 -6
View File
@@ -127,8 +127,9 @@ applyPresets = (currentRequest) ->
return sendRpcRequest(currentRequest, id, rpcRequest) return sendRpcRequest(currentRequest, id, rpcRequest)
for k, v of parameters for k, v of parameters
if (vv = device.getAll(currentRequest.sessionData.deviceData, v)[0]?[8]?[0]) unpacked = device.unpack(currentRequest.sessionData.deviceData, v)
parameters[k] = vv if unpacked[0] and (vv = deviceData.values.value.get(unpacked[0]))?
parameters[k] = vv[0]
for p in presets for p in presets
if query.test(parameters, p.precondition) if query.test(parameters, p.precondition)
@@ -272,8 +273,9 @@ listener = (httpRequest, httpResponse) ->
return body return body
stream.on('end', () -> stream.on('end', () ->
getSession(httpRequest, (sessionId, sessionData) -> cwmpRequest = null
cwmpRequest = soap.request(httpRequest, session?.cwmpVersion) getSession(httpRequest, f = (sessionId, sessionData) ->
cwmpRequest ?= soap.request(httpRequest, sessionData?.cwmpVersion)
if not sessionData? if not sessionData?
if cwmpRequest.methodRequest?.type isnt 'Inform' if cwmpRequest.methodRequest?.type isnt 'Inform'
httpResponse.writeHead(400) httpResponse.writeHead(400)
@@ -281,8 +283,11 @@ listener = (httpRequest, httpResponse) ->
return return
deviceId = common.generateDeviceId(cwmpRequest.methodRequest.deviceId) deviceId = common.generateDeviceId(cwmpRequest.methodRequest.deviceId)
sessionData = session.init(deviceId, cwmpRequest.cwmpVersion, cwmpRequest.sessionTimeout ? config.get('SESSION_TIMEOUT', deviceId)) return session.init(deviceId, cwmpRequest.cwmpVersion, cwmpRequest.sessionTimeout ? config.get('SESSION_TIMEOUT', deviceId), (err, sessionData) ->
httpRequest.connection.setTimeout(sessionData.timeout * 1000) throw err if err
httpRequest.connection.setTimeout(sessionData.timeout * 1000)
f(null, sessionData)
)
currentRequest = { currentRequest = {
httpRequest : httpRequest, httpRequest : httpRequest,
+1 -1
View File
@@ -452,7 +452,7 @@ saveDevice = (deviceId, deviceData, isNew, callback) ->
# Set object's children timestamps # Set object's children timestamps
iter = deviceData.timestamps.exist.diff() iter = deviceData.timestamps.exist.diff()
while not (diff = iter.next()).done while not (diff = iter.next()).done
continue if diff.value[0].wildcards != (1 << (diff.value[0].length - 1)) continue if diff.value[0].wildcard != (1 << (diff.value[0].length - 1))
continue if diff.value[0][0] in ['Events', 'DeviceID', 'Tags'] continue if diff.value[0][0] in ['Events', 'DeviceID', 'Tags']
if not diff.value[2]? and diff.value[1]? if not diff.value[2]? and diff.value[1]?
+86 -17
View File
@@ -61,12 +61,6 @@ function sanitizeParameterValue(parameterValue) {
} }
function getAliasDeclarations(path) {
// TODO Return declarations necessary for unpacking aliases
return [];
}
function inferTimestamps(deviceData, path) { function inferTimestamps(deviceData, path) {
var res = {}; var res = {};
@@ -79,14 +73,14 @@ function inferTimestamps(deviceData, path) {
} }
for (let i = path.length - 1; i > 0; -- i) { for (let i = path.length - 1; i > 0; -- i) {
if (path.wildcards & ((2 << i) - 1) === 0) if (path.wildcard & ((2 << i) - 1) === 0)
break; break;
let param = null; let param = null;
let ancestor = path.slice(0, i); let ancestor = path.slice(0, i);
let ancestorTimestamp = 0; let ancestorTimestamp = 0;
for (let sup of deviceData.paths.superset(ancestor)) { for (let sup of deviceData.paths.superset(ancestor)) {
if (!sup.wildcards) if (!sup.wildcard)
param = sup; param = sup;
let t = deviceData.timestamps.exist.get(sup); let t = deviceData.timestamps.exist.get(sup);
@@ -108,7 +102,7 @@ function inferTimestamps(deviceData, path) {
newt[attrName] = ancestorTimestamp; newt[attrName] = ancestorTimestamp;
for (let sub of deviceData.paths.subset(ancestor)) { for (let sub of deviceData.paths.subset(ancestor)) {
if (sub.wildcards) if (sub.wildcard)
continue; continue;
let subt = inferTimestamps(deviceData, sub.concat(path.slice(sub.length, path.length))); let subt = inferTimestamps(deviceData, sub.concat(path.slice(sub.length, path.length)));
for (let attrName in newt) { for (let attrName in newt) {
@@ -128,9 +122,84 @@ function inferTimestamps(deviceData, path) {
} }
function getAliasDeclarations(path, timestamp) {
var decs = [];
function recursive(pattern, prefix) {
var pattern = prefix.concat(pattern);
for (let i = prefix.length; i < pattern.length; ++ i) {
if (Array.isArray(pattern[i])) {
let pat = pattern[i];
pattern[i] = '*';
for (let j = 0; j < pat.length; j += 2)
recursive(pat[j], pattern.slice(0, i + 1));
}
}
if (prefix.length)
decs.push([pattern, {exist: timestamp, value: timestamp}]);
else
decs.push([pattern, {exist: timestamp}]);
}
recursive(path, []);
return decs;
}
function unpack(deviceData, path, revision) { function unpack(deviceData, path, revision) {
// TODO implement alias unpacking let allMatches = [];
return [path]; if (path.alias == 0) {
for (let p of deviceData.paths.subset(path, 0))
if (deviceData.values.exist.get(p, revision))
allMatches.push(p);
return allMatches;
}
let wildcardPath = path.slice();
wildcardPath.wildcard = path.wildcard;
for (let i = 0; i < wildcardPath.length; ++ i)
if (Array.isArray(wildcardPath[i])) {
wildcardPath[i] = '*';
wildcardPath.wildcard |= 1 << i;
}
for (let p of deviceData.paths.subset(wildcardPath, 0))
if (deviceData.values.exist.get(p, revision))
allMatches.push(p);
for (let i = path.length - 1; i >= 0; -- i) {
if (Array.isArray(path[i])) {
for (let j = 0; j < path[i].length; j += 2) {
let p = wildcardPath.slice(0, i + 1).concat(path[i][j]);
p.alias = (wildcardPath.alias & ((1 << (i + 1)) - 1)) + path[i][j].alias << (i + 1);
p.wildcard = (wildcardPath.wildcard & ((1 << (i + 1)) - 1)) + path[i][j].wildcard << (i + 1);
let unpacked = unpack(deviceData, p, revision);
let filtered = [];
for (let up of unpacked) {
let v = deviceData.values.value.get(up, revision);
if (v && sanitizeParameterValue([path[i][j + 1], v[1]])[0] == v[0]) {
for (let m = 0; m < allMatches.length; ++ m) {
let k;
for (k = i; k >= 0; -- k)
if (allMatches[m][k] != up[k])
break
if (k < 0) {
filtered.push(allMatches[m]);
allMatches[m] = [];
}
}
}
}
allMatches = filtered;
}
}
}
return allMatches;
} }
@@ -176,7 +245,7 @@ function set(deviceData, path, timestamps, values) {
// TODO Allow overwriting attribute value with same timestamp // TODO Allow overwriting attribute value with same timestamp
path = deviceData.paths.add(path); path = deviceData.paths.add(path);
if (!path.wildcards) { if (!path.wildcard) {
normalizeAttributes(timestamps, values); normalizeAttributes(timestamps, values);
if (values.exist && path.length > 1) if (values.exist && path.length > 1)
set(deviceData, path.slice(0, path.length - 1), set(deviceData, path.slice(0, path.length - 1),
@@ -187,7 +256,7 @@ function set(deviceData, path, timestamps, values) {
var current = inferTimestamps(deviceData, path); var current = inferTimestamps(deviceData, path);
for (let c in current) for (let c in current)
if (current[c] > timestamps[c] || (current[c] == timestamps[c] && path.wildcards > 0))//!deviceData.values[c].has(path))) if (current[c] > timestamps[c] || (current[c] == timestamps[c] && path.wildcard > 0))
delete timestamps[c]; delete timestamps[c];
if (timestamps.exist != null) { if (timestamps.exist != null) {
@@ -199,19 +268,19 @@ function set(deviceData, path, timestamps, values) {
current = inferTimestamps(deviceData, path); current = inferTimestamps(deviceData, path);
for (let c in current) for (let c in current)
if (current[c] > timestamps[c] || (current[c] == timestamps[c] && path.wildcards > 0))//!deviceData.values[c].has(path))) if (current[c] > timestamps[c] || (current[c] == timestamps[c] && path.wildcard > 0))
delete timestamps[c]; delete timestamps[c];
let toInvalidate = new Map(); let toInvalidate = new Map();
for (let sub of deviceData.paths.subset(path, 0)) { for (let sub of deviceData.paths.subset(path, 0)) {
if (path.wildcards == sub.wildcards) if (path.wildcard == sub.wildcard)
continue; continue;
for (let attrName in timestamps) { for (let attrName in timestamps) {
if (deviceData.timestamps[attrName].get(sub) <= timestamps[attrName]) { if (deviceData.timestamps[attrName].get(sub) <= timestamps[attrName]) {
if (sub.wildcards || !deviceData.values[attrName].has(sub)) if (sub.wildcard || !deviceData.values[attrName].has(sub))
deviceData.timestamps[attrName].delete(sub); deviceData.timestamps[attrName].delete(sub);
else if (deviceData.timestamps[attrName].get(sub) < timestamps[attrName]) { else if (deviceData.timestamps[attrName].get(sub) < timestamps[attrName]) {
deviceData.timestamps[attrName].delete(sub); deviceData.timestamps[attrName].delete(sub);
@@ -263,7 +332,7 @@ function set(deviceData, path, timestamps, values) {
// depth = 99; // depth = 99;
// //
// for (let sup of deviceData.paths.superset(path, depth)) { // for (let sup of deviceData.paths.superset(path, depth)) {
// if ((sup.wildcards && (3 << path.length) - 1) != path.wildcards) { // if ((sup.wildcard && (3 << path.length) - 1) != path.wildcard) {
// throw new Error('Not implemented'); // throw new Error('Not implemented');
// } // }
// } // }
+5 -4
View File
@@ -79,18 +79,19 @@ class PathSet {
} }
} }
var wildcards = 0; var wildcard = 0;
this.lengthIndex[path.length].add(path); this.lengthIndex[path.length].add(path);
for (let i = 0; i < path.length; ++ i) { for (let i = 0; i < path.length; ++ i) {
let fragment = path[i]; let fragment = path[i];
if (fragment === '*') if (fragment === '*')
wildcards |= 1 << i; wildcard |= 1 << i;
this.fragmentIndex[i][fragment].add(path); this.fragmentIndex[i][fragment].add(path);
} }
if (path.wildcards == null) { if (path.wildcard == null) {
path.wildcards = wildcards; path.alias = 0;
path.wildcard = wildcard;
Object.freeze(path); Object.freeze(path);
} }
return path; return path;
+15 -14
View File
@@ -83,23 +83,24 @@ sandbox.context.declare = (decs) ->
res = {} res = {}
for k, v of decs for k, v of decs
path = common.parsePath(k) path = common.parsePath(k)
single = true
for p in path
if p == '*' or common.typeOf(p) isnt common.STRING_TYPE
single = false
break
res[k] = {}
unpacked = device.unpack(sandbox.deviceData, path, sandbox.revision) unpacked = device.unpack(sandbox.deviceData, path, sandbox.revision)
for path in unpacked for param in unpacked
iter = sandbox.deviceData.paths.subset(path) r = {}
while (param = iter.next().value)? for attrName, dec of v
if param.wildcards == 0 and sandbox.deviceData.values.exist.get(param, sandbox.revision) if (attrValue = sandbox.deviceData.values[attrName].get(param, sandbox.revision))?
r = {} r[attrName] = [sandbox.deviceData.timestamps[attrName].get(param, sandbox.revision), attrValue]
for attrName, dec of v
if (attrValue = sandbox.deviceData.values[attrName].get(param, sandbox.revision))?
r[attrName] = [sandbox.deviceData.timestamps[attrName].get(param, sandbox.revision), attrValue]
p = param.join('.') if single
if p == k res[k] = r
res[k] = r else
else res[k] ?= {}
res[k][p] = r res[k][param.join('.')] = r
return res return res
+550 -499
View File
File diff suppressed because it is too large. Load diff