faye_tracking 0.2.1 → 0.2.2

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: 2b5bc32dcffabad6cf234874363c19f599f77a77
4
- data.tar.gz: d500ca536492f5d71582271df6a5ebf132ea9286
3
+ metadata.gz: 59510a6d0b8840e8d1a023e7688cce9e7dcba4b2
4
+ data.tar.gz: a2eccf51d9d9ae29d31154ac8debffba9368cdc0
5
5
  SHA512:
6
- metadata.gz: ebb45db8cc27a4d6be278fba007a62bfa8d40379b43373d67a5bdeb0af2995b4e173008d4579e7d3bc9b85f765145bb00b758b3be61c6ee17a9a7546e95f8417
7
- data.tar.gz: c87e4dad1e31060b9199a840210d5faef242c9381f16168908c65aae1bf6cf22712155a149aba1fa4c775bdaf9ddce462a51fe3eb8b6c8e9808456baf5cd6181
6
+ metadata.gz: 98eceda9db22c158a7d46ce1b8998a68b6462304af15ff2a6d61535fee17993666d475d32f16446d97d45680a831c7222cc6023b59556df886addd34a77ffbe3
7
+ data.tar.gz: be8768b99523474637524d1e24fff8ad4c3e9dd2c05e9dfdf650715d6910db308fe78aa19687b3da910f7ece8055c34194718441eb68f80a5ad2457e3fddedc5
data/README.md CHANGED
@@ -37,7 +37,7 @@ end
37
37
 
38
38
  client.add_extension(FayeTracking.faye_extension)
39
39
 
40
- FayeTracking.all_users_in_channel('/chat/1')
40
+ FayeTracking.users_in_channel('/chat/1')
41
41
  FayeTracking.user_in_any_channel?('/user_1')
42
42
  FayeTracking.user_in_channel?('/user_1', '/chat/1')
43
43
  ```
@@ -54,7 +54,7 @@ FayeTrackingExtension =
54
54
  message.ext.faye_tracking_client_id = subscription.user_id
55
55
  callback(message)
56
56
 
57
- PrivatePub.extensions = [PrivatePubClientIdExtension]
57
+ PrivatePub.extensions = [FayeTrackingExtension]
58
58
 
59
59
  # To subscribe to a channel
60
60
  subscription["user_id"] = user_id
@@ -62,6 +62,12 @@ PrivatePub.sign(subscription)
62
62
  PrivatePub.subscribe(subscription.channel, callback)
63
63
  ```
64
64
 
65
+ ## TODO
66
+
67
+ * <del>Allow one application user to have many Faye `clientId` mappings.</del>
68
+ * Rely on events (instead of extensions) to handle user disconnecting event
69
+ because it's more reliable. (see http://faye.jcoglan.com/ruby/monitoring.html)
70
+
65
71
  ## Contributing
66
72
 
