transport

package
v0.3.3 Latest Latest
Warning

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

Go to latest
Published: May 5, 2026 License: MIT Imports: 5 Imported by: 0

Documentation

Overview

Package transport defines the contract between the tether framework and its transport implementations (WebSocket, SSE). It lives in an internal package so that the main tether package can import the concrete ws and sse packages without creating a circular dependency.

User code should use the type aliases in the tether package ([tether.Transport], [tether.Event], [tether.Heartbeater]) rather than importing this package directly.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Event

type Event struct {
	Type    event.Type        `json:"type"`
	Action  string            `json:"action"`
	Target  string            `json:"target,omitempty"`
	Data    map[string]string `json:"data,omitempty"`
	EventID string            `json:"event_id,omitempty"`
}

Event is the message the client sends to the server when the user interacts with the page. The client JS intercepts DOM events on elements annotated with data-tether-* attributes and serialises them into this structure.

Type is the DOM event type (e.g. click, input, submit, navigate). Action is the application-defined name that the Handle function switches on. Data carries event-specific key-value pairs.

EventID is a monotonically increasing counter generated by the client JS and echoed back in the server's response. The client uses it to correlate responses with specific events.

func (Event) Bind

func (e Event) Bind(dest any) error

Bind decodes the event's Data map into a struct. Fields are matched by the "tether" struct tag; untagged exported fields use their lowercased name. Supported field types: string, int, int64, float64, bool.

This is the multi-field counterpart to the single-value helpers (Value, Key, Int, Bool). Use Bind when a form submit sends several named fields at once:

var form struct {
    Email string `tether:"email"`
    Age   int    `tether:"age"`
}
if err := ev.Bind(&form); err != nil {
    s.TodoError = err.Error()
    return s
}

func (Event) Bool

func (e Event) Bool(key string) bool

Bool returns true when the data value for key is the string "true". All other values - including missing keys - return false.

func (Event) Float64

func (e Event) Float64(key string) (float64, error)

Float64 returns the data value for key parsed as a float. If the key is missing or the value is not a valid number, it returns 0 and an error.

func (Event) Get

func (e Event) Get(key string) (string, bool)

Get returns the value for a data key and reports whether it was present.

func (Event) Int

func (e Event) Int(key string) (int, error)

Int returns the data value for key parsed as an integer. If the key is missing or the value is not a valid integer, it returns 0 and an error.

func (Event) Key

func (e Event) Key() string

Key returns the key name from a keydown event. This is a convenience for ev.Data["key"], which the client JS populates automatically for keydown events (e.g. "Enter", "Escape", "ArrowUp").

func (Event) Value

func (e Event) Value() string

Value returns the input element's value from the event data. This is a convenience for ev.Data["value"], which the client JS populates automatically for input and change events.

func (Event) WithAction

func (e Event) WithAction(action string) Event

WithAction returns a copy of the event with a different Action. Used by component routing to strip the component prefix before forwarding the event to a component's Handle method.

type Heartbeater

type Heartbeater interface {
	StartHeartbeat(interval time.Duration)
}

Heartbeater is an optional interface for transports that need periodic keep-alive activity. Both built-in transports implement it: SSE sends comment lines to prevent proxy timeouts; WebSocket sends ping frames and sets read deadlines to detect silently dropped connections.

When the handler detects that a transport implements Heartbeater, it calls StartHeartbeat with the configured interval after the session is established.

type Transport

type Transport interface {
	// Send writes pre-encoded bytes to the client. The session
	// encodes updates before calling Send, so implementations only
	// need to frame and transmit the data.
	Send(data []byte) error

	// ReceiveEvent blocks until the next client event arrives. Returns
	// io.EOF when the connection is closed cleanly. Any other error is
	// treated as an unrecoverable connection failure and terminates the
	// session.
	ReceiveEvent() (Event, error)

	// Close terminates the connection. Must be safe to call from any
	// goroutine and safe to call more than once.
	Close() error
}

Transport abstracts the persistent connection between server and client. The session event loop calls ReceiveEvent in a tight loop and calls Send after each state change. Implementations must be safe for concurrent use: Send may be called from any goroutine, while ReceiveEvent is only called from the event loop goroutine.

Send receives pre-encoded bytes - the session handles all encoding so transports only deal with raw bytes.

Jump to

Keyboard shortcuts

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