faye_tracking 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e65dc0c10240816a421e137aa34bbb0d1a31bf8b
4
- data.tar.gz: ff775198df38629943868fd204a592e77cac9e46
3
+ metadata.gz: 7fcbc653ce1ea17f6709545fd5ac543cee22bfae
4
+ data.tar.gz: 4ea9bc79243cb02c01cff7a846c65c4165aa0447
5
5
  SHA512:
6
- metadata.gz: c8c584abc579d57ac7d091462aada28192503edca65eb7371bccd9e130a176a586d86be5ed4904c7949495cf188da93d73aa6fd9f91e9c99dfb64d2e49243268
7
- data.tar.gz: 07d9b9f1f3e5adbdc827086cefbfe46a7e344b3deba479a2c2aa9b6eeefead78251c7dd911c02635054601acc98e822be3922a963c003e911dc73caf15985341
6
+ metadata.gz: 468a983f7595f5d4965d180bb8bfe52145409e0373c1d79c53c5c6acc173cb576022246527696f91f1ab72d798dd789a6ae084a511199b12219c95b145da545a
7
+ data.tar.gz: 41c937b43b00d5f16ed23bd6a7af702ec9b8457567848836e9e8b57ee0c0e8ef607f5772f847c24db0c0c0989107b81f11b6a2b23445eea63193394138d492d6
data/README.md CHANGED
@@ -3,6 +3,8 @@
3
3
  A Faye extension for tracking user subscriptions, i.e. can be used for
4
4
  checking if a user is online.
5
5
 
6
+ BUT: http://faye.jcoglan.com/ruby/monitoring.html
7
+
6
8
  ## Prerequisites
7
9
 
8
10
  * Faye
@@ -26,16 +28,38 @@ Or install it yourself as:
26
28
 
27
29
  ## Usage
28
30
 
31
+ Set it up:
32
+
29
33
  ```ruby
30
34
  FayeTracking.configure do |config|
31
35
  config.redis = Redis.new
32
36
  end
33
37
 
38
+ client.add_extension(FayeTracking.faye_extension)
39
+
34
40
  FayeTracking.all_users_in_channel('/chat/1')
35
41
  FayeTracking.user_in_any_channel?('/user_1')
36
42
  FayeTracking.user_in_channel?('/user_1', '/chat/1')
43
+ ```
37
44
 
38
- client.add_extension(FayeTracking.faye_extension)
45
+ Client side: a PrivatePub example using a fork here: https://github.com/he9lin/private_pub, which makes it possible to add client side Faye extensions to PrivatePub javascript.
46
+
47
+ ```coffeescript
48
+ FayeTrackingExtension =
49
+ outgoing: (message, callback) ->
50
+ if message.channel == "/meta/subscribe"
51
+ # Attach the user id to subscription messages
52
+ subscription = PrivatePub.subscriptions[message.subscription]
53
+ message.ext ?= {}
54
+ message.ext.faye_tracking_client_id = subscription.user_id
55
+ callback(message)
56
+
57
+ PrivatePub.extensions = [PrivatePubClientIdExtension]
58
+
59
+ # To subscribe to a channel
60
+ subscription["user_id"] = user_id
61
+ PrivatePub.sign(subscription)
62
+ PrivatePub.subscribe(subscription.channel, callback)
39
63
  ```
40
64
 
41
65
  ## Contributing
@@ -1,6 +1,6 @@
1
1
  module FayeTracking
2
2
  class FayeExtension
3
- MONITORED_CHANNELS = [ '/meta/subscribe', '/meta/disconnect' ]
3
+ MONITORED_CHANNELS = [ '/meta/subscribe', '/meta/unsubscribe', '/meta/disconnect' ]
4
4
 
5
5
  def initialize(tracker)
6
6
  @tracker = tracker
@@ -9,15 +9,24 @@ module FayeTracking
9
9
  def incoming(message, callback)
10
10
  return callback.call(message) unless MONITORED_CHANNELS.include? message['channel']
11
11
 
12
+ FayeTracking.logger.debug "received incoming message: #{message}"
13
+
12
14
  unless message['error']
