diff --git a/lib/api-functions.ts b/lib/api-functions.ts index 9c26a0a..2a2fbaf 100644 --- a/lib/api-functions.ts +++ b/lib/api-functions.ts @@ -241,6 +241,18 @@ function sanitizeTask(task): void { ) throw new Error("Invalid 'targetFileName' property"); break; + + case "provisions": + if ( + !Array.isArray(task.provisions) || + !task.provisions.every(arr => + arr.every( + s => s == null || ["boolean", "number", "string"].includes(typeof s) + ) + ) + ) + throw new Error("Invalid 'provisions' property"); + break; } return task; diff --git a/lib/cwmp.ts b/lib/cwmp.ts index 2a20a24..b283a4f 100644 --- a/lib/cwmp.ts +++ b/lib/cwmp.ts @@ -686,6 +686,13 @@ async function nextRpc(sessionContext: SessionContext): Promise { ["instances", task.objectName, 0] ]); break; + case "provisions": + session.addProvisions( + sessionContext, + `task_${task._id}`, + task.provisions + ); + break; default: throw new Error("Task name not recognized"); } diff --git a/lib/default-provisions.ts b/lib/default-provisions.ts index 1da26dd..9f8c228 100644 --- a/lib/default-provisions.ts +++ b/lib/default-provisions.ts @@ -29,25 +29,45 @@ export function refresh(sessionContext, provision, declarations): boolean { (provision.length !== 2 || typeof provision[1] !== "string") && (provision.length !== 3 || typeof provision[1] !== "string" || - typeof provision[2] !== "number") + typeof provision[2] !== "number") && + (provision.length < 4 || + typeof provision[1] !== "string" || + typeof provision[2] !== "number" || + typeof provision[3] !== "boolean") ) throw new Error("Invalid arguments"); - const segments = Path.parse(provision[1]).segments.slice(); - const l = segments.length; - segments.length = MAX_DEPTH; - segments.fill("*", l); - const path = Path.parse(segments.join(".")); const every = 1000 * (provision[2] || 1); const offset = scheduling.variance(sessionContext.deviceId, every); const t = scheduling.interval(sessionContext.timestamp, every, offset); - for (let i = l; i < path.length; ++i) { + let attrGet; + let refreshChildren; + if (provision[3] == null) { + refreshChildren = true; + attrGet = { object: 1, writable: 1, value: t }; + } else { + attrGet = {}; + refreshChildren = !!provision[3]; + for (const a of provision.slice(4)) attrGet[a] = t; + } + + let path = Path.parse(provision[1]); + let l = path.length; + if (refreshChildren) { + const segments = path.segments.slice(); + l = segments.length; + segments.length = MAX_DEPTH; + segments.fill("*", l); + path = Path.parse(segments.join(".")); + } + + for (let i = l; i <= path.length; ++i) { declarations.push({ path: path.slice(0, i), pathGet: t, pathSet: null, - attrGet: { object: 1, writable: 1, value: t }, + attrGet: attrGet, attrSet: null, defer: true }); @@ -57,15 +77,38 @@ export function refresh(sessionContext, provision, declarations): boolean { } export function value(sessionContext, provision, declarations): boolean { - if (provision.length !== 3 || typeof provision[1] !== "string") + if ( + provision.length < 3 || + provision.length > 4 || + typeof provision[1] !== "string" + ) throw new Error("Invalid arguments"); + let attr: string, val: any; + + if (provision.length === 3) { + attr = "value"; + val = provision[2]; + } else { + attr = provision[2] || ""; + val = provision[3]; + } + + if (attr === "accessList") { + val = (val || "") + .split(",") + .map(s => s.trim()) + .filter(s => !!s); + } else if (attr === "value") { + val = [val]; + } + declarations.push({ path: Path.parse(provision[1]), pathGet: 1, pathSet: null, - attrGet: { value: 1 }, - attrSet: { value: [provision[2]] }, + attrGet: { [attr]: 1 }, + attrSet: { [attr]: val }, defer: true }); diff --git a/lib/types.ts b/lib/types.ts index f96cac6..e3ada40 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -178,6 +178,7 @@ export interface Task { fileName?: string; targetFileName?: string; expiry?: number; + provisions?: (string | number | boolean)[][]; } export interface Operation {