channels

package
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 4, 2026 License: Apache-2.0 Imports: 15 Imported by: 0

Documentation

Overview

Package channels implements the upstream Phoenix Channels V2 wire protocol served at /appengine/v1/socket/websocket. It is the compatibility counterpart to the Astrate-native socket in internal/appengine/stream.

Index

Constants

View Source
const (
	EventPhxJoin   = "phx_join"
	EventPhxReply  = "phx_reply"
	EventPhxLeave  = "phx_leave"
	EventPhxClose  = "phx_close"
	EventPhxError  = "phx_error"
	EventHeartbeat = "heartbeat"

	// TopicHeartbeat is the reserved topic for heartbeat messages.
	TopicHeartbeat = "phoenix"
)

Event-name constants used by the Phoenix V2 protocol.

View Source
const (
	EventWatch    = "watch"
	EventUnwatch  = "unwatch"
	EventNewEvent = "new_event"
)

Event-name constants for the watch/unwatch/new_event cycle.

View Source
const DefaultMailbox = 64

DefaultMailbox is the mailbox capacity used when AddMember is given a non-positive buffer.

Variables

This section is empty.

Functions

This section is empty.

Types

type API

type API struct {
	// contains filtered or unexported fields
}

API serves the Phoenix V2 WebSocket endpoint.

func NewAPI

func NewAPI(bus Bus, keys auth.KeySource) *API

NewAPI creates an API backed by the given bus and key source.

func (*API) Mount

func (a *API) Mount(mux *http.ServeMux)

Mount registers the WebSocket handler on the given mux.

type Bus

type Bus interface {
	Subscribe(realm string, f stream.Filter, buffer int) (<-chan stream.Event, func())
}

Bus is the subset of *stream.Bus a room needs. *stream.Bus satisfies it.

type Frame

type Frame struct {
	JoinRef *string
	Ref     *string
	Topic   string
	Event   string
	Payload json.RawMessage
}

Frame is one Phoenix V2 message on the wire, encoded as a five-element JSON array: [join_ref, ref, topic, event, payload]. A nil JoinRef or Ref is marshalled as JSON null; the two are distinguished from the empty string.

func Err

func Err(in Frame, reason string) (Frame, error)

Err is a convenience wrapper over Reply that sends an "error" status with a reason field.

func OK

func OK(in Frame, response any) (Frame, error)

OK is a convenience wrapper over Reply that sends a "ok" status.

func Reply

func Reply(in Frame, status string, response any) (Frame, error)

Reply builds a phx_reply answer to in. The JoinRef and Ref are echoed from in so the client can route the reply to its caller. The payload is {"status":"<status>","response":<response>}. A nil response renders as {}.

func (Frame) MarshalJSON

func (f Frame) MarshalJSON() ([]byte, error)

MarshalJSON renders the frame as a five-element JSON array. A nil JoinRef or Ref becomes JSON null. A nil or zero-length Payload becomes {}.

func (*Frame) UnmarshalJSON

func (f *Frame) UnmarshalJSON(b []byte) error

UnmarshalJSON parses a five-element JSON array back into the frame. It rejects anything that is not a JSON array of exactly five elements.

type Member

type Member struct {
	// contains filtered or unexported fields
}

Member is a joined socket with its own mailbox.

func (*Member) Dropped

func (m *Member) Dropped() uint64

Dropped reports how many envelopes were discarded because the mailbox was full.

func (*Member) Events

func (m *Member) Events() <-chan triggers.SimpleEvent

Events returns the mailbox channel.

func (*Member) Leave

func (m *Member) Leave()

Leave deregisters the member and closes its mailbox exactly once.

type Registry

type Registry struct {
	// contains filtered or unexported fields
}

Registry is a topic→room map.

func NewRegistry

func NewRegistry(b Bus) *Registry

NewRegistry creates a new Registry.

func (*Registry) Join

func (r *Registry) Join(realm, topic string) *Room

Join returns the room for topic, creating it on first join.

func (*Registry) Rooms

func (r *Registry) Rooms() int

Rooms reports the live room count.

type Room

type Room struct {
	// contains filtered or unexported fields
}

Room is one Phoenix topic.

func (*Room) AddMember

func (rm *Room) AddMember(buffer int) *Member

AddMember registers a member with a mailbox of the given capacity. A non-positive buffer selects DefaultMailbox.

func (*Room) Unwatch

func (rm *Room) Unwatch(name string) bool

Unwatch removes a watch, reporting whether one was there.

func (*Room) Watch

func (rm *Room) Watch(req WatchRequest) error

Watch compiles and stores a watch.

func (*Room) Watches

func (rm *Room) Watches() int

Watches reports the number of active watches.

type WatchRequest

type WatchRequest struct {
	Name          string          `json:"name"`
	DeviceID      string          `json:"device_id"`
	GroupName     string          `json:"group_name"`
	SimpleTrigger json.RawMessage `json:"simple_trigger"`
}

WatchRequest is the watch payload DTO, exactly as the client sends it.

GroupName is a top-level field, measured against upstream (channels.json, 2026-08-22): a group_name nested inside simple_trigger is refused by upstream's changeset, and one at the top level is what its authorization path is built from. Astrate used to read it only from simple_trigger, which meant an upstream-shaped group watch silently degraded into a device-shaped path check.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL