phollyer/elm-phoenix-websocket/1.0.0

NOTE: the latest version is 4.0.0

Socket

This module is for working directly with the socket.

Once you have connected to the socket, you will then need to join a channel.

Sending Messages

send : EventOut -> PortOut msg -> Cmd msg

Send an EventOut to the socket.

import Ports.Phoenix as Phx
import Socket exposing (EventOut(..))


-- Connect to the Socket


Phx.sendMessage
  |> Socket.send
    (Connect Nothing)


-- Disconnect from the Socket


Phx.sendMessage
  |> Socket.send
    Disconnect
= Connect (Maybe Value)
| ConnectWithOptions ConnectOptions (Maybe Value)
| Disconnect
| ConnectionState
| EndPointURL
| HasLogger
| IsConnected
| MakeRef
| Protocol
| Log
{ kind : String
, msg : String
, data : Value
}

All of the events you can send to the socket.

You will probably be most interested in Connect, ConnectWithOptions and Disconnect.

Each of these EventOut messages corresponds to the equivalent function in the PhoenixJS API. For more info on these please read the API docs.

type alias PortOut msg =
PackageOut -> Cmd msg

A type alias representing the port function required to send the EventOut to the socket.

You could write this yourself, if you do, it needs to be named sendMessage, although you may find it simpler to just add this port module to your src - it includes all the necessary port functions.

type alias PackageOut =
{ target : String
, event : String
, payload : Value
}

A type alias representing the data sent out through the port to the socket. You will not use this directly.

Connecting With Options

This enables finer control over the socket if you want to adjust the default settings.

connectOptions : ConnectOptions

A helper function to return a ConnectOptions record with Nothing set on everything. Use it as a starting point for setting just the options you want.

{ connectOptions | timeout = Just 10000 }

Not all options are available on all versions of PhoenixJS, so check the docs at https://hexdocs.pm/phoenix/{vesion}/js if something isn't working as expected.

And please raise an issue if you find that an option doesn't behave as it should.

type alias ConnectOptions =
{ transport : Maybe String
, timeout : Maybe Int
, heartbeatIntervalMs : Maybe Int
, reconnectAfterMs : Maybe Int
, reconnectMaxBackOff : Maybe Int
, reconnectSteppedBackoff : Maybe (List Int)
, rejoinAfterMs : Maybe Int
, rejoinMaxBackOff : Maybe Int
, rejoinSteppedBackoff : Maybe (List Int)
, longpollerTimeout : Maybe Int
, binaryType : Maybe String
}

A type alias representing the options that can be set on the socket when instantiating a new Socket(url, options) on the JS side.

See https://hexdocs.pm/phoenix/js/#socket for more info on the options and the effect they have. All the option types are Maybe's of the equivalent JS types, with two exceptions:

  1. reconnectAfterMS
  2. rejoinAfterMs

On the JS side, these take an Int or a function that returns an Int. But because we can't send functions through ports, you can set the ...MaxBackOff and ...SteppedBackOff values as follows:

{ connectOptions
    | reconnectSteppedBackOff = [ 10, 20, 50, 100, 500 ]
    , reconnectMaxBackOff = 1000
}


{ connectOptions
    | rejoinSteppedBackOff = [ 1000, 2000, 5000 ]
    , rejoinMaxBackOff = 10000
}

On the JS side, this results in:

{ reconnectAfterMs: function(tries){ return [10, 20, 50, 100, 500][tries - 1] || 1000 }}


{ rejoinAfterMs: function(tries){ return [1000, 2000, 5000][tries - 1] || 10000 }}

Receiving Messages

subscriptions : (EventIn -> msg) -> PortIn msg -> Sub msg

Subscribe to receive incoming socket events.

import Ports.Phoenix as Phx
import Socket


type Msg
  = SocketMsg Socket.EventIn
  | ...




subscriptions : Model -> Sub Msg
subscriptions _ =
    Phx.socketReceiver
      |> Socket.subscriptions
        SocketMsg
type EventIn
= Opened
| Closed
| Error String
| Message MessageConfig
| ConnectionStateReply String
| EndPointURLReply String
| HasLoggerReply (Maybe Bool)
| IsConnectedReply Bool
| MakeRefReply String
| ProtocolReply String
| InvalidEvent String

All of the events you can receive from the socket.

You will probably be most interested in Opened, Closed and Error.

The data each EventIn carries should be self explanatory, except for maybe:

HasLoggerReply - not all versions of PhoenixJS have the hasLogger function. Therefore, a value of Nothing means the function does not exist, while a Just will carry the result of calling hasLogger on the socket.

InvalidEvent means that an event has been received from the accompanying JS that cannot be handled. This should not happen, if it does, please raise an issue.

type alias MessageConfig =
{ joinRef : Maybe String
, ref : Maybe String
, topic : String
, event : String
, payload : Value
}

A type alias representing the raw message received by the socket. This arrives as an EventIn Message.

You will need to decode payload yourself, as only you will know the structure of this Value. It will be whatever data has been sent back from Phoenix corresponding to event so you will need to check this in order to select the correct decoder if you are sending different structures for different events.

If you are using multiple channels, you will also need to check the topic to identify the channel that sent the event.

You won't need this if you choose to handle messages over Channels.

type alias PortIn msg =
(PackageIn -> msg) -> Sub msg

A type alias representing the port function required to receive the EventIn from the socket.

You could write this yourself, if you do, it needs to be named socketReceiver, although you may find it simpler to just add this port module to your src - it includes all the necessary port functions.

type alias PackageIn =
{ event : String
, payload : Value
}

A type alias representing the data received from the socket. You will not use this directly.