Skip to content

Commit

Permalink
Return a copy instead of mutating client presence state
Browse files Browse the repository at this point in the history
  • Loading branch information
chrismccord committed Jun 6, 2016
1 parent f7a0e58 commit dffe053
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 11 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ See these [`1.1.x` to `1.2.x` upgrade instructions](https://gist.github.com/chri
* JavaScript client enhancements
* Use return value of channel onMessage callback for specialized message transformations before dispatching to the channel

* JavaScript client backward incompatible changes
* `Presence.syncState` and `Presence.syncDiff` now return a copy of the state instead of mutating it

## 1.2.0-rc.1 (2016-05-25)

See these [`1.1.x` to `1.2.x` upgrade instructions](https://gist.github.com/chrismccord/29100e16d3990469c47f851e3142f766) to bring your existing apps up to speed.
Expand Down
17 changes: 10 additions & 7 deletions web/static/js/phoenix.js
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@
// they came online from:
//
// let state = {}
// Presence.syncState(state, stateFromServer)
// state = Presence.syncState(state, stateFromServer)
// let listBy = (id, {metas: [first, ...rest]}) => {
// first.count = rest.length + 1 // count of this user's presences
// first.id = id
Expand Down Expand Up @@ -157,12 +157,12 @@
// let presences = {} // client's initial empty presence state
// // receive initial presence data from server, sent after join
// myChannel.on("presences", state => {
// Presence.syncState(presences, state, onJoin, onLeave)
// presences = Presence.syncState(presences, state, onJoin, onLeave)
// displayUsers(Presence.list(presences))
// })
// // receive "presence_diff" from server, containing join/leave events
// myChannel.on("presence_diff", diff => {
// Presence.syncDiff(presences, diff, onJoin, onLeave)
// presences = Presence.syncDiff(presences, diff, onJoin, onLeave)
// this.setState({users: Presence.list(room.presences, listBy)})
// })
//
Expand Down Expand Up @@ -795,13 +795,14 @@ Ajax.states = {complete: 4}

export var Presence = {

syncState(state, newState, onJoin, onLeave){
syncState(currentState, newState, onJoin, onLeave){
let state = this.clone(currentState)
let joins = {}
let leaves = {}

this.map(state, (key, presence) => {
if(!newState[key]){
leaves[key] = this.clone(presence)
leaves[key] = presence
}
})
this.map(newState, (key, newPresence) => {
Expand All @@ -823,10 +824,11 @@ export var Presence = {
joins[key] = newPresence
}
})
this.syncDiff(state, {joins: joins, leaves: leaves}, onJoin, onLeave)
return this.syncDiff(state, {joins: joins, leaves: leaves}, onJoin, onLeave)
},

syncDiff(state, {joins, leaves}, onJoin, onLeave){
syncDiff(currentState, {joins, leaves}, onJoin, onLeave){
let state = this.clone(currentState)
if(!onJoin){ onJoin = function(){} }
if(!onLeave){ onLeave = function(){} }

Expand All @@ -850,6 +852,7 @@ export var Presence = {
delete state[key]
}
})
return state
},

list(presences, chooser){
Expand Down
21 changes: 17 additions & 4 deletions web/test/presence_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import assert from "assert"

import {Presence} from "../static/js/phoenix"

let clone = (obj) => { return JSON.parse(JSON.stringify(obj)) }

let fixtures = {
joins(){
return {u1: {metas: [{id: 1, phx_ref: "1.2"}]}}
Expand All @@ -22,7 +24,11 @@ describe("syncState", () => {
it("syncs empty state", () => {
let newState = {u1: {metas: [{id: 1, phx_ref: "1"}]}}
let state = {}
let stateBefore = clone(state)
Presence.syncState(state, newState)
assert.deepEqual(state, stateBefore)

state = Presence.syncState(state, newState)
assert.deepEqual(state, newState)
})

Expand All @@ -37,7 +43,11 @@ describe("syncState", () => {
let onLeave = (key, current, leftPres) => {
left[key] = {current: current, leftPres: leftPres}
}
let stateBefore = clone(state)
Presence.syncState(state, newState, onJoin, onLeave)
assert.deepEqual(state, stateBefore)

state = Presence.syncState(state, newState, onJoin, onLeave)
assert.deepEqual(state, newState)
assert.deepEqual(joined, {
u1: {current: null, newPres: {metas: [{id: 1, phx_ref: "1"}]}},
Expand All @@ -60,7 +70,7 @@ describe("syncState", () => {
let onLeave = (key, current, leftPres) => {
left[key] = {current: current, leftPres: leftPres}
}
Presence.syncState(state, newState, onJoin, onLeave)
state = Presence.syncState(state, newState, onJoin, onLeave)
assert.deepEqual(state, newState)
assert.deepEqual(joined, {
u3: {current: {metas: [{id: 3, phx_ref: "3"}]},
Expand All @@ -74,7 +84,10 @@ describe("syncDiff", () => {
it("syncs empty state", () => {
let joins = {u1: {metas: [{id: 1, phx_ref: "1"}]}}
let state = {}
Presence.syncDiff(state, {
Presence.syncDiff(state, {joins: joins, leaves: {}})
assert.deepEqual(state, {})

state = Presence.syncDiff(state, {
joins: joins,
leaves: {}
})
Expand All @@ -83,7 +96,7 @@ describe("syncDiff", () => {

it("removes presence when meta is empty and adds additional meta", () => {
let state = fixtures.state()
Presence.syncDiff(state, {joins: fixtures.joins(), leaves: fixtures.leaves()})
state = Presence.syncDiff(state, {joins: fixtures.joins(), leaves: fixtures.leaves()})

assert.deepEqual(state, {
u1: {metas: [{id: 1, phx_ref: "1"}, {id: 1, phx_ref: "1.2"}]},
Expand All @@ -95,7 +108,7 @@ describe("syncDiff", () => {
let state = {
u1: {metas: [{id: 1, phx_ref: "1"}, {id: 1, phx_ref: "1.2"}]}
}
Presence.syncDiff(state, {joins: {}, leaves: {u1: {metas: [{id: 1, phx_ref: "1"}]}}})
state = Presence.syncDiff(state, {joins: {}, leaves: {u1: {metas: [{id: 1, phx_ref: "1"}]}}})

assert.deepEqual(state, {
u1: {metas: [{id: 1, phx_ref: "1.2"}]},
Expand Down

0 comments on commit dffe053

Please sign in to comment.