67
73
  1. Fork it ( https://github.com/he9lin/faye_tracking/fork )
data/lib/faye_tracking.rb CHANGED
@@ -4,24 +4,14 @@ require 'logger'
4
4
  require "faye_tracking/version"
5
5
 
6
6
  module FayeTracking
7
- MAPPING_STORE_NAME = 'client_id_to_user'.freeze
8
-
9
7
  class << self
10
- attr_accessor :redis, :logger
8
+ attr_accessor :logger
9
+ attr_writer :redis
11
10
 
12
11
  def configure(&block)
13
12
  block.call(self)
14
13
  end
15
14
 
16
- def reset_store
17
- raise 'redis is not set' unless redis
18
- redis.keys('*').each {|k| redis.del k}
19
- end
20
-
21
- def faye_extension
22
- @_faye_extension ||= FayeExtension.new(tracker)
23
- end
24
-
25
15
  def user_in_any_channel?(user)
26
16
  !tracker.channels_for_user(user).empty?
27
17
  end
@@ -30,30 +20,34 @@ module FayeTracking
30
20
  tracker.user_in_channel?(user, channel)
31
21
  end
32
22
 
33
- def all_users_in_channel(channel)
23
+ def users_in_channel(channel)
34
24
  tracker.users_in_channel(channel)
35
25
  end
36
26
 
27
+ def reset_store
28
+ redis.keys('*').each {|k| redis.del k}
29
+ end
30
+
31
+ def faye_extension
32
+ @_faye_extension ||= FayeExtension.new(tracker)
33
+ end
34
+
37
35
  def logger
38
36
  @logger ||= Logger.new(STDOUT)
39
37
  end
40
38
 
41
- private
39
+ def redis
40
+ @redis || raise('redis is not set')
41
+ end
42
42
 
43
43
  def tracker
44
- raise 'redis is not set' unless 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
44
+ @_tracker = Tracker.new(redis)
50
45
  end
51
46
  end
52
47
  end
53
48
 
54
49
  require "faye_tracking/faye_extension"
50
+ require "faye_tracking/tracker"
55
51
  require "faye_tracking/store/abstract_key_list"
56
- require "faye_tracking/store/abstract_mapping"
57
52
  require "faye_tracking/store/adapter/redis_key_list"
58
- require "faye_tracking/store/adapter/redis_mapping"
59
- require "faye_tracking/tracker"
53
+ require "faye_tracking/store/adapter/namespaced_key_list"
@@ -21,12 +21,14 @@ module FayeTracking
21
21
  if app_client_id = ext['faye_tracking_client_id']
22
22
  @tracker.add(subs_channel, client_id, app_client_id)
23
23
  else
24
- message['error'] = "missing ext['faye_tracking_client_id']"
24
+ error_message = "missing ext['faye_tracking_client_id']"
25
+ FayeTracking.logger.debug "error with message: #{error_message}"
26
+ message['error'] = error_message
25
27
  end
26
28
  when '/meta/unsubscribe'
27
29
  @tracker.remove(subs_channel, client_id)
28
30
  when '/meta/disconnect'
29
- @tracker.remove_user_from_all_channels(client_id)
31
+ @tracker.remove_all(client_id)
30
32
  end
31
33
  end
32
34
 
@@ -0,0 +1,40 @@
1
+ module FayeTracking
2
+ class NamespacedKeyList < AbstractKeyList
3
+ def initialize(ns, key_list)
4
+ raise ArgumentError, 'namespace param cannot be blank' if ns.nil? || ns.empty?
5
+
6
+ @ns = ns
7
+ @key_list = key_list
8
+ end
9
+
10
+ def add(key, value)
11
+ @key_list.add build_key(key), value
12
+ end
13
+
14
+ def remove(key, value)
15
+ @key_list.remove build_key(key), value
16
+ end
17
+
18
+ def member?(key, value)
19
+ @key_list.member? build_key(key), value
20
+ end
21
+
22
+ def members(key)
23
+ @key_list.members build_key(key)
24
+ end
25
+
26
+ def empty?(key)
27
+ @key_list.empty? build_key(key)
28
+ end
29
+
30
+ def remove_all(key)
31
+ @key_list.remove_all build_key(key)
32
+ end
33
+
34
+ private
35
+
36
+ def build_key(key)
37
+ [@ns, key].join(':')
38
+ end
39
+ end
40
+ end
@@ -1,48 +1,71 @@
1
1
  module FayeTracking
2
2
  class Tracker
3
- def initialize(key_list, mapping)
4
- @key_list = key_list
5
- @mapping = mapping
3
+ def initialize(redis)
4
+ @channel_to_client_ids = namespaced_key_list('channel_to_client_ids', redis)
5
+ @client_id_to_channels = namespaced_key_list('client_id_to_channels', redis)
6
+ @user_to_client_ids = namespaced_key_list('user_to_client_ids', redis)
7
+ @client_id_to_users = namespaced_key_list('client_id_to_users', redis)
6
8
  end
7
9
 
8
10
  def add(channel, client_id, user)
9
- @mapping.set(client_id, user)
10
- @key_list.add(channel, user)
11
- @key_list.add(user, channel)
11
+ @channel_to_client_ids.add(channel, client_id)
12
+ @client_id_to_channels.add(client_id, channel)
13
+ @user_to_client_ids.add(user, client_id)
14
+ @client_id_to_users.add(client_id, user)
12
15
  end
13
16
 
14
17
  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
+ @channel_to_client_ids.remove(channel, client_id)
19
+ @client_id_to_channels.remove(client_id, channel)
20
+ @client_id_to_users.members(client_id).each do |user|
21
+ @user_to_client_ids.remove(user, client_id)
18
22
  end
19
- @mapping.delete(client_id)
23
+ @client_id_to_users.remove_all(client_id)
20
24
  end
21
25
 
22
- def remove_user_from_all_channels(client_id)
23
- if user = @mapping.get(client_id)
24
- channels_for_user(user).each do |channel|
25
- @key_list.remove(channel, user)
26
- end
27
- @key_list.remove_all(user)
26
+ def remove_all(client_id)
27
+ @client_id_to_channels.members(client_id).each do |channel|
28
+ @channel_to_client_ids.remove(channel, client_id)
28
29
  end
29
- @mapping.delete(client_id)
30
+ @client_id_to_users.members(client_id).each do |user|
31
+ @user_to_client_ids.remove(user, client_id)
32
+ end
33
+ @client_id_to_users.remove_all(client_id)
34
+ @client_id_to_channels.remove_all(client_id)
30
35
  end
31
36
 
32
37
  def channels_for_user(user)
33
- @key_list.members(user)
38
+ client_ids = @user_to_client_ids.members(user)
39
+ client_ids.inject([]) do |acc, client_id|
40
+ acc += @client_id_to_channels.members(client_id)
41
+ end.uniq
34
42
  end
35
43
 
36
44
  def users_in_channel(channel)
37
- @key_list.members(channel)
45
+ client_ids = @channel_to_client_ids.members(channel)
46
+ client_ids.inject([]) do |acc, client_id|
47
+ acc += @client_id_to_users.members(client_id)
48
+ end.uniq
38
49
  end
39
50
 
40
51
  def user_in_channel?(user, channel)
41
- @key_list.member?(user, channel)
52
+ client_ids = @user_to_client_ids.members(user)
53
+ client_ids.any? do |client_id|
54
+ @channel_to_client_ids.member? channel, client_id
55
+ end
42
56
  end
43
57
 
44
58
  def channel_has_user?(channel, user)
45
- @key_list.member?(channel, user)
59
+ client_ids = @channel_to_client_ids.members(channel)
60
+ client_ids.any? do |client_id|
61
+ @user_to_client_ids.member? user, client_id
62
+ end
63
+ end
64
+
65
+ private
66
+
67
+ def namespaced_key_list(name, redis)
68
+ NamespacedKeyList.new(name, RedisKeyList.new(redis))
46
69
  end
47
70
  end
48
71
  end
@@ -1,3 +1,3 @@
1
1
  module FayeTracking
2
- VERSION = "0.2.1"
2
+ VERSION = "0.2.2"
3
3
  end
@@ -28,20 +28,22 @@ describe FayeTracking do
28
28
  faye_run('/meta/disconnect', nil, client_id, nil)
29
29
  end
30
30
 
31
- context 'subscribing to a channel' do
32
- before do
33
- faye_subscribe 'room', client_id, 'user_1'
34
- end
35
-
36
- it 'adds user to the subscription channel' do
37
- expect(described_class.user_in_any_channel?('user_1')).to be_truthy
38
- expect(described_class.user_in_channel?('user_1', 'room')).to be_truthy
39
- expect(described_class.user_in_channel?('user_2', 'room')).to be_falsey
40
- end
41
-
42
- it 'returns all users in a channel' do
43
- faye_subscribe 'room', client_id, 'user_2'
44
- expect(described_class.all_users_in_channel('room')).to match_array(['user_1', 'user_2'])
31
+ describe 'subscribing to a channel' do
32
+ describe 'multiple users' do
33
+ before do
34
+ faye_subscribe 'room', client_id, 'user_1'
35
+ end
36
+
37
+ it 'adds user to the subscription channel' do
38
+ expect(described_class.user_in_any_channel?('user_1')).to be_truthy
39
+ expect(described_class.user_in_channel?('user_1', 'room')).to be_truthy
40
+ expect(described_class.user_in_channel?('user_2', 'room')).to be_falsey
41
+ end
42
+
43
+ it 'returns all users in a channel' do
44
+ faye_subscribe 'room', client_id, 'user_2'
45
+ expect(described_class.users_in_channel('room')).to match_array(['user_1', 'user_2'])
46
+ end
45
47
  end
46
48
  end
47
49
 
@@ -53,7 +55,7 @@ describe FayeTracking do
53
55
  it 'removes a user from a subscription channel' do
54
56
  faye_unsubscribe 'room', client_id
55
57
  expect(described_class.user_in_any_channel?('user_1')).to be_falsey
56
- expect(described_class.all_users_in_channel('rooom')).to eq([])
58
+ expect(described_class.users_in_channel('rooom')).to eq([])
57
59
 
58
60
  faye_subscribe 'room', client_id, 'user_2'
59
61
  expect(described_class.user_in_any_channel?('user_2')).to be_truthy
@@ -66,6 +68,23 @@ describe FayeTracking do
66
68
  end
67
69
  end
68
70
 
71
+ describe 'subscribing/unsubscribing same users with different clientIds' do
72
+ before do
73
+ faye_subscribe 'room', client_id, 'user_1'
74
+ faye_subscribe 'room', another_client_id, 'user_1'
75
+ end
76
+
77
+ it 'user able to have multiple client ids' do
78
+ expect(described_class.user_in_channel?('user_1', 'room')).to be_truthy
79
+
80
+ faye_unsubscribe 'room', client_id
81
+ expect(described_class.user_in_channel?('user_1', 'room')).to be_truthy
82
+
83
+ faye_unsubscribe 'room', another_client_id
84
+ expect(described_class.user_in_channel?('user_1', 'room')).to be_falsey
85
+ end
86
+ end
87
+
69
88
  context 'disconnecting' do
70
89
  before do
71
90
  faye_subscribe 'room1', client_id, 'user_1'
@@ -76,7 +95,7 @@ describe FayeTracking do
76
95
  it 'removes the user from all channels' do
77
96
  faye_disconnect(client_id)
78
97
  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'])
98
+ expect(described_class.users_in_channel('room1')).to eq(['user_2'])
80
99
  end
81
100
  end
82
101
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: faye_tracking
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lin He
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-06-30 00:00:00.000000000 Z
11
+ date: 2015-07-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: redis
@@ -97,9 +97,8 @@ files:
97
97
  - lib/faye_tracking.rb
98
98
  - lib/faye_tracking/faye_extension.rb
99
99
  - lib/faye_tracking/store/abstract_key_list.rb
100
- - lib/faye_tracking/store/abstract_mapping.rb
100
+ - lib/faye_tracking/store/adapter/namespaced_key_list.rb
101
101
  - lib/faye_tracking/store/adapter/redis_key_list.rb
102
- - lib/faye_tracking/store/adapter/redis_mapping.rb
103
102
  - lib/faye_tracking/tracker.rb
104
103
  - lib/faye_tracking/version.rb
105
104
  - spec/faye_tracking_spec.rb
@@ -1,15 +0,0 @@
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,20 +0,0 @@
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