Chip as a session index
We may use chip to track individual subjects through an identifier. The identifier may be an integer, string or even a union type if you only need few records.
This pattern would be a way of re-defining chip as an indexed store:
import chip
import gleam/erlang/process
import gleam/otp/actor
import gleam/otp/supervisor
pub type Store(message) =
chip.Registry(message, Int)
pub type Id =
Int
pub fn start() -> Result(Store(message), actor.StartError) {
chip.start(chip.Unnamed)
}
pub fn childspec() {
supervisor.worker(fn(_index) { start() })
}
pub fn index(store: Store(message), id: Id, subject: process.Subject(message)) {
chip.register(store, id, subject)
}
pub fn get(store: Store(message), id: Id) {
case chip.members(store, id, 50) {
[] -> Error(Nil)
[subject] -> Ok(subject)
[_, ..] -> panic as "Shouldn't insert more than 1 subject."
}
}
It may be used to retrieve information from out of bound subjects. For example, in a web app we may add the registry as part of our app context:
import artifacts/game.{DrawCard}
import artifacts/store
pub fn main() {
let assert Ok(sessions) = store.start()
let assert Ok(session_1) = game.start(DrawCard)
let assert Ok(session_2) = game.start(DrawCard)
let assert Ok(session_3) = game.start(DrawCard)
store.index(sessions, 1, session_1)
store.index(sessions, 2, session_2)
store.index(sessions, 3, session_3)
router(sessions, "/resource/", 2)
}
fn router(sessions, url, id) {
case url, id {
"/resource/", id -> render_resource(sessions, id)
_other, _id -> render_error()
}
}
fn render_resource(sessions, id) {
case store.get(sessions, id) {
Ok(session) -> game.current(session)
Error(Nil) -> render_error()
}
}
fn render_error() {
"Print Error"
}
Of course, if our sessions die we can no longer reference them through the index. For process restart strategies check the supervision guideline.