Движок правил wb-rules 1.7/en: различия между версиями

Материал из Wiren Board
(Новая страница: «Before: <pre> 2019-01-05 17:29:50myFuncTwo called 2019-01-05 17:29:50test1: 84, test2: Hello 2019-01-05 17:29:50myFuncOne called 2019-01-05 17:29:50test1: 84 2019…»)
(Новая страница: «Now: <pre> 2019-01-05 17:28:42myFuncTwo called 2019-01-05 17:28:42test1: 84, test2: Hello 2019-01-05 17:28:42myFuncOne called 2019-01-05 17:28:42test1: 42 2019-01…»)
Строка 56: Строка 56:




Стало:
Now:
<pre>
<pre>
2019-01-05 17:28:42myFuncTwo called
2019-01-05 17:28:42myFuncTwo called

Версия 18:11, 6 июня 2019

Другие языки:

The updated wb-rules engine contains a number of important innovations regarding the logic of scripting.

Scripts

Isolation of scripts

Starting with wb-rules v.1.7, local variables and functions declared in the script file are not visible in other scripts. Thus, each script can define its own functions and variables without the risk of changing the behavior of other scripts.


Example

As an example, here are two scenarios that run simultaneously in the rules engine. Each scenario defines variables and functions.

In previous versions of wb-rules, refering to a global variable, that is modified in several script files, may cause undefined behavior. Starting from v.1.7, the behavior is strictly defined and is the same as if the script is the only one in the system.

The comments indicate the output of the log commands for earlier versions and for the current version. Note the 'var' before the variables.

rules1.js

var test1 = 42;

setInterval(function myFuncOne() {
    log("myFuncOne called");
    log("test1: {}", test1);
    log("test2: {}", test2);
}, 5000);

rules2.js

test1 = 84;
test2 = "Hello";

setInterval(function myFuncTwo() {
    log("myFuncTwo called");
    log("test1: {}, test2: {}", test1, test2);
}, 5000);


Before:

2019-01-05 17:29:50myFuncTwo called
2019-01-05 17:29:50test1: 84, test2: Hello
2019-01-05 17:29:50myFuncOne called
2019-01-05 17:29:50test1: 84
2019-01-05 17:29:50test2: Hello


Now:

2019-01-05 17:28:42myFuncTwo called
2019-01-05 17:28:42test1: 84, test2: Hello
2019-01-05 17:28:42myFuncOne called
2019-01-05 17:28:42test1: 42
2019-01-05 17:28:42ECMAScript error: ReferenceError: identifier 'test2' undefined
duk_js_var.c:1232
myFuncOne /etc/wb-rules/rules1.js:6 preventsyield



Примечание

В предыдущих версиях wb-rules для изоляции правил рекомендовалось использовать замыкание, т.е. оборачивание кода сценария в конструкцию:

(function() {
    // код сценария идёт здесь
})();

Начиная с версии 1.7, в подобной конструкции обычно нет необходимости. Тем не менее, старые сценарии, использующие эту конструкцию, продолжат работу без изменений в поведении.


Обходные пути

Если в вашей системе использовалось общее глобальное пространство для хранения общих данных и функций, есть несколько способов реализации такого поведения:


Постоянное хранилище

Для обмена данными также можно использовать глобальные постоянные хранилища (PersistentStorage).

Внимание: при использовании глобальных постоянных хранилищ может произойти совпадение имён, в этом случае возможно труднообнаруживаемое нарушение поведения.

var ps = new PersistentStorage("my-global-storage", {global: true});

/// ...

ps.myvar = "value"; // это значение доступно для всех пользователей хранилища с именем "my-global-storage"


Прототип глобального объекта

ВНИМАНИЕ: метод считается "грязным", т.к. все переменные и функции, опубликованные таким образом, становятся доступными всем сценариям в системе. Старайтесь избегать этого способа. За неопределённое поведение при использовании этого метода несёт ответственность сам программист.

Глобальные объекты всех сценариев имеют общий объект-прототип, в котором определены стандартные функции wb-rules (такие, как defineRule, setTimeout и т.д.). Через него можно передавать переменные или функции в общую область видимости.

global.__proto__.myVar = 42; // теперь myVar - общая переменная для всех сценариев

// из других сценариев к переменной можно обращаться так
log("shared myVar: {}", myVar);

// или вот так, что чуть более аккуратно, т.к. однозначно показывает, где определена переменная
log("shared myVar: {}", global.__proto__.myVar);

Правило поиска переменной в первом случае будет выглядеть так:

  1. Проверяем, есть ли myVar среди локальных переменных (определённой как var myVar = ...).
  2. Если нет, проверяем, есть ли myVar в глобальном объекте (определённой как myVar = ...).
  3. Если нет, проверяем, есть ли myVar в прототипе глобального объекта (определённой как global.__proto__.myVar).

Поиск останавливается, как только переменная найдена.

Таким образом, первый способ обращения будет работать только в том случае, если myVar не определена в верхних областях видимости.


Постоянное хранилище данных

В wb-rules 1.7 добавлена поддержка постоянных хранилищ. По сути, это объекты, значения в которых будут сохраняться даже при потере питания контроллера. Такие хранилища удобно использовать для хранения состояний или конфигурации.

var ps = new PersistentStorage("my-storage", { global: true });

ps.key = "Hello World";
log(ps.key);

Поддерживаются только глобальные хранилища, т.е. видимые по одному и тому же имени из всех файлов сценариев.


Виртуальные устройства

В предыдущих версиях wb-rules значения контролов виртуальных устройств хранились только в MQTT retained, что не очень надёжно (в случае потери питания данные могли быть легко утеряны). Начиная с версии 2.0, эти значения сохраняются также в специальное хранилище в постоянной памяти и восстанавливаются при загрузке сценария.

Если необходимо каждый раз при перезагрузке скрипта восстанавливать строго определённое значение (т.е. не восстанавливать предыдущее сохранённое), можно добавить в описание контрола поле forceDefault:

defineVirtualDevice("vdev", {
    ...
    cells: {
        ...
        mycell: {
            type: "value",
            value: "10",
            forceDefault: true // при каждой загрузке сценария поле mycell будет получать значение 10
        }
    }
});