colossus 0.10.0 → 0.11.0

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: 744e97003be9b4ba97c54fd8877679f042268423
4
- data.tar.gz: 831be7283ce1271cf95cb80ea751d62c4ab384e8
3
+ metadata.gz: c95d76c91b2b37ca49130fc2fbb14ded53d85620
4
+ data.tar.gz: 123c4860b3864ddfda2d505faca5292f36e9083c
5
5
  SHA512:
6
- metadata.gz: 0db8010a14269f54288633e7701c6bae7a13a27cd087e8b024faedbc307717fbc185b2e051a653575cd5abfe17ef6a0bb0898e982a5ca9b8a8c1c465ca0df9e2
7
- data.tar.gz: 287374b1f76f7b5891f4ebb5ea4a25c66c9cdb9df77d6db0231fe8369a70572238df3a3ab426b7877e019686ccae675e97b855950e4a84815d33afafa4854e85
6
+ metadata.gz: 2f998058fc924ccb6c760c7e40529a7db2db09a53c50bc4e0c059d7b80225216617347e7d1ed50a096d36671b39dcd232fe8f740bd6c44676415beac25bf5df7
7
+ data.tar.gz: 071464b4bc8a3bee161f6780b6db462b84f7a98bbcabe3f302b7d2be9075b964fc9131d618f990b30060ed319c20bcc235c6557fe64cfac47261b3266c1c812b
@@ -1,11 +1,13 @@
1
1
  require 'faye'
2
2
  require 'json'
3
3
  require 'openssl'
4
+ require 'monitor'
4
5
  require 'faraday'
5
6
  require 'faraday_middleware'
6
7
  require 'observer'
7
8
  require 'em-synchrony'
8
9
  require 'securerandom'
10
+ require 'thread_safe'
9
11
 
10
12
  require 'colossus/configuration'
11
13
  require 'colossus/verifier'
@@ -16,6 +18,12 @@ require 'colossus/engines/memory/memory'
16
18
  require 'colossus/engines/memory/client_session'
17
19
  require 'colossus/engines/memory/client_session_store'
18
20
 
21
+ require 'colossus/engines/memory_thread_safe/memory'
22
+ require 'colossus/engines/memory_thread_safe/client_session'
23
+ require 'colossus/engines/memory_thread_safe/client_session_store'
24
+
25
+ require 'colossus/engines/memory_monitor/memory'
26
+
19
27
  require 'colossus/faye/extension'
20
28
 
21
29
  # Top Level Class.
@@ -23,6 +31,10 @@ require 'colossus/faye/extension'
23
31
  class Colossus
24
32
  include Observable
25
33
 
34
+ ACTIVE = 'active'.freeze
35
+ AWAY = 'away'.freeze
36
+ DISCONNECTED = 'disconnected'.freeze
37
+
26
38
  attr_reader :engine, :verifier
27
39
 
28
40
  # Initialize Colossus
@@ -9,7 +9,7 @@ class Colossus
9
9
  def initialize
10
10
  @ttl = 10
11
11
  @seconds_before_ttl_check = 2
12
- @engine = Colossus::Engine::Memory
12
+ @engine = Colossus::Engine::MemoryThreadSafe
13
13
  @secret_key = ''
14
14
  @writer_token = ''
15
15
  end
@@ -6,7 +6,7 @@ class Colossus
6
6
  attr_reader :status, :last_seen
7
7
 
8
8
  def initialize
9
- @status = 'disconnected'
9
+ @status = DISCONNECTED
10
10
  @last_seen = Time.now
11
11
  end
12
12
 
@@ -11,16 +11,16 @@ class Colossus
11
11
  @sessions = Hash.new do |hash, key|
12
12
  hash[key] = Colossus::Engine::Memory::ClientSession.new
13
13
  end
14
- @last_status = 'disconnected'
14
+ @last_status = DISCONNECTED
15
15
  end
16
16
 
17
17
  def status
18
- sessions.values.reduce('disconnected') do |memo, session|
18
+ sessions.values.reduce(DISCONNECTED) do |memo, session|
19
19
  case session.status
20
- when 'active'
20
+ when ACTIVE
21
21
  session.status
22
- when 'away'
23
- memo == 'active' ? memo : session.status
22
+ when AWAY
23
+ memo == ACTIVE ? memo : session.status
24
24
  else
