Handle presence events in Elm

Pass state and diff events to elm, where the state can be managed
accordingly. Because vote events are used to update player state, we
don't want to blindly overwrite it by passing a separately synced
presence list through, as it will lack vote data.

Fixes #1
This commit is contained in:
Correl Roush 2020-05-20 21:24:01 -04:00
parent 4e8ac6f8d2
commit e5777f6f7a
3 changed files with 74 additions and 26 deletions

View file

@ -38,17 +38,8 @@ app.ports.joinRoom.subscribe(options => {
let channel = socket.channel("room:" + options.room, {}) let channel = socket.channel("room:" + options.room, {})
// Presence events // Presence events
let presences = {} channel.on("presence_state", app.ports.gotPresenceState.send)
channel.on("presence_state", state => { channel.on("presence_diff", app.ports.gotPresenceDiff.send)
console.log("presence state", state)
presences = Presence.syncState(presences, state)
app.ports.gotPresence.send(presences)
})
channel.on("presence_diff", diff => {
console.log("presence diff", diff)
presences = Presence.syncDiff(presences, diff)
app.ports.gotPresence.send(presences)
})
// Incoming room events // Incoming room events
channel.on("vote", app.ports.gotVote.send) channel.on("vote", app.ports.gotVote.send)

View file

@ -1,5 +1,6 @@
port module PlanningPokerAPI exposing port module PlanningPokerAPI exposing
( gotPresence ( gotPresenceDiff
, gotPresenceState
, gotReset , gotReset
, gotReveal , gotReveal
, gotVote , gotVote
@ -73,7 +74,10 @@ encodeAction action =
wrap "reveal" (Encode.object []) wrap "reveal" (Encode.object [])
port gotPresence : (Decode.Value -> msg) -> Sub msg port gotPresenceState : (Decode.Value -> msg) -> Sub msg
port gotPresenceDiff : (Decode.Value -> msg) -> Sub msg
port gotVote : (Decode.Value -> msg) -> Sub msg port gotVote : (Decode.Value -> msg) -> Sub msg

View file

@ -41,12 +41,25 @@ type Msg
| Reveal | Reveal
| PlayerNameChanged String | PlayerNameChanged String
| JoinRoom | JoinRoom
| GotPresence Decode.Value | GotPresence Presence
| GotPresenceDiff Decode.Value
| GotVote Decode.Value | GotVote Decode.Value
| GotReveal | GotReveal
| GotReset | GotReset
type Presence
= PresenceState (Dict String Player)
| PresenceDiff (Diff (Dict String Player))
| PresenceError Decode.Error
type alias Diff a =
{ joins : a
, leaves : a
}
type alias Room = type alias Room =
{ id : String { id : String
, name : String , name : String
@ -138,17 +151,30 @@ update key msg model =
, API.newProfile { playerName = model.playerName } , API.newProfile { playerName = model.playerName }
) )
GotPresence value -> GotPresence (PresenceState players) ->
case Decode.decodeValue playersDecoder value of let
Ok players -> newRoom =
let { room | players = players }
newRoom = in
{ room | players = players } ( { model | room = newRoom }, Cmd.none )
in
( { model | room = newRoom }, Cmd.none )
Err _ -> GotPresence (PresenceDiff { joins, leaves }) ->
( model, Cmd.none ) let
newPlayers =
room.players
|> Dict.filter (\id _ -> not (Dict.member id leaves))
|> Dict.union joins
newRoom =
{ room | players = newPlayers }
in
( { model | room = newRoom }, Cmd.none )
GotPresence _ ->
( model, Cmd.none )
GotPresenceDiff _ ->
( model, Cmd.none )
GotVote value -> GotVote value ->
case Decode.decodeValue voteDecoder value of case Decode.decodeValue voteDecoder value of
@ -194,7 +220,6 @@ view dimensions model =
let let
device = device =
classifyDevice dimensions classifyDevice dimensions
|> Debug.log "device"
playerName = playerName =
Dict.get model.player model.room.players Dict.get model.player model.room.players
@ -439,13 +464,41 @@ joinForm room playerName =
subscriptions : Sub Msg subscriptions : Sub Msg
subscriptions = subscriptions =
Sub.batch Sub.batch
[ API.gotPresence GotPresence [ API.gotPresenceState (decodePresenceState >> GotPresence)
, API.gotPresenceDiff (decodePresenceDiff >> GotPresence)
, API.gotReset (\_ -> GotReset) , API.gotReset (\_ -> GotReset)
, API.gotReveal (\_ -> GotReveal) , API.gotReveal (\_ -> GotReveal)
, API.gotVote GotVote , API.gotVote GotVote
] ]
decodePresenceState : Decode.Value -> Presence
decodePresenceState value =
case Decode.decodeValue playersDecoder value of
Ok players ->
PresenceState players
Err error ->
PresenceError error
decodePresenceDiff : Decode.Value -> Presence
decodePresenceDiff value =
let
diffDecoder =
Decode.map PresenceDiff <|
Decode.map2 Diff
(Decode.field "joins" playersDecoder)
(Decode.field "leaves" playersDecoder)
in
case Decode.decodeValue diffDecoder value of
Ok diff ->
diff
Err error ->
PresenceError error
playersDecoder : Decode.Decoder (Dict String Player) playersDecoder : Decode.Decoder (Dict String Player)
playersDecoder = playersDecoder =
let let