Сессии и контексты в Metarhia
В Impress нет middleware и AsyncLocalStorage. Сессии и контексты сделаны через Proxy на data и явный инжект context в прикладной код.
Базовые идеи
- Сессия — anonymous или authenticated. Создаётся всегда (даже для гостя).
- Контекст — данные текущего запроса.
- Несколько соединений на одну сессию — пользователь открыл много вкладок, сессия одна, RPC-каналов несколько.
Изоляция
«Нам нужно изолировать контексты друг от друга, изолировать системный код от прикладного, чтобы нельзя было из клиентского кода как-то обращаться к реквесту и респонсу.»
В Express/Nest часто пробивается до req, res, что нарушает абстракцию. В Metarhia:
- В прикладной код доступен только
context. context.client— клиент (с методом emit для событий).- HTTP-внутрянка (request, response, headers) — недоступна.
Persistence сессий
Сессии могут сохраняться в БД:
- Таблица
SystemSession— token, data, IP, время создания. - Таблица
SystemUser— пользователи. - Маленький модуль с методами
register,restoreSession,validate.
Counter через context.data
// applications/myapp/api/incrementCounter.js
module.exports = async (args, context) => {
context.data.counter = (context.data.counter || 0) + 1;
return context.data.counter;
};
context.data — Proxy, который сессия отслеживает. При каждом изменении знает, что надо сохранить.
Proxy и инжект
«Сессия создала коллекшен data, обернула его в Proxy и инжектнула в прикладной код контекст. Поэтому каждый раз, когда мы что-то читаем или пишем в контекст, сессия может об этом знать.»
Mechanism:
- Impress принял запрос.
- Достал сессию по токену.
- Создал контекст для запроса.
- Обернул
context.dataв Proxy. - Передал в прикладную функцию.
- После вызова — сохранил измененное в БД (если authenticated).
Без AsyncLocalStorage
Большинство Node-фреймворков используют ALS (AsyncLocalStorage) для контекста: «достань текущий контекст откуда угодно в стеке». Это сложно для отладки и имеет накладные расходы.
Metarhia: контекст явно прокидывается аргументом метода. context приходит как второй параметр в RPC-функцию.
Несколько соединений → одна сессия
Tab 1 ─→ WebSocket 1 ─┐
Tab 2 ─→ WebSocket 2 ─┼─→ Session (id=abc, user=roma)
Tab 3 ─→ WebSocket 3 ─┘
Все три канала разделяют одну сессию. Изменения context.data синкаются между ними через event bus.
Аутентификация
В Impress есть готовые методы:
registerUser({ login, password })→ токен.signIn({ login, password })→ токен.- Auth-pluggable через адаптеры (если нужен OAuth/SAML).
🎓 Источники
- 🎓 Sessions and contexts on Node.js and the Metarhia tech stack · 2021-02-05
- Цитата: «Внутренняя машинерия Metacom скрыта от клиентского кода, но видно из клиента и контекста только то, что необходимо пользователю.»
- 🎓 Семинар Metarhia #1 · 2021-01-30