13
15
  subs_channel = message['subscription']
14
- app_client_id = message['ext']['faye_tracking_client_id']
16
+ client_id = message['clientId']
15
17
 
16
18
  case message['channel']
17
19
  when '/meta/subscribe'
18
- @tracker.add(subs_channel, app_client_id)
20
+ ext = message['ext']
21
+ if app_client_id = ext['faye_tracking_client_id']
22
+ @tracker.add(subs_channel, client_id, app_client_id)
23
+ else
24
+ message['error'] = "missing ext['faye_tracking_client_id']"
25
+ end
26
+ when '/meta/unsubscribe'
27
+ @tracker.remove(subs_channel, client_id)
19
28
  when '/meta/disconnect'
20
- @tracker.remove(subs_channel, app_client_id)
29
+ @tracker.remove_user_from_all_channels(client_id)
21
30
  end
22
31
  end
23
32
 
@@ -1,5 +1,5 @@
1
1
  module FayeTracking
2
- class AbstractStore
2
+ class AbstractKeyList
3
3
  def add(key, value)
4
4
  raise NotImplementedError
5
5
  end
@@ -19,5 +19,9 @@ module FayeTracking
19
19
  def empty?(key)
20
20
  raise NotImplementedError
21
21
  end
22
+
23
+ def remove_all(key)
24
+ raise NotImplementedError
25
+ end
22
26
  end
23
27
  end
@@ -0,0 +1,15 @@
1
+ module FayeTracking
2
+ class AbstractMapping
3
+ def set(key, value)
4
+ raise NotImplementedError
5
+ end
6
+
7
+ def get(key)
8
+ raise NotImplementedError
9
+ end
10
+
11
+ def delete(key)
12
+ raise NotImplementedError
13
+ end
14
+ end
15
+ end
@@ -1,5 +1,5 @@
1
1
  module FayeTracking
2
- class RedisStore < AbstractStore
2
+ class RedisKeyList < AbstractKeyList
3
3
  def initialize(redis)
4
4
  @redis = redis
5
5
  end
@@ -23,5 +23,9 @@ module FayeTracking
23
23
  def empty?(key)
24
24
  @redis.smembers(key).empty?
25
25
  end
26
+
27
+ def remove_all(key)
28
+ @redis.del(key)
29
+ end
26
30
  end
27
31
  end
@@ -0,0 +1,20 @@
1
+ module FayeTracking
2
+ class RedisMapping < AbstractMapping
3
+ def initialize(redis, name=FayeTracking::MAPPING_STORE_NAME)
4
+ @name = name
5
+ @redis = redis
6
+ end
7
+
8
+ def set(key, value)
9
+ @redis.hset @name, key, value
10
+ end
11
+
12
+ def get(key)
13
+ @redis.hget @name, key
14
+ end
15
+
16
+ def delete(key)
17
+ @redis.del @name, key
18
+ end
19
+ end
20
+ end
@@ -1,33 +1,46 @@
1
1
  module FayeTracking
2
2
  class Tracker
3
- def initialize(store)
4
- @store = store
3
+ def initialize(key_list, mapping)
4
+ @key_list = key_list
5
+ @mapping = mapping
5
6
  end
6
7
 
7
- def add(channel, user)
8
- @store.add(channel, user)
9
- @store.add(user, channel)
8
+ def add(channel, client_id, user)
9
+ @mapping.set(client_id, user)
10
+ @key_list.add(channel, user)
11
+ @key_list.add(user, channel)
10
12
  end
11
13
 
12
- def remove(channel, user)
13
- @store.remove(channel, user)
14
- @store.remove(user, channel)
14
+ def remove(channel, client_id)
15
+ if user = @mapping.get(client_id)
16
+ @key_list.remove(channel, user)
17
+ @key_list.remove(user, channel)
18
+ end
19
+ end
20
+
21
+ def remove_user_from_all_channels(client_id)
22
+ if user = @mapping.get(client_id)
23
+ channels_for_user(user).each do |channel|
24
+ @key_list.remove(channel, user)
25
+ end
26
+ @key_list.remove_all(user)
27
+ end
15
28
  end
