Implement support for Get/SetParameterAttributes

This commit is contained in:
Zaid Abdulla committed 2020-08-17 19:21:13 -07:00
1 parent 6385f54888
commit bf9517c652
10 files changed
+524 -56

No files matched your search

+185 -16
View File
@@ -770,8 +770,11 @@ function runDeclarations(
object: new Set(),
writable: new Set(),
value: new Set(),
notification: new Set(),
accessList: new Set(),
},
spv: new Map(),
spa: new Map(),
gpn: new Set<Path>(),
gpnPatterns: new Map(),
tags: new Map(),
@@ -1508,6 +1511,8 @@ function generateGetRpcRequest(sessionContext: SessionContext): GetAcsRequest {
syncState.refreshAttributes.value.has(p) ||
syncState.refreshAttributes.object.has(p) ||
syncState.refreshAttributes.writable.has(p) ||
syncState.refreshAttributes.notification.has(p) ||
syncState.refreshAttributes.accessList.has(p) ||
syncState.gpn.has(p)
) {
found = true;
@@ -1536,7 +1541,9 @@ function generateGetRpcRequest(sessionContext: SessionContext): GetAcsRequest {
syncState.refreshAttributes.value.has(p) ||
(p.length > path.length &&
(syncState.refreshAttributes.object.has(p) ||
syncState.refreshAttributes.writable.has(p)))
syncState.refreshAttributes.writable.has(p) ||
syncState.refreshAttributes.notification.has(p) ||
syncState.refreshAttributes.accessList.has(p)))
) {
found = true;
break;
@@ -1648,9 +1655,59 @@ function generateGetRpcRequest(sessionContext: SessionContext): GetAcsRequest {
};
}
}
if (
syncState.refreshAttributes.notification.size ||
syncState.refreshAttributes.accessList.size
) {
const GPV_BATCH_SIZE = localCache.getConfig(
sessionContext.cacheSnapshot,
"cwmp.gpvBatchSize",
{},
sessionContext.timestamp,
(e) => configContextCallback(sessionContext, e)
);
const parameterNames: string[] = [];
for (const path of syncState.refreshAttributes.notification) {
syncState.refreshAttributes.notification.delete(path);
syncState.refreshAttributes.accessList.delete(path);
// Need to check in case param is deleted
const attrs = sessionContext.deviceData.attributes.get(path);
if (attrs) {
parameterNames.push(path.toString());
if (parameterNames.length >= GPV_BATCH_SIZE) break;
}
}
if (parameterNames.length < GPV_BATCH_SIZE) {
for (const path of syncState.refreshAttributes.accessList) {
syncState.refreshAttributes.accessList.delete(path);
const attrs = sessionContext.deviceData.attributes.get(path);
if (attrs) {
parameterNames.push(path.toString());
if (parameterNames.length >= GPV_BATCH_SIZE) break;
}
}
}
if (parameterNames.length) {
return {
name: "GetParameterAttributes",
parameterNames: parameterNames,
};
}
}
return null;
}
function compareAccessLists(list1: string[], list2: string[]): boolean {
if (list1.length !== list2.length) return false;
for (const [i, v] of list1.entries()) if (v !== list2[i]) return false;
return true;
}
function generateSetRpcRequest(sessionContext: SessionContext): SetAcsRequest {
const syncState = sessionContext.syncState;
if (!syncState) return null;
@@ -1709,7 +1766,7 @@ function generateSetRpcRequest(sessionContext: SessionContext): SetAcsRequest {
(e) => configContextCallback(sessionContext, e)
);
const parameterValues: [Path, string | number | boolean, string][] = [];
const parameterValues: [string, string | number | boolean, string][] = [];
for (const [k, v] of syncState.spv) {
syncState.spv.delete(k);
const attrs = sessionContext.deviceData.attributes.get(k);
@@ -1728,7 +1785,7 @@ function generateSetRpcRequest(sessionContext: SessionContext): SetAcsRequest {
val[0] -= val[0] % 1000;
if (val[0] !== curVal[0] || val[1] !== curVal[1])
parameterValues.push([k, val[0], val[1]]);
parameterValues.push([k.toString(), val[0], val[1]]);
if (parameterValues.length >= GPV_BATCH_SIZE) break;
}
@@ -1737,19 +1794,44 @@ function generateSetRpcRequest(sessionContext: SessionContext): SetAcsRequest {
if (parameterValues.length) {
return {
name: "SetParameterValues",
parameterList: parameterValues.map(
(p) =>
[p[0].toString(), p[1], p[2]] as [
string,
string | number | boolean,
string
]
),
parameterList: parameterValues,
DATETIME_MILLISECONDS: DATETIME_MILLISECONDS,
BOOLEAN_LITERAL: BOOLEAN_LITERAL,
};
}
// Set attributes
const parameterAttributes: [string, number, string[]][] = [];
for (const [k, v] of syncState.spa) {
syncState.spa.delete(k);
const attrs = sessionContext.deviceData.attributes.get(k);
if (
v.notification != null &&
(!attrs.notification || v.notification === attrs.notification[1])
)
v.notification = null;
if (
v.accessList != null &&
(!attrs.accessList ||
compareAccessLists(v.accessList, attrs.accessList[1]))
)
v.accessList = null;
if (v.notification != null || v.accessList != null)
parameterAttributes.push([k.toString(), v.notification, v.accessList]);
if (parameterAttributes.length >= GPV_BATCH_SIZE) break;
}
if (parameterAttributes.length) {
return {
name: "SetParameterAttributes",
parameterList: parameterAttributes,
};
}
// Downloads
for (const [p, t] of syncState.downloadsDownload) {
const attrs = deviceData.attributes.get(p);
@@ -2167,8 +2249,34 @@ function processDeclarations(
}
}
}
if (declareAttributeValues && declareAttributeValues.value != null)
syncState.spv.set(currentPath, declareAttributeValues.value);
if (declareAttributeValues) {
if (declareAttributeValues.value != null)
syncState.spv.set(currentPath, declareAttributeValues.value);
if (declareAttributeValues.notification != null) {
const spa = syncState.spa.get(currentPath);
if (spa) {
spa.notification = declareAttributeValues.notification;
} else {
syncState.spa.set(currentPath, {
notification: declareAttributeValues.notification,
accessList: null,
});
}
}
if (declareAttributeValues.accessList != null) {
const spa = syncState.spa.get(currentPath);
if (spa) {
spa.accessList = declareAttributeValues.accessList;
} else {
syncState.spa.set(currentPath, {
notification: null,
accessList: declareAttributeValues.accessList,
});
}
}
}
}
}
@@ -2305,7 +2413,7 @@ export async function rpcResponse(
if (p[1] !== req.instanceValues[p[0]]) {
const v = device.sanitizeParameterValue([
req.instanceValues[p[0]],
p[2],
p[2] as string,
]);
parameterList.push([p[0], v[0], v[1]]);
}
@@ -2371,6 +2479,24 @@ export async function rpcResponse(
toClear
);
}
} else if (rpcRes.name === "GetParameterAttributesResponse") {
const req = rpcReq as GetAcsRequest;
const res = rpcRes as CpeGetResponse;
if (req.name !== "GetParameterAttributes")
throw new Error("Response name does not match request name");
for (const p of res.parameterList) {
toClear = device.set(
sessionContext.deviceData,
Path.parse(p[0]),
timestamp,
{
notification: [timestamp, p[1] as number],
accessList: [timestamp, p[2] as string[]],
},
toClear
);
}
} else if (rpcRes.name === "GetParameterNamesResponse") {
const req = rpcReq as GetAcsRequest;
const res = rpcRes as CpeGetResponse;
@@ -2485,6 +2611,37 @@ export async function rpcResponse(
toClear
);
}
} else if (rpcRes.name === "SetParameterAttributesResponse") {
const req = rpcReq as SetAcsRequest;
if (req.name !== "SetParameterAttributes")
throw new Error("Response name does not match request name");
for (const p of req.parameterList) {
let attrs;
if (p[1] != null && p[2] != null) {
attrs = {
notification: [timestamp + 1, p[1]],
accessList: [timestamp + 1, p[2]],
};
} else if (p[1] != null) {
attrs = {
notification: [timestamp + 1, p[1]],
};
} else if (p[2] != null) {
attrs = {
accessList: [timestamp + 1, p[2]],
};
}
toClear = device.set(
sessionContext.deviceData,
Path.parse(p[0]),
timestamp + 1,
attrs,
toClear
);
}
} else if (rpcRes.name === "AddObjectResponse") {
const req = rpcReq as SetAcsRequest;
const res = rpcRes as CpeSetResponse;
@@ -2628,7 +2785,7 @@ export async function rpcFault(
// Recover from invalid parameter name faults
if (faultResponse.detail.faultCode === "9005") {
const timestamp = sessionContext.timestamp + sessionContext.iteration;
const timestamp = sessionContext.timestamp + sessionContext.iteration + 1;
const revision =
(sessionContext.revisions[sessionContext.revisions.length - 1] || 0) + 1;
sessionContext.deviceData.timestamps.revision = revision;
@@ -2646,13 +2803,25 @@ export async function rpcFault(
(p) => [Path.parse(p.replace(/\.$/, "")), timestamp] as Clear
);
} else if (rpcReq.name === "SetParameterValues") {
toClear = rpcReq.parameterList.map(
toClear = (rpcReq.parameterList as [
string,
string | number | boolean,
string
][]).map(
(p) => [Path.parse(p[0].replace(/\.$/, "")), timestamp] as Clear
);
} else if (rpcReq.name === "AddObject") {
toClear = [[Path.parse(rpcReq.objectName.replace(/\.$/, "")), timestamp]];
} else if (rpcReq.name === "DeleteObject") {
toClear = [[Path.parse(rpcReq.objectName.replace(/\.$/, "")), timestamp]];
} else if (rpcReq.name === "GetParameterAttributes") {
toClear = rpcReq.parameterNames.map(
(p) => [Path.parse(p.replace(/\.$/, "")), timestamp] as Clear
);
} else if (rpcReq.name === "SetParameterAttributes") {
toClear = (rpcReq.parameterList as [string, number, string[]][]).map(
(p) => [Path.parse(p[0].replace(/\.$/, "")), timestamp] as Clear
);
}
if (toClear) {