billstclair / elm-websocket-client / PortFunnel.WebSocket

Web sockets make it cheaper to talk to your servers.

Connecting to a server takes some time, so with web sockets, you make that connection once and then keep using. The major benefits of this are:

  1. It faster to send messages. No need to do a bunch of work for every single message.

  2. The server can push messages to you. With normal HTTP you would have to keep asking for changes, but a web socket, the server can talk to you whenever it wants. This means there is less unnecessary network traffic.

Web Sockets

Types


type State

Internal state of the WebSocketClient module.

Get the initial, empty state with initialState.


type alias Message =
InternalMessage

Opaque message type.

You can create the instances you need to send with openMessage, sendMessage, closeMessage, and bytesQueuedMessage.


type Response
    = NoResponse
    | CmdResponse Message
    | ListResponse (List Response)
    | ConnectedResponse ({ key : String, description : String })
    | ReconnectedResponse ({ key : String, description : String })
    | MessageReceivedResponse ({ key : String, message : String })
    | ClosedResponse ({ key : String, code : ClosedCode, reason : String, wasClean : Basics.Bool, expected : Basics.Bool })
    | BytesQueuedResponse ({ key : String, bufferedAmount : Basics.Int })
    | ErrorResponse Error

A response that your code must process to update your model.

NoResponse means there's nothing to do.

CmdResponse encapsulates a Message that needs to be sent out through your Cmd port. This is done internally. Your application code may ignore these responses.

ListResponse contains a number of responses. It is generated only when you send messages while the connection is down, causing them to be queued up. It may contain one or more ReconnectedResponse instances, so if you care about that, you should call reconnectedResponses to extract them.

ConnectedResponse tells you that an earlier call to send or keepAlive has successfully connected. You can usually ignore this.

ReconnectedResponse is sent when the connection to the server has been re-established after being lost. If you need to re-establish logical connections after losing the physical connection, you'll need to pay attention to this. Otherwise, you can safely ignore it.

MessageReceivedResponse is a message from one of the connected sockets.

ClosedResponse tells you that an earlier call to close has completed. Its code, reason, and wasClean fields are as passed by the JavaScript WebSocket interface. Its expected field will be True, if the response is to a close call on your part. It will be False if the close was unexpected, and reconnection attempts failed for 20 seconds (using exponential backoff between attempts).

ErrorResponse means that something went wrong. Details in the encapsulated Error.


type Error
    = SocketAlreadyOpenError String
    | SocketConnectingError String
    | SocketClosingError String
    | SocketNotOpenError String
    | UnexpectedConnectedError ({ key : String, description : String })
    | UnexpectedMessageError ({ key : String, message : String })
    | LowLevelError InternalMessage.PIErrorRecord
    | InvalidMessageError ({ message : Message })

All the errors that can be returned in a Response.ErrorResponse.

If an error tag has a single String arg, that string is a socket key.


type ClosedCode
    = NormalClosure
    | GoingAwayClosure
    | ProtocolErrorClosure
    | UnsupportedDataClosure
    | NoStatusRecvdClosure
    | AbnormalClosure
    | InvalidFramePayloadDataClosure
    | PolicyViolationClosure
    | MessageTooBigClosure
    | MissingExtensionClosure
    | InternalErrorClosure
    | ServiceRestartClosure
    | TryAgainLaterClosure
    | BadGatewayClosure
    | TLSHandshakeClosure
    | TimedOutOnReconnect
    | UnknownClosure

This will usually be NormalClosure. The rest are standard, except for UnknownClosure, which denotes a code that is not defined, and TimeoutOutOnReconnect, which means that exponential backoff connection reestablishment attempts timed out.

The standard codes are from https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent


type alias JSVersion =
{ v4_1 : () }

This is used to force a major version bump when the JS changes.

You'll usually not use it for anything.

Components of a PortFunnel.FunnelSpec

moduleName : String

The name of this module: "WebSocket".

moduleDesc : PortFunnel.ModuleDesc Message State Response

Our module descriptor.

commander : (PortFunnel.GenericMessage -> Platform.Cmd.Cmd msg) -> Response -> Platform.Cmd.Cmd msg

Responsible for sending a CmdResponse back through the port.

Called by PortFunnel.appProcess for each response returned by process.

Initial State

initialState : State

The initial, empty state.

Creating a Message

makeOpen : String -> Message

Create a Message to open a connection to a WebSocket server.

