ABI / Host imports
ABI стабилен начиная с abi_version: 1 (поле в манифесте). При изменении контракта в обратно-несовместимую сторону хост поднимет CurrentABIVersion, и плагины со старой версией будут видны в админке как “incompatible”.
Память и упаковка указателей
Плагины и хост обмениваются JSON-байтами через linear memory гостя. Хост никогда не аллоцирует у себя — он зовёт экспорт гостя alloc(size) i32 и пишет туда. Указатель и длина возвращаются из функций упакованными в один i64:
high32(result) = ptr (offset в guest memory)
low32(result) = len (количество байт)Хелперы:
// В Go-хосте:
func PackPtrLen(ptr, length uint32) uint64 { return (uint64(ptr) << 32) | uint64(length) }
func UnpackPtrLen(v uint64) (ptr, length uint32) { return uint32(v >> 32), uint32(v & 0xFFFFFFFF) }// В JS-loader для client-target:
function packPtrLen(ptr, len) { return (BigInt(ptr) << 32n) | BigInt(len); }Обязательные экспорты гостя
| Экспорт | Сигнатура | Когда вызывается |
|---|---|---|
alloc |
(size i32) -> i32 |
Хост резервирует буфер для входных данных и для возврата из host-импортов |
handle |
(ptr i32, len i32) -> i64 |
Главный entry point. Вход — JSON Invocation, выход — pack(ptr,len) JSON Response |
Опциональные экспорты:
| Экспорт | Что |
|---|---|
abi_version |
() -> i32 — гость может отдать свою ABI; хост сверяет с manifest |
_initialize |
TinyGo / Rust — reactor-mode инициализация |
on_load / on_event |
Только для client-target; см. client |
Хост-импорты (модуль lampac для server-target)
host_log(level i32, ptr i32, len i32)
level: 0=debug 1=info 2=warn 3=errorПишет строку в logsink модуля (виден в админке) и в общий zerolog. Stdout/stderr плагина тоже перенаправлены сюда — fmt.Println работает.
host_http(req_ptr i32, req_len i32) -> i64
Синхронный HTTP-запрос. Гейтится permissions — см. permissions.
Вход (JSON):
{
"method": "GET",
"url": "https://api.example.com/v1/movies",
"headers": {"User-Agent": "lampac"},
"body": "raw string body",
"body_b64": "base64 alt",
"timeout_ms": 15000,
"transport": "default"
}Выход (JSON):
{
"status": 200,
"headers": {"content-type": "application/json"},
"body_b64": "...base64...",
"error": ""
}Возврат — pack(ptr,len) JSON-ответа в guest memory. Cap на тело — 16 МиБ.
host_proxy_url(req_ptr i32, req_len i32) -> i64
Подписывает потоковый URL через proxylink.Manager, чтобы Lampa-клиент ходил к нему через /proxy/ (с правильными headers, cookies, Origin).
Вход:
{
"uri": "https://cdn.example.com/movie.m3u8",
"plugin": "my_plugin", // опционально, по умолчанию = manifest.id
"headers": {"Origin": "https://example.com"}
}Выход:
{ "url": "https://lampac-host/proxy/<aes-blob>" }host_cache_get(key_ptr, key_len) -> i64
Возвращает pack(ptr,len) сырых байт, которые гость записал через host_cache_set. На промахе возвращает 0. Хост не интерпретирует значение — гость сериализует/десериализует сам.
host_cache_set(key_ptr, key_len, val_ptr, val_len, ttl_sec)
TTL по умолчанию (если 0) — 300 сек. Кеш per-module, чистится при reload.
host_config() -> i64
Возвращает текущий снимок конфига модуля как JSON: manifest.config_schema.default + manifest.defaults + admin-overrides из wasm_modules/{id}/config.json. То же значение приходит как Invocation.config.
Хост-импорты (модуль lampac_client для client-target)
Используется в Lampa через wasm_loader.js.
| Импорт | Что делает |
|---|---|
host_log(level, ptr, len) |
console.{debug,info,warn,error} с префиксом [<id>] |
host_storage_get(key_ptr, key_len) -> i64 |
Lampa.Storage.get('wasm_plugin_<id>:'+key) |
host_storage_set(key_ptr, key_len, val_ptr, val_len) |
Lampa.Storage.set(...) |
host_listener_emit(event_ptr, event_len, data_ptr, data_len) |
Lampa.Listener.send(event, JSON.parse(data)) |
host_noty(msg_ptr, msg_len) |
Lampa.Noty.show(msg) |
host_activity_push(json_ptr, json_len) |
Lampa.Activity.push(JSON.parse(...)) |
Каждому плагину выдаётся свой namespace в Lampa.Storage (wasm_plugin_<id>:*), чтобы плагины не топтали ключи друг друга.
Invocation / Response
Серверные плагины получают на вход:
{
"query": {"id": "123", "s": "1"},
"headers": {"user-agent": "..."},
"host": "https://example.com",
"requestIP": "1.2.3.4",
"path": "my_plugin",
"life": false,
"checksearch": false,
"userAgent": "...",
"config": { /* host_config() snapshot */ }
}Возвращают любую JSON-структуру, которую Lampa поймёт. Типичный формат для списков:
{
"type": "movie",
"data": [
{"name": "Title", "url": "/proxy/...", "quality": {"1080p": "...m3u8"}}
],
"voice": [{"name": "Дубляж", "url": "?id=123&voice=1", "active": true}]
}Для прямого воспроизведения:
{ "method": "play", "url": "/proxy/...", "title": "...", "quality": "1080p" }Middleware ABI
Когда target: middleware, хост до вызова handle() дёргает каждого upstream’а и складывает их ответы в inv.Config.__upstreams:
{
"__upstreams": [
{"balancer": "collaps", "status": 200, "body": {...}},
{"balancer": "filmix", "status": 503, "error": "timeout"}
]
}В TinyGo SDK для этого есть lampac.Upstreams(inv) []UpstreamResult. См. middleware.
ABI-version bumps
abi_version |
Что меняется |
|---|---|
1 (текущая) |
Базовый набор — host_log, host_http, host_proxy_url, host_cache_*, host_config для server; host_storage_* + host_noty + host_activity_push + host_listener_emit для client |
Когда поднимется до 2, плагины с abi_version: 1 продолжат работать через shim — старые импорты остаются.