Implement support for Get/SetParameterAttributes
This commit is contained in:
1 parent
6385f54888
commit
bf9517c652
10 files changed
+524
-56
No files matched your search
+185
-16
@@ -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) {
|
||||
|
||||
Reference in new issue
Block a user