25
25
  memo
26
26
  end
@@ -1,20 +1,19 @@
1
1
  class Colossus
2
2
  module Engine
3
- # The Memory Engine is a non-distributed engine.
3
+ # The Memory Engine is a non-distributed, in process, non-threadsafe engine.
4
4
  # Based on EventMachine in order to provide the ttl to
5
5
  # disconnect clients.
6
6
  class Memory
7
7
  include Observable
8
8
 
9
- attr_reader :client_sessions, :ttl, :mutex
9
+ attr_reader :client_sessions, :ttl
10
10
 
11
11
  # @param [Integer/Float] ttl TTL in seconds
12
12
  def initialize(ttl)
13
13
  @client_sessions = Hash.new do |hash, key|
14
14
  hash[key] = Colossus::Engine::Memory::ClientSessionStore.new
15
15
  end
16
- @ttl = ttl
17
- @mutex = Mutex.new
16
+ @ttl = ttl
18
17
  end
19
18
 
20
19
  def user_changed(user_id, status)
@@ -23,18 +22,16 @@ class Colossus
23
22
  end
24
23
 
25
24
  def set(user_id, client_id, given_status)
26
- mutex.synchronize do
27
- if given_status == 'disconnected'
28
- client_sessions[user_id].delete(client_id)
29
- else
30
- client_sessions[user_id][client_id] = given_status
31
- end
25
+ if given_status == DISCONNECTED
26
+ client_sessions[user_id].delete(client_id)
27
+ else
28
+ client_sessions[user_id][client_id] = given_status
32
29
  end
33
30
 
34
31
  if client_sessions[user_id].sessions.empty? ||
35
32
  client_sessions[user_id].status_changed?
36
33
  status = client_sessions[user_id].status
37
- delete(user_id) if status == 'disconnected'
34
+ delete(user_id) if status == DISCONNECTED
38
35
  user_changed(user_id, status)
39
36
  return true
40
37
  end
@@ -46,7 +43,7 @@ class Colossus
46
43
  if client_sessions.has_key?(user_id)
47
44
  { user_id => client_sessions[user_id].status }
48
45
  else
49
- { user_id => 'disconnected' }
46
+ { user_id => DISCONNECTED }
50
47
  end
51
48
  end
52
49
 
@@ -63,16 +60,12 @@ class Colossus
63
60
  end
64
61
 
65
62
  def delete(user_id)
66
- mutex.synchronize do
67
- client_sessions.delete(user_id)
68
- end
63
+ client_sessions.delete(user_id)
69
64
  end
70
65
 
71
66
  def reset!
72
- mutex.synchronize do
73
- @client_sessions = Hash.new do |hash, key|
74
- hash[key] = Colossus::Engine::Memory::ClientSessionStore.new
75
- end
67
+ @client_sessions = Hash.new do |hash, key|
68
+ hash[key] = Colossus::Engine::Memory::ClientSessionStore.new
76
69
  end
77
70
  end
78
71
 
@@ -85,16 +78,10 @@ class Colossus
85
78
  user_ids_to_delete = []
86
79
 
87
80
  client_sessions.each_pair do |user_id, session_store|
88
- sessions_dupped = session_store.sessions.dup
89
-
90
- session_store.sessions.each_pair do |session_id, session|
91
- if (session.last_seen + ttl) < Time.now
92
- sessions_dupped.delete(session_id)
93
- end
81
+ session_store.sessions.delete_if do |session_id, session|
82
+ (session.last_seen + ttl) < Time.now
94
83
  end
95
84
 
96
- mutex.synchronize { session_store.sessions = sessions_dupped }
97
-
98
85
  if (session_store.last_seen + ttl) < Time.now
99
86
  user_ids_to_delete << user_id
100
87
  end
@@ -106,7 +93,7 @@ class Colossus
106
93
  def delete_expired_users(user_ids)
107
94
  user_ids.each do |user_id|
108
95
  delete(user_id)
109
- user_changed(user_id, 'disconnected')
96
+ user_changed(user_id, DISCONNECTED)
110
97
  end
111
98
  end
112
99
  end
