Issho.Participant (Issho v0.4.0)

Copy Markdown View Source

An actor in a room from Elixir: an agent running in your app, a job, a script. It joins like a browser, with the same presence, awareness, locks, transactions and policy, and the people in the room see it.

{:ok, claude} = Issho.join_as(MyApp.Issho, agent, "board:42", on_behalf_of: ada)

{:ok, doc} = Issho.Participant.open(claude, "board:42")
Issho.Participant.place(claude, %{"doc" => "board:42", "at" => %{"node" => "n7"}})
Issho.Participant.lock(claude, [%{"doc" => "board:42", "at" => %{"node" => "n7"}}])
{:ok, _receipt} = Issho.Participant.transact(claude, "board:42", ops)
Issho.Participant.leave(claude)

A participant is a process linked to the one that joins. It forwards what happens in the room to that process (or to :notify) as {Issho.Participant, participant, event, payload} messages: "tx", "aware", "presence_diff" and "bye", as a browser receives them, and, with events: true, "event": the room's events (Issho.Event), but those the participant made happen itself.

transact/3 takes a list of operations (Issho builds the envelope, on the latest revision) or a whole transaction map, to retry one with its original id.

Present, paused, stopped

A participant is a state machine (:gen_statem): present in the room, or paused or stopped by a person (Issho.Work). Paused or stopped, it changes nothing: each transaction is refused whole ({:error, {:interrupted, by}}), so nothing is half done, and its task says who paused or stopped it. It reads, looks and leaves as ever. A resume makes it present again; so does finishing its task (a pause or a stop), or beginning another (a stop).

Summary

Functions

Whether the room's policy lets the participant do action (:read, :write, :lock or your own) now: for a component whose data is not in Issho's documents, such as a grid of your database, which writes it itself. A write needs a participant that writes (can: :write).

Merges keys into the participant's awareness state ("status", your own).

Merges a component's own keys into the participant's state, under its document ("blocks", see Issho.Awareness); a key set to nil goes.

The participant's own awareness state: its place, its locks, its status.

The participant's identity in the room: who it is, and whom it acts for.

Whether someone paused or stopped the participant in the room (Issho.Work): %{"action" => "pause" | "stop", "by" => person}, or nil. While it is, its transactions are refused.

The participant's key in the room (its identity's).

Leaves the room.

Sets the places the participant locks ([] releases them).

The places locked in the room by anyone, each with its holder's key.

Opens a document of the room; gives its snapshot.

The people of the room now (Phoenix.Presence's list, by actor key), each with where they are: %{key => %{"person" => meta, "places" => [place], "states" => [state]}}, a place for each of their sessions that has one, and each session's whole awareness state (a component's own keys: a canvas's selection, say).

Sets the participant's place (nil for none), keeping its locks.

The document's current snapshot.

The room of the participant.

Commits operations, or a whole transaction, to an open document.

Functions

authorize(participant, action)

@spec authorize(GenServer.server(), atom()) :: :ok | {:error, term()}

Whether the room's policy lets the participant do action (:read, :write, :lock or your own) now: for a component whose data is not in Issho's documents, such as a grid of your database, which writes it itself. A write needs a participant that writes (can: :write).

aware(participant, changes)

@spec aware(GenServer.server(), map()) :: :ok | {:error, term()}

Merges keys into the participant's awareness state ("status", your own).

aware_block(participant, document, changes)

@spec aware_block(GenServer.server(), String.t(), map()) :: :ok | {:error, term()}

Merges a component's own keys into the participant's state, under its document ("blocks", see Issho.Awareness); a key set to nil goes.

awareness(participant)

@spec awareness(GenServer.server()) :: map()

The participant's own awareness state: its place, its locks, its status.

identity(participant)

@spec identity(GenServer.server()) :: Issho.Identity.t()

The participant's identity in the room: who it is, and whom it acts for.

interrupted(participant)

@spec interrupted(GenServer.server()) :: map() | nil

Whether someone paused or stopped the participant in the room (Issho.Work): %{"action" => "pause" | "stop", "by" => person}, or nil. While it is, its transactions are refused.

key(participant)

@spec key(GenServer.server()) :: String.t()

The participant's key in the room (its identity's).

leave(participant)

@spec leave(GenServer.server()) :: :ok

Leaves the room.

lock(participant, places)

@spec lock(GenServer.server(), [map()]) :: :ok | {:error, term()}

Sets the places the participant locks ([] releases them).

locks(participant)

@spec locks(GenServer.server()) :: [{map(), String.t()}]

The places locked in the room by anyone, each with its holder's key.

open(participant, document_id)

@spec open(GenServer.server(), String.t()) :: {:ok, map()} | {:error, term()}

Opens a document of the room; gives its snapshot.

people(participant)

@spec people(GenServer.server()) :: map()

The people of the room now (Phoenix.Presence's list, by actor key), each with where they are: %{key => %{"person" => meta, "places" => [place], "states" => [state]}}, a place for each of their sessions that has one, and each session's whole awareness state (a component's own keys: a canvas's selection, say).

place(participant, place)

@spec place(GenServer.server(), map() | nil) :: :ok | {:error, term()}

Sets the participant's place (nil for none), keeping its locks.

read(participant, document_id)

@spec read(GenServer.server(), String.t()) :: {:ok, map()} | {:error, term()}

The document's current snapshot.

room(participant)

@spec room(GenServer.server()) :: String.t()

The room of the participant.

transact(participant, document_id, ops_or_transaction)

@spec transact(GenServer.server(), String.t(), [map()] | map()) ::
  {:ok, map()} | {:error, term()}

Commits operations, or a whole transaction, to an open document.