16
29
 
17
30
  def channels_for_user(user)
18
- @store.members(user)
31
+ @key_list.members(user)
19
32
  end
20
33
 
21
34
  def users_in_channel(channel)
22
- @store.members(channel)
35
+ @key_list.members(channel)
23
36
  end
24
37
 
25
38
  def user_in_channel?(user, channel)
26
- @store.member?(user, channel)
39
+ @key_list.member?(user, channel)
27
40
  end
28
41
 
29
42
  def channel_has_user?(channel, user)
30
- @store.member?(channel, user)
43
+ @key_list.member?(channel, user)
31
44
  end
32
45
  end
33
46
  end
@@ -1,3 +1,3 @@
1
1
  module FayeTracking
2
- VERSION = "0.1.1"
2
+ VERSION = "0.2.0"
3
3
  end
data/lib/faye_tracking.rb CHANGED
@@ -1,16 +1,20 @@
1
1
  require 'redis'
2
2
  require 'redis-namespace'
3
+ require 'logger'
3
4
  require "faye_tracking/version"
4
5
 
5
6
  module FayeTracking
7
+ MAPPING_STORE_NAME = 'client_id_to_user'.freeze
8
+
6
9
  class << self
7
- attr_accessor :redis
10
+ attr_accessor :redis, :logger
8
11
 
9
12
  def configure(&block)
10
13
  block.call(self)
11
14
  end
12
15
 
13
16
  def reset_store
17
+ raise 'redis is not set' unless redis
14
18
  redis.keys('*').each {|k| redis.del k}
15
19
  end
16
20
 
@@ -30,16 +34,26 @@ module FayeTracking
30
34
  tracker.users_in_channel(channel)
31
35
  end
32
36
 
37
+ def logger
38
+ @logger ||= Logger.new(STDOUT)
39
+ end
40
+
33
41
  private
34
42
 
35
43
  def tracker
36
44
  raise 'redis is not set' unless redis
37
- @_tracker ||= Tracker.new(RedisStore.new(redis))
45
+ @_tracker ||= begin
46
+ key_list_store = RedisKeyList.new(redis)
47
+ mapping_store = RedisMapping.new(redis)
48
+ Tracker.new(key_list_store, mapping_store)
49
+ end
38
50
  end
39
51
  end
40
52
  end
41
53
 
42
54
  require "faye_tracking/faye_extension"
43
- require "faye_tracking/abstract_store"
44
- require "faye_tracking/redis_store"
55
+ require "faye_tracking/store/abstract_key_list"
56
+ require "faye_tracking/store/abstract_mapping"
57
+ require "faye_tracking/store/adapter/redis_key_list"
58
+ require "faye_tracking/store/adapter/redis_mapping"
45
59
  require "faye_tracking/tracker"
@@ -5,24 +5,32 @@ describe FayeTracking do
5
5
  FayeTracking.reset_store
6
6
  end
7
7
 
8
- def faye_run(meta_action, channel, user)
9
- message = {"channel" => meta_action, "ext" => {}}
10
- message["subscription"] = channel
11
- message["ext"]["faye_tracking_client_id"] = user
8
+ let(:client_id) { 'rpy799jnfeq' }
9
+ let(:another_client_id) { '651w533ncba' }
10
+
11
+ def faye_run(meta_action, subscription, client_id, user)
12
+ message = { "channel" => meta_action, "clientId" => client_id }
13
+ message["subscription"] = subscription if subscription
14
+ message["ext"] = { "faye_tracking_client_id" => user } if user
15
+
12
16
  FayeTracking.faye_extension.incoming(message, lambda { |m| m })
13
17
  end
14
18
 
15
- def faye_subscribe(channel, user)
16
- faye_run('/meta/subscribe', channel, user)
19
+ def faye_subscribe(channel, client_id, user)
20
+ faye_run('/meta/subscribe', channel, client_id, user)
21
+ end
22
+
23
+ def faye_unsubscribe(channel, client_id)
24
+ faye_run('/meta/unsubscribe', channel, client_id, nil)
17
25
  end
