src/cart/cart.oxl
use super.model.*
use super.config { Features }
use super.limits { CART_IDLE }
// Шардированный актор (V.5, §12.5): одна корзина на пользователя во всём кластере. Живёт на узле-владельце шарда userId;
// `var` сохраняются в журнал после каждого сообщения, неактивная корзина выгружается из памяти, но не теряется.
@idle(CART_IDLE)
pub actor Cart sharded by userId: UserId {
var items: List<Item> = []
// Сообщения обрабатываются строго по одному — гонок за items нет
msg add(item: Item) -> () | CartFull {
let max = Features.get().maxCart.get()
if items.len() as u32 >= max { fail CartFull{ max } }
items.push(item)
()
}
msg remove(sku: Sku) { items = items.filter(i => i.sku != sku) }
// Копия содержимого: сама корзина остаётся у актора
msg snapshot() -> CartSnapshot {
CartSnapshot{ userId: userId, items: items.clone(),
total: items.fold(Money.ZERO, (a, i) => a + i.price * (i.qty as i64)) }
}
msg clear() { items = [] }
// Убирает из корзины только первые `n` позиций — те, что вошли в снимок заказа; добавленные после снимка остаются.
// Вызывается из `checkout` с `await` (в Стандарте V.5 — `removeOrdered`): очистка в фоне гонялась бы со следующим запросом.
msg removeOrdered(n: usize) {
if n >= items.len() { items = [] }
else { items = items.iter().skip(n).collect() }
}
}
// Пользователь может работать только со своей корзиной; userId — ключ актора
policy Cart { allow * if caller.isUser("{userId}") } // `isUser` takes the id as text (the JWT `sub`), as in `users` (DEVIATIONS.md #3)Исходник: examples/shop/src/cart/cart.oxl