faye_tracking 0.2.1 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
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