18
26
 
19
- def faye_disconnect(channel, user)
20
- faye_run('/meta/disconnect', channel, user)
27
+ def faye_disconnect(client_id)
28
+ faye_run('/meta/disconnect', nil, client_id, nil)
21
29
  end
22
30
 
23
31
  context 'subscribing to a channel' do
24
32
  before do
25
- faye_subscribe 'room', 'user_1'
33
+ faye_subscribe 'room', client_id, 'user_1'
26
34
  end
27
35
 
28
36
  it 'adds user to the subscription channel' do
@@ -32,29 +40,43 @@ describe FayeTracking do
32
40
  end
33
41
 
34
42
  it 'returns all users in a channel' do
35
- faye_subscribe 'room', 'user_2'
43
+ faye_subscribe 'room', client_id, 'user_2'
36
44
  expect(described_class.all_users_in_channel('room')).to match_array(['user_1', 'user_2'])
37
45
  end
38
46
  end
39
47
 
40
- context 'disconnecting to a channel' do
48
+ context 'unsubscribing a channel' do
41
49
  before do
42
- faye_subscribe 'room', 'user_1'
50
+ faye_subscribe 'room', client_id, 'user_1'
43
51
  end
44
52
 
45
53
  it 'removes a user from a subscription channel' do
46
- faye_disconnect 'room', 'user_1'
54
+ faye_unsubscribe 'room', client_id
47
55
  expect(described_class.user_in_any_channel?('user_1')).to be_falsey
48
56
  expect(described_class.all_users_in_channel('rooom')).to eq([])
49
57
 
50
- faye_subscribe 'room', 'user_2'
58
+ faye_subscribe 'room', client_id, 'user_2'
51
59
  expect(described_class.user_in_any_channel?('user_2')).to be_truthy
52
60
  end
53
61
 
54
62
  it 'does not raise error when removing a non-existing user' do
55
63
  expect {
56
- faye_disconnect 'room', 'user_2'
64
+ faye_unsubscribe 'room', 'user_2'
57
65
  }.to_not raise_error
58
66
  end
59
67
  end
68
+
69
+ context 'disconnecting' do
70
+ before do
71
+ faye_subscribe 'room1', client_id, 'user_1'
72
+ faye_subscribe 'room2', client_id, 'user_1'
73
+ faye_subscribe 'room1', another_client_id, 'user_2'
74
+ end
75
+
76
+ it 'removes the user from all channels' do
77
+ faye_disconnect(client_id)
78
+ expect(described_class.user_in_any_channel?('user_1')).to be_falsey
79
+ expect(described_class.all_users_in_channel('room1')).to eq(['user_2'])
80
+ end
81
+ end
60
82
  end
data/spec/spec_helper.rb CHANGED
@@ -4,6 +4,7 @@ require 'faye_tracking'
4
4
 
5
5
  FayeTracking.configure do |config|
6
6
  config.redis = Redis::Namespace.new(:faye_tracking_test, redis: Redis.new)
7
+ config.logger.level = Logger::INFO
7
8
  end
8
9
 
9
10
  RSpec.configure do |config|
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: faye_tracking
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lin He
@@ -95,9 +95,11 @@ files:
95
95
  - Rakefile
96
96
  - faye_tracking.gemspec
97
97
  - lib/faye_tracking.rb
98
- - lib/faye_tracking/abstract_store.rb
99
98
  - lib/faye_tracking/faye_extension.rb
100
- - lib/faye_tracking/redis_store.rb
99
+ - lib/faye_tracking/store/abstract_key_list.rb
100
+ - lib/faye_tracking/store/abstract_mapping.rb
101
+ - lib/faye_tracking/store/adapter/redis_key_list.rb
102
+ - lib/faye_tracking/store/adapter/redis_mapping.rb
101
103
  - lib/faye_tracking/tracker.rb
102
104
  - lib/faye_tracking/version.rb
103
105
  - spec/faye_tracking_spec.rb