diff --git a/lib/common/expression-parser.ts b/lib/common/expression-parser.ts index 07833f1..ead985e 100644 --- a/lib/common/expression-parser.ts +++ b/lib/common/expression-parser.ts @@ -215,9 +215,7 @@ const lang = parsimmon.createLanguage({ .regexp(/([a-zA-Z0-9_]+)/, 1) .skip(parsimmon.optWhitespace) .desc("function"), - r.Expression.sepBy( - parsimmon.string(",").skip(parsimmon.optWhitespace) - ).wrap( + r.ExpressionList.wrap( parsimmon.string("(").skip(parsimmon.optWhitespace), parsimmon.string(")").skip(parsimmon.optWhitespace) ), @@ -330,6 +328,11 @@ const lang = parsimmon.createLanguage({ ) ); }, + ExpressionList: function (r) { + return r.Expression.sepBy( + parsimmon.string(",").skip(parsimmon.optWhitespace) + ); + }, Expression: function (r) { function unary(operatorsParser, nextParser): parsimmon.Parser { return parsimmon.seq(operatorsParser, nextParser).or(nextParser); @@ -350,6 +353,11 @@ export function parse(str: string): Expression { return lang.Expression.tryParse(str); } +export function parseList(str: string): Expression[] { + if (!str) return []; + return lang.ExpressionList.tryParse(str); +} + export function stringify(exp: Expression, level = 0): string { if (!Array.isArray(exp)) return JSON.stringify(exp); diff --git a/lib/common/expression.ts b/lib/common/expression.ts index 7b84bf8..593c1d6 100644 --- a/lib/common/expression.ts +++ b/lib/common/expression.ts @@ -112,17 +112,25 @@ export function evaluateCallback(exp: Expression): Expression { if (exp[i]) return exp[i + 1]; } return null; - } else if (exp[0] === "FUNC" && exp[1] === "COALESCE") { - const args: Expression[] = []; - for (let i = 2; i < exp.length; ++i) { - const e = exp[i]; - if (e == null) continue; - args.push(e); - if (!Array.isArray(e)) break; + } else if (exp[0] === "FUNC") { + if (exp[1] === "COALESCE") { + const args: Expression[] = []; + for (let i = 2; i < exp.length; ++i) { + const e = exp[i]; + if (e == null) continue; + args.push(e); + if (!Array.isArray(e)) break; + } + if (!args.length) return null; + if (args.length === 1) return args[0]; + return ["FUNC", "COALESCE", ...args]; + } else if (exp[1] === "UPPER") { + if (exp[2] == null) return null; + if (!isArray(exp[2])) return toString(exp[2]).toUpperCase(); + } else if (exp[1] === "LOWER") { + if (exp[2] == null) return null; + if (!isArray(exp[2])) return toString(exp[2]).toLowerCase(); } - if (!args.length) return null; - if (args.length === 1) return args[0]; - return ["FUNC", "COALESCE", ...args]; } else if (exp[0] === "AND") { for (let i = 1; i < exp.length; ++i) if (!Array.isArray(exp[i]) && exp[i] != null && !exp[i]) return false; @@ -274,16 +282,8 @@ export function evaluate( if (cb) e = cb(e); if (!isArray(e)) return e; - if (e[0] === "FUNC") { - if (e[1] === "NOW") { - if (now) return now; - } else if (e[1] === "UPPER") { - if (e[2] == null) return null; - if (!isArray(e[2])) return `${e[2]}`.toUpperCase(); - } else if (e[1] === "LOWER") { - if (e[2] == null) return null; - if (!isArray(e[2])) return `${e[2]}`.toLowerCase(); - } + if (e[0] === "FUNC" && e[1] === "NOW") { + if (now) return now; } else if (e[0] === "PARAM") { if (e[1] == null) return null; if (obj && !isArray(e[1])) { diff --git a/lib/cwmp.ts b/lib/cwmp.ts index 0cb189a..a17dbdb 100644 --- a/lib/cwmp.ts +++ b/lib/cwmp.ts @@ -45,6 +45,7 @@ import { SoapMessage, InformRequest, AcsResponse, + Preset, } from "./types"; import { IncomingMessage, ServerResponse } from "http"; import { Readable } from "stream"; @@ -431,7 +432,7 @@ async function applyPresets(sessionContext: SessionContext): Promise { } const parameters: { [name: string]: Path } = {}; - const filteredPresets = []; + const filteredPresets: Preset[] = []; for (const preset of presets) { if (whiteList != null) { @@ -460,11 +461,24 @@ async function applyPresets(sessionContext: SessionContext): Promise { } filteredPresets.push(preset); - for (const k of extractParams(preset.precondition)) { + for (const k of extractParams( + evaluate(preset.precondition, null, sessionContext.timestamp) + )) { // Mark channel in case of fault during fetching precondition sessionContext.channels[preset.channel] = 0; if (typeof k === "string") parameters[k] = Path.parse(k); } + for (const prov of preset.provisions) { + for (const arg of prov.slice(1)) { + for (const k of extractParams( + evaluate(arg, null, sessionContext.timestamp) + )) { + // Mark channel in case of fault during fetching precondition + sessionContext.channels[preset.channel] = 0; + if (typeof k === "string") parameters[k] = Path.parse(k); + } + } + } } const declarations = Object.values(parameters).map((v) => ({ @@ -501,12 +515,22 @@ async function applyPresets(sessionContext: SessionContext): Promise { session.configContextCallback(sessionContext, e) ) ) { + const provs = p.provisions.map((pp) => [ + pp[0], + ...pp + .slice(1) + .map((arg) => + evaluate(arg, {}, sessionContext.timestamp, (e) => + session.configContextCallback(sessionContext, e) + ) + ), + ]); if (blackList[p.channel] === 2) { appendProvisionsToFaults[p.channel] = ( appendProvisionsToFaults[p.channel] || [] - ).concat(p.provisions); + ).concat(provs); } else { - session.addProvisions(sessionContext, p.channel, p.provisions); + session.addProvisions(sessionContext, p.channel, provs); } } } diff --git a/lib/mongodb-functions.ts b/lib/mongodb-functions.ts index c36e92e..c98dff1 100644 --- a/lib/mongodb-functions.ts +++ b/lib/mongodb-functions.ts @@ -18,7 +18,7 @@ */ import { ObjectID } from "mongodb"; -import { map, parse, stringify } from "./common/expression-parser"; +import { map, parse, stringify, parseList } from "./common/expression-parser"; import { likePatternToRegExp, evaluate } from "./common/expression"; import { Expression, Fault, Task } from "./types"; @@ -593,7 +593,7 @@ export function flattenPreset( ) { p.provision = provision.name; p.provisionArgs = provision.args - ? JSON.stringify(provision.args).slice(1, -1) + ? provision.args.map((a) => stringify(a)).join(", ") : ""; } @@ -650,7 +650,7 @@ export function preProcessPreset( }; if (preset.provisionArgs) - configuration.args = JSON.parse(`[${preset.provisionArgs}]`); + configuration.args = parseList(preset.provisionArgs as string); delete preset.provision; delete preset.provisionArgs; diff --git a/lib/types.ts b/lib/types.ts index 4dd4a11..659444f 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -323,7 +323,7 @@ export interface Preset { schedule?: { md5: string; duration: number; schedule: any }; events?: { [event: string]: boolean }; precondition?: Expression; - provisions: string[][]; + provisions: [string, ...Expression[]][]; } export interface Provisions { diff --git a/ui/presets-page.ts b/ui/presets-page.ts index ad300fb..52c7cd9 100644 --- a/ui/presets-page.ts +++ b/ui/presets-page.ts @@ -43,7 +43,7 @@ const attributes = [ { id: "events", label: "Events" }, { id: "precondition", label: "Precondition", type: "textarea" }, { id: "provision", label: "Provision", type: "combo" }, - { id: "provisionArgs", label: "Arguments" }, + { id: "provisionArgs", label: "Arguments", type: "textarea" }, ]; const unpackSmartQuery = memoize((query) => {