Sandbox & isolation#
Model izolacji#
Każdy plugin działa w osobnym sandboxie Lua z:
- Izolowanym środowiskiem (własna przestrzeń zmiennych)
- Śledzeniem zasobów (timery, eventy, MQTT, registry)
- Automatycznym czyszczeniem przy unload
- Ograniczonym dostępem do systemu
┌─────────────────────────────────────────┐
│ Plugin Manager (vCLU) │
├──────────┬──────────┬───────────────────┤
│ weather │ telegram │ sun-position │
│ timers[] │ timers[] │ timers[] │
│ events[] │ events[] │ events[] │
│ mqtt[] │ mqtt[] │ mqtt[] │
│ reg[] │ reg[] │ reg[] │
└──────────┴──────────┴───────────────────┘Dostępne API#
Każdy plugin ma dostęp do bezpiecznego podzbioru Lua i vCLU API:
Lua standard#
print, pairs, ipairs, type, tostring, tonumber, pcall, error, assert,
string.*, table.*, math.*,
os.time, os.date, os.difftime, os.clock
vCLU API#
Plugin, EventBus, JSON, Logger, HTTP, MQTT,
setTimeout, setInterval, clearInterval,
_ / _registry (odczyt dowolny, zapis tylko own namespace)
Zablokowane#
| Funkcja | Powód |
|---|---|
os.execute() | Brak dostępu do shell |
io.* | Brak dostępu do plików |
loadfile(), dofile(), load() | Brak dynamicznego ładowania kodu |
rawset(), rawget() | Brak obejścia ochrony |
debug.* | Brak debug API |
Śledzenie zasobów#
System automatycznie śledzi wszystkie zasoby tworzone przez plugin:
| Zasób | Tworzenie | Automatyczne czyszczenie |
|---|---|---|
| Timery | plugin:setTimeout(), plugin:setInterval() | Usunięcie wszystkich timerów |
| Eventy | plugin:on() | Wyrejestrowanie subskrypcji |
| MQTT | plugin:mqttSubscribe() | Wyrejestrowanie subskrypcji |
| Registry | plugin:upsertObject() | Usunięcie obiektów z namespace |
| Throttle | plugin:emit({throttle = ...}) | Wyczyszczenie stanu |
Auto-cleanup#
Przy unload pluginu (wyłączenie, odinstalowanie, zmiana konfiguracji) system automatycznie czyści wszystkie zasoby.
Plugin nie musi ręcznie czyścić timerów, eventów ani MQTT w onCleanup():
plugin:onCleanup(function()
-- Timery, eventy, MQTT — auto-czyszczone!
-- Tutaj tylko własne zasoby (np. zamknięcie połączeń)
plugin:log("info", "Plugin stopped")
end)Write protection#
Registry ma ochronę zapisu — plugin może pisać tylko do swojego namespace:
-- Format: plugins.{namespace}.{shortId}.{path}
-- OK — własny namespace:
plugin:upsertObject("sensor", {})
-- → plugins.vclu.weather.sensor ✓
-- BŁĄD — cudzy namespace:
_registry["CLU.DOUT1"] = something
-- → error: Plugin can only write to own namespace ✗
-- OK — odczyt dowolny:
local lamp = _:get("CLU.DOUT1") -- ✓Komunikacja między pluginami#
Pluginy mogą się komunikować przez:
Events (rekomendowane)#
-- Plugin A emituje
plugin:emit("weather:changed", {temp = 22.5})
-- Plugin B subskrybuje
plugin:on("weather:changed", function(data)
plugin:log("info", "Temp: " .. data.temp)
end)Public API#
-- Plugin B wywołuje metody Plugin A
local weather = Plugin.getPlugin("@vclu/weather")
if weather and weather:isReady() then
local temp = weather:getTemperature()
endRegistry (read-only)#
-- Plugin B czyta obiekt Plugin A
local data = plugin:getObject("plugins.vclu.weather.current")
if data then
plugin:log("info", "Weather data: " .. data.temp)
endLimity#
| Zasób | Limit |
|---|---|
| Timery | Bez limitu (śledzone, auto-cleanup) |
| HTTP requests | Bez limitu (timeout per-request) |
| MQTT subscriptions | Bez limitu (śledzone) |
| Registry objects | Tylko w own namespace |
| KV Store | Per-plugin, na dysku |
| Sieć | Tylko HTTP/HTTPS i MQTT |
| Filesystem | Brak dostępu |
| System | Brak os.execute |