Current section

Files

Jump to
processgroups src processgroups.gleam
Raw

src/processgroups.gleam

import gleam/dynamic
import gleam/dynamic/decode
import gleam/erlang
import gleam/erlang/atom
import gleam/erlang/process
/// A scope for process groups is an atom, we type alias to make it clearer
pub type Scope =
atom.Atom
@external(erlang, "pg", "start_link")
pub fn start_link() -> Result(process.Pid, dynamic.Dynamic)
@external(erlang, "pg", "start_link")
pub fn start_link_with_scope(
scope: Scope,
) -> Result(process.Pid, dynamic.Dynamic)
@external(erlang, "pg", "start")
pub fn start(scope: Scope) -> Result(process.Pid, dynamic.Dynamic)
@external(erlang, "pg", "join")
pub fn join(group: group, pid: process.Pid) -> Nil
@external(erlang, "pg", "join")
pub fn join_many(group: group, pids: List(process.Pid)) -> Nil
@external(erlang, "pg", "join")
pub fn join_scope(scope: Scope, group: group, pid: process.Pid) -> Nil
@external(erlang, "pg", "join")
pub fn join_scope_many(
scope: Scope,
group: group,
pids: List(process.Pid),
) -> Nil
@external(erlang, "pg", "leave")
pub fn leave(group: group, pid: process.Pid) -> Nil
@external(erlang, "pg", "leave")
pub fn leave_scope(scope: Scope, group: group, pid: process.Pid) -> atom.Atom
@external(erlang, "pg", "leave")
pub fn leave_many(group: group, pids: List(process.Pid)) -> Nil
@external(erlang, "pg", "leave")
pub fn leave_many_scope(
scope: Scope,
group: group,
pids: List(process.Pid),
) -> atom.Atom
/// For monitoring, we use the `gleam/erlang/process`
/// module and their way of handling messages.
/// The GroupMonitor type is constructed when monitoring
/// a process group. You can than use `selecting_process_group_monitor`
/// To receive `GroupMonitorEvent` messages using `gleam/erlang/process.select`.
pub opaque type GroupMonitor(group) {
GroupMonitor(tag: erlang.Reference, group: group)
}
/// The events send when monitoring a process group.
pub type GroupMonitorEvent(group) {
/// Some processes have joined
ProcessJoined(group: group, pids: List(process.Pid))
/// Same process have left
ProcessLeft(group: group, pids: List(process.Pid))
}
pub fn monitor(group: group) -> #(GroupMonitor(group), List(process.Pid)) {
let #(ref, pids) = erlang_monitor(group)
#(GroupMonitor(tag: ref, group: group), pids)
}
@external(erlang, "pg", "monitor")
fn erlang_monitor(group: group) -> #(erlang.Reference, List(process.Pid))
pub fn monitor_scope(
scope: Scope,
group: group,
) -> #(GroupMonitor(group), List(process.Pid)) {
let #(ref, pids) = erlang_monitor_scope(scope, group)
#(GroupMonitor(tag: ref, group: group), pids)
}
@external(erlang, "pg", "monitor")
pub fn erlang_monitor_scope(
scope: Scope,
group: group,
) -> #(erlang.Reference, List(process.Pid))
/// Receive monitoring events.
///
/// # Example
///
/// ```
/// import pg_for_gleam as pg
/// import gelam/erlang/process
///
/// let monitor = pg.monitor(SomeProcessGroup)
///
/// let selector = pg.selecting_process_group_monitor(
/// selector: new_selector(),
/// monitor: monitor,
/// mapping: fn(gme) {gme}
/// )
///
/// case select(selector) {
/// Ok(ProcessJoined(_, pids)) -> io.print("some process joined")
/// Ok(ProcessLeft(_, pids)) -> io.print("some process left")
/// _ -> panic
/// }
/// ```
pub fn selecting_process_group_monitor(
selector: process.Selector(payload),
monitor: GroupMonitor(group),
mapping: fn(GroupMonitorEvent(group)) -> payload,
) -> process.Selector(payload) {
// monitoring sends 4-tuples, see https://www.erlang.org/doc/man/pg.html#monitor_scope-0
process.selecting_record4(
selector,
monitor.tag,
fn(event: dynamic.Dynamic, _group: dynamic.Dynamic, pids: dynamic.Dynamic) {
let assert Ok(event) = atom.from_dynamic(event)
let assert Ok(pids) =
decode.run(
pids,
decode.list(
decode.new_primitive_decoder("pid", fn(d) {
case process.pid_from_dynamic(d) {
Ok(pid) -> Ok(pid)
Error(_) -> Error(process.self())
}
}),
),
)
let payload = case atom.to_string(event) {
"join" -> ProcessJoined(monitor.group, pids)
"leave" -> ProcessLeft(monitor.group, pids)
_ -> panic
}
mapping(payload)
},
)
}
@external(erlang, "pg", "demonitor")
pub fn demonitor(group: group) -> Bool
@external(erlang, "pg", "demonitor")
pub fn demonitor_scope(scope: Scope, group: group) -> Bool
@external(erlang, "pg", "get_local_members")
pub fn get_local_members(group: group) -> List(process.Pid)
@external(erlang, "pg", "get_local_members")
pub fn get_local_members_scope(scope: Scope, group: group) -> List(process.Pid)
@external(erlang, "pg", "get_members")
pub fn get_members(group: group) -> List(process.Pid)
@external(erlang, "pg", "get_members")
pub fn get_members_scope(scope: Scope, group: group) -> List(process.Pid)
@external(erlang, "pg", "which_groups")
pub fn which_groups() -> List(group)
@external(erlang, "pg", "which_groups")
pub fn which_groups_scope(scope: Scope) -> List(group)