@@ -0,0 +1,118 @@
1
+ class Colossus
2
+ module Engine
3
+ # The Memory Engine is a non-distributed, in process, threadsafe engine.
4
+ # Based on EventMachine in order to provide the ttl to
5
+ # disconnect clients.
6
+ class MemoryMonitor
7
+ include Observable
8
+
9
+ attr_reader :client_sessions, :ttl, :monitor
10
+
11
+ # @param [Integer/Float] ttl TTL in seconds
12
+ def initialize(ttl)
13
+ @client_sessions = Hash.new do |hash, key|
14
+ hash[key] = Colossus::Engine::Memory::ClientSessionStore.new
15
+ end
16
+ @ttl = ttl
17
+ @monitor = Monitor.new
18
+ end
19
+
20
+ def user_changed(user_id, status)
21
+ changed
22
+ notify_observers(user_id, status)
23
+ end
24
+
25
+ def set(user_id, client_id, given_status)
26
+ synchronize do
27
+ if given_status == DISCONNECTED
28
+ client_sessions[user_id].delete(client_id)
29
+ else
30
+ client_sessions[user_id][client_id] = given_status
31
+ end
32
+ end
33
+
34
+ if client_sessions[user_id].sessions.empty? ||
35
+ client_sessions[user_id].status_changed?
36
+ status = client_sessions[user_id].status
37
+ delete(user_id) if status == DISCONNECTED
38
+ user_changed(user_id, status)
39
+ return true
40
+ end
41
+
42
+ false
43
+ end
44
+
45
+ def get(user_id)
46
+ if client_sessions.has_key?(user_id)
47
+ { user_id => client_sessions[user_id].status }
48
+ else
49
+ { user_id => DISCONNECTED }
50
+ end
51
+ end
52
+
53
+ def get_multi(*user_ids)
54
+ user_ids.inject({}) { |memo, user_id| memo.merge!(get(user_id)) }
55
+ end
56
+
57
+ def get_all
58
+ statuses = {}
59
+ client_sessions.each_pair do |user_id, session_store|
60
+ statuses[user_id] = session_store.status
61
+ end
62
+ statuses
63
+ end
64
+
65
+ def delete(user_id)
66
+ synchronize do
67
+ client_sessions.delete(user_id)
68
+ end
69
+ end
70
+
71
+ def reset!
72
+ synchronize do
73
+ @client_sessions = Hash.new do |hash, key|
74
+ hash[key] = Colossus::Engine::Memory::ClientSessionStore.new
75
+ end
76
+ end
77
+ end
78
+
79
+ def new_periodic_ttl
80
+ secs_ttl = Colossus.config.seconds_before_ttl_check
81
+ @periodic_ttl = EM::Synchrony.add_periodic_timer(secs_ttl, &method(:gc_ttl))
82
+ end
83
+
84
+ def gc_ttl
85
+ user_ids_to_delete = []
86
+
87
+ client_sessions.each_pair do |user_id, session_store|
88
+ sessions_dupped = session_store.sessions.dup
89
+
90
+ session_store.sessions.each_pair do |session_id, session|
91
+ if (session.last_seen + ttl) < Time.now
92
+ sessions_dupped.delete(session_id)
93
+ end
94
+ end
95
+
96
+ synchronize { session_store.sessions = sessions_dupped }
97
+
98
+ if (session_store.last_seen + ttl) < Time.now
99
+ user_ids_to_delete << user_id
100
+ end
101
+ end
102
+
103
+ delete_expired_users(user_ids_to_delete)
104
+ end
105
+
106
+ def delete_expired_users(user_ids)
107
+ user_ids.each do |user_id|
108
+ delete(user_id)
109
+ user_changed(user_id, DISCONNECTED)
110
+ end
111
+ end
112
+
113
+ def synchronize(&block)
114
+ monitor.synchronize(&block)
115
+ end
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,30 @@
1
+ class Colossus
2
+ module Engine
3
+ class MemoryThreadSafe
4
+ # Represent the status and the information of a given user.
5
+ class ClientSession
6
+ attr_reader :status, :last_seen
7
+
8
+ def initialize
9
+ @data = ThreadSafe::Cache.new
10
+ @data[:status] = DISCONNECTED
11
+ @data[:last_seen] = Time.now
12
+ end
13
+
14
+ def status
15
+ @data[:status]
16
+ end
17
+
18
+ def status=(given_status)
19
+ @data[:last_seen] = Time.now
20
+ @data[:status] = given_status
21
+ end
22
+
23
+ def last_seen
24
+ @data[:last_seen]
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+
@@ -0,0 +1,65 @@
1
+ class Colossus
2
+ module Engine
3
+ class MemoryThreadSafe
4
+ # Represents all the different sessions of a user. It can find
5
+ # the global status of the user given all the different status.
6
+ class ClientSessionStore
7
+ attr_reader :last_status, :ttl
8
+ attr_accessor :sessions
9
+
10
+ def initialize(ttl)
11
+ @sessions = ThreadSafe::Cache.new do |hash, key|
12
+ hash[key] = Colossus::Engine::MemoryThreadSafe::ClientSession.new
13
+ end
14
+ @last_status = DISCONNECTED
15
+ @ttl = ttl
16
+ end
17
+
18
+ def status
19
+ sessions.values.reduce(DISCONNECTED) do |memo, session|
20
+ case session.status
21
+ when ACTIVE
22
+ session.status
23
+ when AWAY
24
+ memo == ACTIVE ? memo : session.status
25
+ else
26
+ memo
27
+ end
28
+ end
29
+ end
30
+
31
+ def last_seen
32
+ sessions.values.reduce(Time.new(0)) do |memo, session|
33
+ session.last_seen > memo ? session.last_seen : memo
34
+ end
35
+ end
36
+
37
+ def status_changed?
38
+ last_status != status
39
+ end
40
+
41
+ def [](session_id)
42
+ sessions[session_id]
43
+ end
44
+
45
+ def []=(session_id, session_status)
46
+ @last_status = status
47
+ sessions[session_id].status = session_status
48
+ end
49
+
50
+ def delete(session_id)
51
+ sessions.delete(session_id)
52
+ end
53
+
54
+ def delete_expired_sessions
55
+ session_keys_to_delete = []
56
+ sessions.each_pair do |session_id, session|
57
+ session_keys_to_delete << session_id if (session.last_seen + ttl) < Time.now
58
+ end
59
+
60
+ session_keys_to_delete.each { |session_id| sessions.delete(session_id) }
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,90 @@
1
+ class Colossus
2
+ module Engine
3
+ # Threadsage with ThreadSafe
4
+ class MemoryThreadSafe
5
+ include Observable
6
+
7
+ attr_reader :client_sessions, :ttl
8
+
9
+ # @param [Integer/Float] ttl TTL in seconds
10
+ def initialize(ttl)
11
+ @client_sessions = ThreadSafe::Cache.new do |hash, key|
12
+ hash[key] = Colossus::Engine::MemoryThreadSafe::ClientSessionStore.new(ttl)
13
+ end
14
+ @ttl = ttl
15
+ end
16
+
17
+ def user_changed(user_id, status)
18
+ changed
19
+ notify_observers(user_id, status)
20
+ end
21
+
22
+ def set(user_id, client_id, given_status)
23
+ if given_status == DISCONNECTED
24
+ client_sessions[user_id].delete(client_id)
25
+ else
26
+ client_sessions[user_id][client_id] = given_status
27
+ end
28
+
29
+ if client_sessions[user_id].sessions.empty? ||
30
+ client_sessions[user_id].status_changed?
31
+ status = client_sessions[user_id].status
32
+ delete(user_id) if status == DISCONNECTED
33
+ user_changed(user_id, status)
34
+ return true
35
+ end
36
+
37
+ false
38
+ end
39
+
40
+ def get(user_id)
41
+ if client_sessions.key?(user_id)
42
+ { user_id => client_sessions[user_id].status }
43
+ else
44
+ { user_id => DISCONNECTED }
45
+ end
46
+ end
47
+
48
+ def get_multi(*user_ids)
49
+ user_ids.inject({}) { |memo, user_id| memo.merge!(get(user_id)) }
50
+ end
51
+
52
+ def get_all
53
+ statuses = {}
54
+ client_sessions.each_pair do |user_id, session_store|
55
+ statuses[user_id] = session_store.status
56
+ end
57
+ statuses
58
+ end
59
+
60
+ def delete(user_id)
61
+ client_sessions.delete(user_id)
62
+ end
63
+
64
+ def reset!
65
+ client_sessions.clear
66
+ end
67
+
68
+ def new_periodic_ttl
69
+ secs_ttl = Colossus.config.seconds_before_ttl_check
70
+ @periodic_ttl = EM::Synchrony.add_periodic_timer(secs_ttl, &method(:gc_ttl))
71
+ end
72
+
73
+ def gc_ttl
74
+ delete_expired_users
75
+ client_sessions.each_pair do |user_id, session_store|
76
+ session_store.delete_expired_sessions
77
+ end
78
+ end
79
+
80
+ def delete_expired_users
81
+ user_ids_to_delete = []
82
+ client_sessions.each_pair do |user_id, session_store|
83
+ user_ids_to_delete << user_id if (session_store.last_seen + ttl) < Time.now
84
+ end
85
+
86
+ user_ids_to_delete.each { |user_id| client_sessions.delete(user_id) }
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,12 @@
1
+ class Colossus
2
+ module Engine
3
+ # The Redis Engine is a distributed engine.
4
+ # Colossus server is now stateless.
5
+ class Redis
6
+ include Observable
7
+
8
+ def initialize(ttl)
9
+ end
10
+ end
11
+ end
12
+ end
@@ -13,7 +13,7 @@ class Colossus
13
13
  faye.add_extension(self)
