UNPKG

phoenix

Version:

The official JavaScript client for the Phoenix web framework.

208 lines (205 loc) 7.45 kB
/** * Phoenix Channels JavaScript client * * ## Socket Connection * * A single connection is established to the server and * channels are multiplexed over the connection. * Connect to the server using the `Socket` class: * * ```javascript * let socket = new Socket("/socket", {params: {userToken: "123"}}) * socket.connect() * ``` * * The `Socket` constructor takes the mount point of the socket, * the authentication params, as well as options that can be found in * the Socket docs, such as configuring the `LongPoll` transport, and * heartbeat. * * ## Channels * * Channels are isolated, concurrent processes on the server that * subscribe to topics and broker events between the client and server. * To join a channel, you must provide the topic, and channel params for * authorization. Here's an example chat room example where `"new_msg"` * events are listened for, messages are pushed to the server, and * the channel is joined with ok/error/timeout matches: * * ```javascript * let channel = socket.channel("room:123", {token: roomToken}) * channel.on("new_msg", msg => console.log("Got message", msg) ) * $input.onEnter( e => { * channel.push("new_msg", {body: e.target.val}, 10000) * .receive("ok", (msg) => console.log("created message", msg) ) * .receive("error", (reasons) => console.log("create failed", reasons) ) * .receive("timeout", () => console.log("Networking issue...") ) * }) * * channel.join() * .receive("ok", ({messages}) => console.log("catching up", messages) ) * .receive("error", ({reason}) => console.log("failed join", reason) ) * .receive("timeout", () => console.log("Networking issue. Still waiting...")) *``` * * ## Joining * * Creating a channel with `socket.channel(topic, params)`, binds the params to * `channel.params`, which are sent up on `channel.join()`. * Subsequent rejoins will send up the modified params for * updating authorization params, or passing up last_message_id information. * Successful joins receive an "ok" status, while unsuccessful joins * receive "error". * * With the default serializers and WebSocket transport, JSON text frames are * used for pushing a JSON object literal. If an `ArrayBuffer` instance is provided, * binary encoding will be used and the message will be sent with the binary * opcode. * * *Note*: binary messages are only supported on the WebSocket transport. * * ## Duplicate Join Subscriptions * * While the client may join any number of topics on any number of channels, * the client may only hold a single subscription for each unique topic at any * given time. When attempting to create a duplicate subscription, * the server will close the existing channel, log a warning, and * spawn a new channel for the topic. The client will have their * `channel.onClose` callbacks fired for the existing channel, and the new * channel join will have its receive hooks processed as normal. * * ## Pushing Messages * * From the previous example, we can see that pushing messages to the server * can be done with `channel.push(eventName, payload)` and we can optionally * receive responses from the push. Additionally, we can use * `receive("timeout", callback)` to abort waiting for our other `receive` hooks * and take action after some period of waiting. The default timeout is 10000ms. * * * ## Socket Hooks * * Lifecycle events of the multiplexed connection can be hooked into via * `socket.onError()` and `socket.onClose()` events, ie: * * ```javascript * socket.onError( () => console.log("there was an error with the connection!") ) * socket.onClose( () => console.log("the connection dropped") ) * ``` * * * ## Channel Hooks * * For each joined channel, you can bind to `onError` and `onClose` events * to monitor the channel lifecycle, ie: * * ```javascript * channel.onError( () => console.log("there was an error!") ) * channel.onClose( () => console.log("the channel has gone away gracefully") ) * ``` * * ### onError hooks * * `onError` hooks are invoked if the socket connection drops, or the channel * crashes on the server. In either case, a channel rejoin is attempted * automatically in an exponential backoff manner. * * ### onClose hooks * * `onClose` hooks are invoked only in two cases. 1) the channel explicitly * closed on the server, or 2). The client explicitly closed, by calling * `channel.leave()` * * * ## Presence * * The `Presence` object provides features for syncing presence information * from the server with the client and handling presences joining and leaving. * * ### Syncing state from the server * * To sync presence state from the server, first instantiate an object and * pass your channel in to track lifecycle events: * * ```javascript * let channel = socket.channel("some:topic") * let presence = new Presence(channel) * ``` * * Next, use the `presence.onSync` callback to react to state changes * from the server. For example, to render the list of users every time * the list changes, you could write: * * ```javascript * presence.onSync(() => { * myRenderUsersFunction(presence.list()) * }) * ``` * * ### Listing Presences * * `presence.list` is used to return a list of presence information * based on the local state of metadata. By default, all presence * metadata is returned, but a `listBy` function can be supplied to * allow the client to select which metadata to use for a given presence. * For example, you may have a user online from different devices with * a metadata status of "online", but they have set themselves to "away" * on another device. In this case, the app may choose to use the "away" * status for what appears on the UI. The example below defines a `listBy` * function which prioritizes the first metadata which was registered for * each user. This could be the first tab they opened, or the first device * they came online from: * * ```javascript * let listBy = (id, {metas: [first, ...rest]}) => { * first.count = rest.length + 1 // count of this user's presences * first.id = id * return first * } * let onlineUsers = presence.list(listBy) * ``` * * ### Handling individual presence join and leave events * * The `presence.onJoin` and `presence.onLeave` callbacks can be used to * react to individual presences joining and leaving the app. For example: * * ```javascript * let presence = new Presence(channel) * * // detect if user has joined for the 1st time or from another tab/device * presence.onJoin((id, current, newPres) => { * if(!current){ * console.log("user has entered for the first time", newPres) * } else { * console.log("user additional presence", newPres) * } * }) * * // detect if user has left from all tabs/devices, or is still present * presence.onLeave((id, current, leftPres) => { * if(current.metas.length === 0){ * console.log("user has left from all devices", leftPres) * } else { * console.log("user left from a device", leftPres) * } * }) * // receive presence data from server * presence.onSync(() => { * displayUsers(presence.list()) * }) * ``` * @module phoenix */ import Channel from "./channel" import LongPoll from "./longpoll" import Presence from "./presence" import Serializer from "./serializer" import Socket from "./socket" export { Channel, LongPoll, Presence, Serializer, Socket }