makeOpen url

Example:

makeOpen "wss://echo.websocket.org"
    |> send cmdPort

makeSend : String -> String -> Message

Create a Message to send a string to a particular address.

makeSend key message

Example:

makeSend "wss://echo.websocket.org" "Hello!"
    |> send cmdPort

You must send a makeOpen or makeOpenWithKey message before makeSend.

If you send a makeSend message before the connection has been established, or while it is being reestablished after it was lost, your message will be buffered and sent after the connection has been (re)established.

makeClose : String -> Message

Create a Message to close a previously opened WebSocket.

makeClose key

The key arg is either they key arg to makeOpenWithKey or makeKeepAliveWithKey or the url arg to makeOpen or makeKeepAlive.

Example:

makeClose "echo"
    |> send cmdPort

makeOpenWithKey : String -> String -> Message

Like makeOpen, but allows matching a unique key to the connection.

makeOpen uses the url as the key.

makeOpenWithKey key url

Example:

makeOpenWithKey "echo" "wss://echo.websocket.org"

makeKeepAlive : String -> Message

Create a Message to connect to a WebSocket server, but not report received messages.

makeKeepAlive url

For keeping a connection open for when you only need to send makeSend messages.

Example:

   makeKeepAlive "wss://echo.websocket.org"
     |> send cmdPort

makeKeepAliveWithKey : String -> String -> Message

Like makeKeepAlive, but allows matching a unique key to the connection.

   makeKeepAliveWithKey key url

Example:

   makeKeepAliveWithKey "echo" "wss://echo.websocket.org"
     |> send cmdPort

Sending a Message out the Cmd Port

send : (Json.Encode.Value -> Platform.Cmd.Cmd msg) -> Message -> Platform.Cmd.Cmd msg

Send a Message through a Cmd port.

Conversion to Strings

toString : Message -> String

Convert a Message to a nice-looking human-readable string.

toJsonString : Message -> String

Convert a Message to the same JSON string that gets sent

over the wire to the JS code.

errorToString : Error -> String

Convert an Error to a string, for simple reporting.

closedCodeToString : ClosedCode -> String

Turn a ClosedCode into a String, for debugging.

Simulator

makeSimulatedCmdPort : (Json.Encode.Value -> msg) -> Json.Encode.Value -> Platform.Cmd.Cmd msg

Make a simulated Cmd port.

Non-standard functions

isLoaded : State -> Basics.Bool

Returns true if a Startup message has been processed.

This is sent by the port code after it has initialized.

isConnected : String -> State -> Basics.Bool

Returns true if a connection is open for the given key.

isConnected key state

getKeyUrl : String -> State -> Maybe String

Get the URL for a key.

willAutoReopen : String -> State -> Basics.Bool

Return True if the connection for the given key will be automatically reopened if it closes unexpectedly.

This is the default. You may change it with setAutoReopen.

willAutoReopen key state

setAutoReopen : String -> Basics.Bool -> State -> State

Set whether the connection for the given key will be automatically reopened if it closes unexpectedly.

This defaults to True. If you would rather get a ClosedResponse when it happens and handle it yourself, set it to False before sending a makeOpen message.

You may change it back to False later. Changing it to True later will not interrupt any ongoing reconnection process.

setAutoReopen key autoReopen

The key is either the key you plan to use for a makeOpenWithKey or makeKeepAliveWithKey message or the url for a makeOpen or makeKeepAlive message.

filterResponses : (Response -> Basics.Bool) -> Response -> List Response

Filter the Response arg with the predicate arg.

If the Response is a ListResponse, then return the elements of its encapsulated list which satisfy the predicate.

If the Response itself satisfies the predicate, return it in a single-element list.

Otherwise, return the empty list.

isReconnectedResponse : Response -> Basics.Bool

Return True iff the Response is a ReconnectedResponse.

reconnectedResponses : Response -> List Response

Return a list of the ReconnectedResponse instances in the Response.

reconnectedResponses response

is equivalent to:

filterResponse isReconnectedResponse response

Internal, exposed only for tests

encode : Message -> PortFunnel.GenericMessage

Encode a Message into a GenericMessage.

Only exposed so the tests can use it.

User code will use it implicitly through moduleDesc.

decode : PortFunnel.GenericMessage -> Result String Message

Decode a GenericMessage into a Message.

Only exposed so the tests can use it.

User code will use it implicitly through moduleDesc.