Динамическое выполнение кода
Динамическое выполнение кода
Заголовок раздела «Динамическое выполнение кода»Выполнение кода во время работы приложения в изолированном окружении с контролем доступа к модулям.
Два подхода
Заголовок раздела «Два подхода»Wippy предоставляет две системы выполнения:
| Система | Назначение | Применение |
|---|---|---|
expr | Вычисление выражений | Конфиги, шаблоны, простые вычисления |
eval_runner | Полноценное выполнение Lua | Плагины, пользовательские скрипты |
Модуль expr
Заголовок раздела «Модуль expr»Вычисление простых выражений на синтаксисе expr-lang:
local expr = require("expr")
local result, err = expr.eval("x + y * 2", {x = 10, y = 5})-- result = 20Компиляция выражений
Заголовок раздела «Компиляция выражений»Скомпилировав выражение один раз, можно выполнять его многократно:
local program, err = expr.compile("price * quantity")
local total1 = program:run({price = 10, quantity = 5})local total2 = program:run({price = 20, quantity = 3})Поддерживаемый синтаксис
Заголовок раздела «Поддерживаемый синтаксис»-- Арифметикаexpr.eval("1 + 2 * 3") -- 7expr.eval("10 / 2 - 1") -- 4expr.eval("10 % 3") -- 1
-- Сравнениеexpr.eval("x > 5", {x = 10}) -- trueexpr.eval("x == y", {x = 1, y = 1}) -- true
-- Логические операцииexpr.eval("a && b", {a = true, b = false}) -- falseexpr.eval("a || b", {a = true, b = false}) -- trueexpr.eval("!a", {a = false}) -- true
-- Тернарный операторexpr.eval("x > 0 ? 'positive' : 'negative'", {x = 5})
-- Функцииexpr.eval("max(1, 5, 3)") -- 5expr.eval("min(1, 5, 3)") -- 1expr.eval("len([1, 2, 3])") -- 3
-- Массивыexpr.eval("[1, 2, 3][0]") -- 1
-- Конкатенация строкexpr.eval("'hello' + ' ' + 'world'")Модуль eval_runner
Заголовок раздела «Модуль eval_runner»Полноценное выполнение Lua с контролем безопасности:
local runner = require("eval_runner")
local result, err = runner.run({ source = [[ local function double(x) return x * 2 end return double(input) ]], args = {21}})-- result = 42Параметры
Заголовок раздела «Параметры»| Параметр | Тип | Описание |
|---|---|---|
source | string | Исходный код Lua (обязательно) |
method | string | Функция для вызова из возвращаемой таблицы |
args | any[] | Аргументы для функции |
modules | string[] | Разрешённые встроенные модули |
imports | table | Записи реестра для импорта |
context | table | Значения, доступные как ctx |
allow_classes | string[] | Дополнительные классы модулей |
custom_modules | table | Пользовательские таблицы как модули |
Доступ к модулям
Заголовок раздела «Доступ к модулям»Укажите белый список разрешённых модулей:
runner.run({ source = [[ local json = require("json") return json.encode({hello = "world"}) ]], modules = {"json"}})Модули, не указанные в списке, недоступны.
Импорт из реестра
Заголовок раздела «Импорт из реестра»Импорт записей из реестра:
runner.run({ source = [[ local utils = require("utils") return utils.format(data) ]], imports = { utils = "app.lib:utilities" }, args = {{key = "value"}}})Пользовательские модули
Заголовок раздела «Пользовательские модули»Передача собственных таблиц:
runner.run({ source = [[ return sdk.version ]], custom_modules = { sdk = {version = "1.0.0", api_key = "xxx"} }})Контекст
Заголовок раздела «Контекст»Передача данных, доступных через ctx:
runner.run({ source = [[ return "Привет, " .. ctx.user ]], context = {user = "Алексей"}})Компиляция программ
Заголовок раздела «Компиляция программ»runner.compile проверяет исходный код и сообщает его точку входа и модули, не выполняя его:
local program, err = runner.compile([[ local function process(x) return x * 2 end return { process = process }]], "process", {modules = {"json"}})
program:method() -- "process" (string)program:modules() -- {"json"} (string[])Скомпилированная программа носит информационный характер; для выполнения вызовите runner.run с исходным кодом и методом.
Модель безопасности
Заголовок раздела «Модель безопасности»Классы модулей
Заголовок раздела «Классы модулей»Модули классифицированы по возможностям:
| Класс | Описание | По умолчанию |
|---|---|---|
deterministic | Чистые функции | Разрешён |
encoding | Кодирование данных | Разрешён |
time | Операции со временем | Разрешён |
nondeterministic | Случайные числа и т.п. | Разрешён |
process | Spawn, реестр | Запрещён |
storage | Файлы, БД | Запрещён |
network | HTTP, сокеты | Запрещён |
Разрешение заблокированных классов
Заголовок раздела «Разрешение заблокированных классов»runner.run({ source = [[ local http = require("http_client") return http.get("https://api.example.com") ]], modules = {"http_client"}, allow_classes = {"network"}})Проверка разрешений
Заголовок раздела «Проверка разрешений»Система проверяет права на:
eval.compile— перед компиляциейeval.run— перед выполнениемeval.module— для каждого модуля в белом спискеeval.import— для каждого импорта из реестраeval.class— для каждого разрешённого класса
Настройка в политиках безопасности.
Обработка ошибок
Заголовок раздела «Обработка ошибок»local result, err = runner.run({...})if err then if err:kind() == errors.PERMISSION_DENIED then -- Доступ запрещён политикой безопасности elseif err:kind() == errors.INVALID then -- Неверный код или настройки elseif err:kind() == errors.INTERNAL then -- Ошибка выполнения или компиляции endendПримеры использования
Заголовок раздела «Примеры использования»Система плагинов
Заголовок раздела «Система плагинов»local plugins = registry.find({meta = {type = "plugin"}})
for _, plugin in ipairs(plugins) do local source = plugin:data().source runner.run({ source = source, method = "init", modules = {"json", "time"}, context = {config = app_config} })endШаблонные выражения
Заголовок раздела «Шаблонные выражения»local template = "Hello, {{name}}! You have {{count}} messages."local compiled = expr.compile("name")
-- Быстрое многократное вычислениеfor _, user in ipairs(users) do local greeting = compiled:run({name = user.name})endПользовательские скрипты
Заголовок раздела «Пользовательские скрипты»local user_code = request:body()
local result, err = runner.run({ source = user_code, modules = {"json", "text"}, -- Только безопасные модули context = {data = input_data}})См. также
Заголовок раздела «См. также»- Выражения — справочник по языку выражений
- Exec — выполнение системных команд
- Безопасность — политики безопасности