14
14
  end
15
15
 
16
- def incoming(message, _request, callback)
16
+ def incoming(message, callback)
17
17
  if !acceptable?(message)
18
18
  handle_invalid_token(message)
19
19
  message.delete('data')
@@ -1,4 +1,4 @@
1
1
  # The Version
2
2
  class Colossus
3
- VERSION = '0.10.0'
3
+ VERSION = '0.11.0'
4
4
  end
metadata CHANGED
@@ -1,69 +1,83 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: colossus
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.0
4
+ version: 0.11.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - antoinelyset
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-01-05 00:00:00.000000000 Z
11
+ date: 2015-01-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faye
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ~>
18
18
  - !ruby/object:Gem::Version
19
19
  version: '1.0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - "~>"
24
+ - - ~>
25
25
  - !ruby/object:Gem::Version
26
26
  version: '1.0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: em-synchrony
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
31
+ - - ~>
32
32
  - !ruby/object:Gem::Version
33
33
  version: '1.0'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - "~>"
38
+ - - ~>
39
39
  - !ruby/object:Gem::Version
40
40
  version: '1.0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: faraday
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - "~>"
45
+ - - ~>
46
46
  - !ruby/object:Gem::Version
47
47
  version: '0'
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - "~>"
52
+ - - ~>
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: faraday_middleware
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - "~>"
59
+ - - ~>
60
60
  - !ruby/object:Gem::Version
