Skip to content

Instantly share code, notes, and snippets.

@note89
Last active Jul 19, 2016
Embed
What would you like to do?
Elm websockets controller
module App.State exposing (..)
{-
We need the URL for the websocket. This will be the phoenix server url, then
the route for the socket, then "websocket" because that's the transport we're
communicating with.
-}
socketServer : String
socketServer =
"ws://localhost:4000/socket/websocket"
{-
initPhxSocket uses Phoenix.Socket.init on the socketServer, and we pipe it
through Phoenix.Socket.withDebug so we can get debug information out of it.
This will print every incoming Phoenix message to the console.
-}
initPhxSocket : Phoenix.Socket.Socket Msg
initPhxSocket =
Phoenix.Socket.init socketServer
subscriptions : Model -> Sub Msg
subscriptions model =
Phoenix.Socket.listen model.phxSocket PhoenixMsg
processPhx : Phx.Msg -> Model -> ( Model, Cmd Msg )
processPhx msg model =
case msg of
Phx.NoOp ->
model ! []
Phx.JoinChannel ( events, channel, component ) ->
let
payload =
JE.object [ ( "guardian_token", JE.string model.guardian_token ) ]
phxChannel =
Phoenix.Channel.init channel
|> Phoenix.Channel.withPayload payload
sendTo =
case component of
Phx.Chat ->
(Chat channel << CT.ReceiveMessage)
Phx.Notification ->
(Notification << NT.ReceiveNotification)
phxSocket =
List.foldl (\event socket -> Phoenix.Socket.on event channel sendTo socket) model.phxSocket events
( phxSocket', phxCmd ) =
phxSocket
|> Phoenix.Socket.join phxChannel
in
( { model | phxSocket = phxSocket' }, Cmd.map PhoenixMsg phxCmd )
Phx.LeaveChannel channel ->
let
( phxSocket, phxCmd ) =
Phoenix.Socket.leave channel model.phxSocket
in
{ model | phxSocket = phxSocket } ! [ Cmd.map PhoenixMsg phxCmd ]
Phx.SendMessage ( msgType, channel, payload ) ->
let
push' =
Phoenix.Push.init msgType channel
|> Phoenix.Push.withPayload payload
( phxSocket', phxCmd ) =
Phoenix.Socket.push push' model.phxSocket
in
{ model | phxSocket = phxSocket' } ! [ Cmd.map PhoenixMsg phxCmd ]
processChat : CT.OutMsg -> Model -> ( Model, Cmd Msg )
processChat msg model =
case msg of
CT.OnNoOp ->
model ! []
CT.OnClose channelId ->
let
( model1, fx1 ) =
update (RemoveChat channelId) model
( model2, fx2 ) =
processPhx (Phx.LeaveChannel channelId) model1
in
model2 ! [ fx1, fx2 ]
CT.ToPhx phxMsg ->
processPhx phxMsg model
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
NoOp ->
( model, Cmd.none )
Notification subMsg ->
let
( ( notification', cmdFromNotification ), outMsg ) =
NS.update subMsg model.notification model.user
model' =
{ model | notification = notification' }
( model'', cmdFromPhx ) =
processNotification outMsg model'
in
model''
! [ cmdFromPhx
, Cmd.map Notification cmdFromNotification
]
module Common.Phx exposing (..)
import Json.Encode as JE
type Msg
= NoOp
| JoinChannel ( List String, String, Component )
| SendMessage ( String, String, JE.Value )
| LeaveChannel String
type Component
= Chat
| Notification
module Notification.State exposing (..)
import Notification.Types exposing (..)
import App.Types as AT
import User.Types as User
import Phoenix.Socket
import Phoenix.Channel
import Phoenix.Push
import Json.Encode as JE
import Json.Decode as JD exposing ((:=))
import Ports
import Common.Phx as Phx
initialModel =
()
type alias Notification =
{ text : String
, id : String
}
notificationDecoder =
JD.object2 Notification
("text" := JD.string)
("id" := JD.string)
update : Msg -> Model -> User.Model -> ( ( Model, Cmd Msg ), OutMsg )
update msg model user =
case msg of
NoOp ->
( model ! [], OnNoOp )
OnStart ->
update JoinChannel model user
JoinChannel ->
let
msgs =
[ "new:event:notification", "new:group:notification" ]
channel =
"notifications:" ++ user.id
in
( model ! []
, ToPhx <| Phx.JoinChannel ( msgs, channel, Phx.Notification )
)
ReceiveNotification raw ->
let
_ =
Debug.log "raw" raw
in
case JD.decodeValue notificationDecoder raw of
Ok notification ->
( model ! [ Ports.toaster notification.text ]
, OnNoOp
)
Err error ->
let
_ =
Debug.log "error parsing notification" error
in
( model ! [], OnNoOp )
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment