Skip to content

Commit

Permalink
Changed abondaning users garbage collection mechanism
Browse files Browse the repository at this point in the history
  • Loading branch information
syrio committed Sep 15, 2011
1 parent cbf9af3 commit 6a031b3
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 20 deletions.
2 changes: 0 additions & 2 deletions README.md
Expand Up @@ -61,8 +61,6 @@ It uses these events to keep an updated representation of the state of it's clie

Messages are being sent using SocketStream users Pub/Sub, even though there is no authentication involved with constant-stream. This is done by assigning (using the @session.setUserId function) each unique session (that is, a user using it's browser to connect to constant-stream) as the user id that match with that session, essentially mimicking a user login for this session. SocketStream users Pub/Sub allows the server to send messages to specific users and this comes handy when you have multiple constant-stream users that are connected to the same channels as the other and with private messaging.

Since we are now using SocketStream users feature, even though the server doesn't uses the built-in users-online mechanism to calculate who is online and who isn't offline, it does uses it to conclude which users have been traveling for too long and have timeout their connection (see the timeout configuration and the client side sections for more general details).

### External libs

Redis was mentioned briefly since pretty much baked-in into SocketStream. It is worth mentioning only because constant-stream wraps it by using a small helper class (see StreamStorage in the helpers module) around it to provide a simple and decoupled storage interface that is easily testable.
Expand Down
16 changes: 8 additions & 8 deletions config/app.coffee
Expand Up @@ -37,20 +37,20 @@ exports.config =


# for SocketStream v0.2.0 beta 2
users:
online:
keep_historic: true
#users:
# online:
# keep_historic: true
# for SocketStream v0.2.0 relase
users_online:
keep_historic: true
#users_online:
# keep_historic: true

# for expiration of lost sessions
offline_expire:
timeout: 24*60
interval: 999
interval: 990

irc:
server: 'irc.freenode.net' # example server
#server: "localhost" # work with local server liked ircdjs
#server: 'irc.freenode.net' # example server
server: "localhost" # work with local server liked ircdjs
name: "constant-stream"
real_name: "IRC streamer"
20 changes: 18 additions & 2 deletions node_modules/helpers.coffee

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

50 changes: 42 additions & 8 deletions test/spec/server/helpers-spec.coffee
Expand Up @@ -261,6 +261,17 @@ describe 'Server helpers', ->
expect(R.srem).toHaveBeenCalledWith('some:set', 'some_item')
expect(R.srem).toHaveBeenCalledWith('some:set', 'a_item')

describe 'Adding a single string key/value', ->
beforeEach ->
global.R =
set: sinon.spy()
afterEach ->
global.R = {}
it 'should add it to the underlying storage', ->
storage = new helpers.StreamStorage()
storage.store('some:key', 'some_value')
expect(R.set).toHaveBeenCalledWith('some:key', 'some_value')

describe 'Removing an entire key', ->
beforeEach ->
global.R =
Expand Down Expand Up @@ -303,6 +314,19 @@ describe 'Server helpers', ->
expect(members[1]).toEqual 'a_member'
expect(R.lrange).toHaveBeenCalledWith('some:list', 0, -1)

describe 'Getting the value from a given string key', ->
beforeEach ->
global.R =
type: sinon.stub().yields(0, 'string')
get: sinon.stub().yields(0, 'some_value')
afterEach ->
global.R = {}
it 'should callback true if it is', ->
storage = new helpers.StreamStorage()
# Vows.js style
storage.get 'some:key', (err, value) ->
expect(value).toEqual 'some_value'
expect(R.get).toHaveBeenCalledWith('some:key')

describe 'Checking if a given value is a member of a given set', ->
beforeEach ->
Expand Down Expand Up @@ -499,19 +523,25 @@ describe 'Server helpers', ->
expect(@manager.emit).toHaveBeenCalledWithExactly('reconnect', {id: 1})

describe 'handling a session disconnection', ->
it 'should store the session id in the offline sessions list', ->
it 'should store the session id in the offline sessions list and store the session disconnection time', ->
runs ->
storage = { sstore: sinon.stub(), list: sinon.spy(), get: sinon.stub().yields(0, ['some_channel', 'a_channel']) }
storage = { sstore: sinon.stub(), store: sinon.stub(), list: sinon.spy(), get: sinon.stub().yields(0, ['some_channel', 'a_channel']) }
disconnected_session = {id : 1}
clock = sinon.useFakeTimers(1234567890000)
manager = new helpers.SessionManager(storage)
manager.handleDisconnect(disconnected_session)
manager.handleDisconnect(disconnected_session)
expect(storage.sstore).toHaveBeenCalledWithExactly('offline:sessions', 1)
expect(storage.store).toHaveBeenCalledWithExactly('offline:1:at:1234567860', 1)
clock.restore()

describe 'handling a session reconnection', ->
beforeEach ->
global.SS = publish: user: sinon.spy()
@storage =
remove: sinon.spy(),
keys: (key, cb) ->
if key == 'offline:1:at:*'
return cb 0, ['offline:1:at:1234567890']
remove: sinon.spy()
get: (key, cb) ->
if key == 'offline:1:some_channel:messages'
return cb 0, [JSON.stringify({ text: 'some_message' })]
Expand Down Expand Up @@ -544,6 +574,11 @@ describe 'Server helpers', ->
runs ->
@manager.handleReconnect(@reconnected_session)
expect(@storage.remove).toHaveBeenCalledWith('offline:sessions', 1)
it 'should remove the session offline timestamp key indicating when it went offline', ->
runs ->
@manager.handleReconnect(@reconnected_session)
expect(@storage.remove).toHaveBeenCalledWith('offline:1:at:1234567890')



describe 'handling a session channel subscription', ->
Expand All @@ -564,10 +599,9 @@ describe 'Server helpers', ->

describe 'handling a session heartbeat', ->
beforeEach ->
global.SS = config : redis : key_prefix : 'ss'
@storage =
keys: (err, cb) ->
cb(0, ["#{SS.config.redis.key_prefix}:online:at:1234567456", "#{SS.config.redis.key_prefix}:online:at:1234567123"])
cb(0, ["offline:1:at:1234567456", "offline:2:at:1234567123"])
get: (err, cb) ->
cb(0, ['1', '2'])
remove: sinon.spy()
Expand All @@ -582,8 +616,8 @@ describe 'Server helpers', ->
it 'should emit a heartbeat event for the period', ->
expect(@emit_spy).toHaveBeenCalledWith('hearbeat', 1234567)
it 'should remove the SocketStream last login entry from storage', ->
expect(@storage.remove).toHaveBeenCalledWith("#{SS.config.redis.key_prefix}:online:at:1234567456")
expect(@storage.remove).toHaveBeenCalledWith("#{SS.config.redis.key_prefix}:online:at:1234567123")
expect(@storage.remove).toHaveBeenCalledWith("offline:1:at:1234567456")
expect(@storage.remove).toHaveBeenCalledWith("offline:2:at:1234567123")

describe 'handling a session tiemout', ->
it 'should remove all session structures from storage', ->
Expand Down

0 comments on commit 6a031b3

Please sign in to comment.