61
61
  version: '0'
62
62
  type: :runtime
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - "~>"
66
+ - - ~>
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: thread_safe
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ~>
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ~>
67
81
  - !ruby/object:Gem::Version
68
82
  version: '0'
69
83
  description: Colossus is a Push and Presence pure Ruby server. It uses Faye internally.
@@ -78,6 +92,11 @@ files:
78
92
  - lib/colossus/engines/memory/client_session.rb
79
93
  - lib/colossus/engines/memory/client_session_store.rb
80
94
  - lib/colossus/engines/memory/memory.rb
95
+ - lib/colossus/engines/memory_monitor/memory.rb
96
+ - lib/colossus/engines/memory_thread_safe/client_session.rb
97
+ - lib/colossus/engines/memory_thread_safe/client_session_store.rb
98
+ - lib/colossus/engines/memory_thread_safe/memory.rb
99
+ - lib/colossus/engines/redis/redis.rb
81
100
  - lib/colossus/faye/extension.rb
82
101
  - lib/colossus/http_writer_client.rb
83
102
  - lib/colossus/simple_writer_server.rb
@@ -93,17 +112,17 @@ require_paths:
93
112
  - lib
94
113
  required_ruby_version: !ruby/object:Gem::Requirement
95
114
  requirements:
96
- - - ">="
115
+ - - '>='
97
116
  - !ruby/object:Gem::Version
98
- version: '0'
117
+ version: 1.9.3
99
118
  required_rubygems_version: !ruby/object:Gem::Requirement
100
119
  requirements:
101
- - - ">="
120
+ - - '>='
102
121
  - !ruby/object:Gem::Version
103
122
  version: '0'
104
123
  requirements: []
105
124
  rubyforge_project:
106
- rubygems_version: 2.2.2
125
+ rubygems_version: 2.0.14
107
126
  signing_key:
108
127
  specification_version: 4
109
128
  summary: Colossus, Web Push & Presence made easy.