socky-server 0.5.0.beta1 → 0.5.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.
@@ -1,5 +1,9 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.5.0 / 2012-02-16
4
+
5
+ - Performance fixes - sending messages should be now 3-5 times faster(thanks to @piotrmarat)
6
+
3
7
  ## 0.5.0.beta1 / 2011-08-01
4
8
 
5
9
  Socky was rewritten from scratch. From this version it's Rack application and is based on
@@ -105,4 +109,4 @@ And many more - please check [Socky website](http://socky.org) for more or check
105
109
 
106
110
  ## 0.0.6 / 2010-05-24
107
111
 
108
- - initial release
112
+ - initial release
data/README.md CHANGED
@@ -2,21 +2,25 @@
2
2
 
3
3
  ## Installation
4
4
 
5
- $ gem install socky-server --pre
5
+ ``` bash
6
+ $ gem install socky-server --pre
7
+ ```
6
8
 
7
9
  ## Usage
8
10
 
9
11
  Socky server provides two Rack middlewares - WebSocket and HTTP. Each one of them can be used separately, but they can be also used in one process. Example Rackup file could look like that:
10
12
 
11
- require 'socky/server'
12
-
13
- map '/websocket' do
14
- run Socky::Server::WebSocket.new
15
- end
16
-
17
- map '/http' do
18
- run Socky::Server::HTTP.new
19
- end
13
+ ``` ruby
14
+ require 'socky/server'
15
+
16
+ map '/websocket' do
17
+ run Socky::Server::WebSocket.new
18
+ end
19
+
20
+ map '/http' do
21
+ run Socky::Server::HTTP.new
22
+ end
23
+ ```
20
24
 
21
25
  ## Configuration
22
26
 
@@ -26,7 +30,9 @@ Both middlewares accept options as hash. Currently available options are:
26
30
 
27
31
  Hash of supported applications. Each key is application name, each value is application secret. You can use as much applications as you want - each of them will have separate application address created by mixing hostname, middleware address and applicatio name. So i.e. for app "my_app" WebSocket application uri will be:
28
32
 
29
- http://example.org/websocket/my_app
33
+ ```
34
+ http://example.org/websocket/my_app
35
+ ```
30
36
 
31
37
  ### :debug [Boolean]
32
38
 
@@ -40,28 +46,32 @@ Path to YAML config file. Config file should contain hash with exactly the same
40
46
 
41
47
  Create file 'config.ru':
42
48
 
43
- require 'socky/server'
49
+ ``` ruby
50
+ require 'socky/server'
44
51
 
45
- options = {
46
- :debug => true,
47
- :applications => {
48
- :my_app => 'my_secret',
49
- :other_app => 'other_secret'
50
- }
51
- }
52
+ options = {
53
+ :debug => true,
54
+ :applications => {
55
+ :my_app => 'my_secret',
56
+ :other_app => 'other_secret'
57
+ }
58
+ }
52
59
 
53
- map '/websocket' do
54
- run Socky::Server::WebSocket.new options
55
- end
60
+ map '/websocket' do
61
+ run Socky::Server::WebSocket.new options
62
+ end
56
63
 
57
- map '/http' do
58
- use Rack::CommonLogger
59
- run Socky::Server::HTTP.new options
60
- end
64
+ map '/http' do
65
+ use Rack::CommonLogger
66
+ run Socky::Server::HTTP.new options
67
+ end
68
+ ```
61
69
 
62
70
  Run file using Thin:
63
71
 
64
- $ thin -R config.ru -p3001 start
72
+ ``` bash
73
+ $ thin -R config.ru -p3001 start
74
+ ```
65
75
 
66
76
  ## Setting other options
67
77
 
data/Rakefile CHANGED
@@ -2,6 +2,7 @@ require 'bundler'
2
2
  Bundler::GemHelper.install_tasks
3
3
 
4
4
  require 'rspec/core/rake_task'
5
+ require File.expand_path(File.join(File.dirname(__FILE__), 'tasks/performance'))
5
6
 
6
7
  RSpec::Core::RakeTask.new do |t|
7
8
  t.rspec_opts = ["-c", "-f progress"]
@@ -10,14 +10,15 @@ module Socky
10
10
  module Server
11
11
  ROOT = File.expand_path(File.dirname(__FILE__))
12
12
 
13
- autoload :Application, "#{ROOT}/server/application"
14
- autoload :Channel, "#{ROOT}/server/channel"
15
- autoload :Config, "#{ROOT}/server/config"
16
- autoload :Connection, "#{ROOT}/server/connection"
17
- autoload :HTTP, "#{ROOT}/server/http"
18
- autoload :Logger, "#{ROOT}/server/logger"
19
- autoload :Message, "#{ROOT}/server/message"
20
- autoload :Misc, "#{ROOT}/server/misc"
21
- autoload :WebSocket, "#{ROOT}/server/websocket"
13
+ autoload :Application, "#{ROOT}/server/application"
14
+ autoload :Channel, "#{ROOT}/server/channel"
15
+ autoload :Config, "#{ROOT}/server/config"
16
+ autoload :Connection, "#{ROOT}/server/connection"
17
+ autoload :HTTP, "#{ROOT}/server/http"
18
+ autoload :Logger, "#{ROOT}/server/logger"
19
+ autoload :Message, "#{ROOT}/server/message"
20
+ autoload :Misc, "#{ROOT}/server/misc"
21
+ autoload :WebSocket, "#{ROOT}/server/websocket"
22
+ autoload :CachedJsonHash, "#{ROOT}/server/cached_json_hash"
22
23
  end
23
- end
24
+ end
@@ -0,0 +1,16 @@
1
+ module Socky
2
+ module Server
3
+ class CachedJsonHash < Hash
4
+
5
+ def to_json
6
+ @json ||= super
7
+ end
8
+
9
+ def remove_cache
10
+ @json = nil
11
+ end
12
+
13
+ end
14
+ end
15
+ end
16
+
@@ -34,8 +34,9 @@ module Socky
34
34
  end
35
35
 
36
36
  def send_data(data, except = nil)
37
+ cached_json_data = CachedJsonHash[data]
37
38
  self.subscribers.each do |subscriber_id, subscriber|
38
- subscriber['connection'].send_data(data) unless subscriber_id == except || !subscriber['read']
39
+ subscriber['connection'].send_data(cached_json_data) unless subscriber_id == except || !subscriber['read']
39
40
  end
40
41
  end
41
42
 
@@ -51,7 +52,7 @@ module Socky
51
52
 
52
53
  def deliver(connection, message)
53
54
  return unless connection.nil? || (subscribers[connection.id] && subscribers[connection.id]['write'])
54
- send_data({ 'event' => message.event, 'channel' => self.name, 'data' => message.user_data })
55
+ send_data('event' => message.event, 'channel' => self.name, 'data' => message.user_data)
55
56
  end
56
57
 
57
58
  protected
@@ -1,5 +1,5 @@
1
1
  module Socky
2
2
  module Server
3
- VERSION = '0.5.0.beta1'
3
+ VERSION = '0.5.0'
4
4
  end
5
5
  end
@@ -11,9 +11,9 @@ Gem::Specification.new do |s|
11
11
  s.homepage = "http://socky.org"
12
12
  s.summary = %q{Socky is a WebSocket server and client for Ruby}
13
13
  s.description = %q{Socky is a WebSocket server and client for Ruby}
14
-
15
- s.add_dependency 'websocket-rack', ">= 0.2.1"
16
- s.add_dependency 'socky-authenticator', '~> 0.5.0.beta5'
14
+
15
+ s.add_dependency 'websocket-rack', ">= 0.3.2"
16
+ s.add_dependency 'socky-authenticator', '~> 0.5.0'
17
17
  s.add_dependency 'json'
18
18
  s.add_development_dependency 'rspec', '~> 2.0'
19
19
 
@@ -0,0 +1,26 @@
1
+ require 'spec_helper'
2
+ require 'performance_helper'
3
+ require 'benchmark'
4
+
5
+ describe 'Connecting Performance' do
6
+
7
+ it "For x listeners" do
8
+ [1, 10, 100].each do |count|
9
+ results = []
10
+ 5.times do
11
+ @application = Socky::Server::Application.new('test_application', 'test_secret')
12
+ @channel = "presence"
13
+ results << Benchmark.realtime {count.times { add_listener }}
14
+ clean_application
15
+ end
16
+ print_result count, results
17
+ end
18
+ end
19
+
20
+ end
21
+
22
+
23
+
24
+
25
+
26
+
@@ -0,0 +1,25 @@
1
+ require 'spec_helper'
2
+ require 'performance_helper'
3
+ require 'benchmark'
4
+
5
+ describe 'Sending Many Messages Performance' do
6
+
7
+ it "For 1 listener and x messages" do
8
+ [1, 10, 100].each do |count|
9
+ results = []
10
+ 5.times do
11
+ @channel = "private"
12
+ @application = application_with_listeners(1)
13
+ results << Benchmark.realtime {send_messages(count)}
14
+ clean_application
15
+ end
16
+ print_result count, results
17
+ end
18
+ end
19
+
20
+ end
21
+
22
+
23
+
24
+
25
+
@@ -0,0 +1,25 @@
1
+ require 'spec_helper'
2
+ require 'performance_helper'
3
+ require 'benchmark'
4
+
5
+ describe 'Sending Message To Many Listeners Performance' do
6
+
7
+ it "For x listeners and 1 message" do
8
+ [1, 10, 100].each do |count|
9
+ results = []
10
+ 5.times do
11
+ @channel = "private"
12
+ @application = application_with_listeners(count)
13
+ results << Benchmark.realtime {send_messages(1)}
14
+ clean_application
15
+ end
16
+ print_result count, results
17
+ end
18
+ end
19
+ end
20
+
21
+
22
+
23
+
24
+
25
+
@@ -0,0 +1,55 @@
1
+ Socky::Server::Channel::Private.class_eval do
2
+ protected
3
+
4
+ def check_auth(connection, message)
5
+ true
6
+ end
7
+
8
+ end
9
+
10
+
11
+ def application_with_listeners count
12
+ @application = Socky::Server::Application.new('test_application', 'test_secret')
13
+ count.times { add_listener }
14
+ add_writer
15
+ @application
16
+ end
17
+
18
+ def add_listener
19
+ websocket = mock_websocket(@application.name)
20
+ env = { 'PATH_INFO' => '/websocket/' + @application.name }
21
+ websocket.on_open(env)
22
+ data = {'event' => 'socky:subscribe', 'channel' => "#{@channel}-channel", 'auth' => 'test_auth'}
23
+ websocket.on_message(env, data)
24
+ websocket
25
+ end
26
+
27
+ def add_writer
28
+ @writer_ws = mock_websocket(@application.name)
29
+ env = { 'PATH_INFO' => '/websocket/' + @application.name }
30
+ @writer_ws.on_open(env)
31
+ data = {'event' => 'socky:subscribe', 'channel' => "#{@channel}-channel", 'write' => 'true', 'auth' => 'test_auth'}
32
+ @writer_ws.on_message(env, data)
33
+ @writer_ws
34
+ end
35
+
36
+ def send_messages count
37
+ env = { 'PATH_INFO' => '/websocket/' + @application.name }
38
+ data = {'event' => 'send', 'channel' => "#{@channel}-channel", 'user_data' => "test_message"}
39
+ count.times { @writer_ws.on_message(env, data) }
40
+ end
41
+
42
+ def clean_application
43
+ @application.connections.values.each {|c| c.destroy}
44
+ Socky::Server::Channel::Private.list['test_application'] = Hash.new
45
+ Socky::Server::Channel::Private.list['test_application'] = Hash.new
46
+ Socky::Server::Application.list.delete('test_application')
47
+ end
48
+
49
+
50
+ def print_result label, results
51
+ avg = results.inject(0.0) { |sum, el| sum + el } / results.size
52
+ puts ["#{label}:".ljust(15), avg].join
53
+ end
54
+
55
+
@@ -8,13 +8,16 @@ def mock_websocket(application)
8
8
  env = {}
9
9
  env['PATH_INFO'] = '/websocket/' + application
10
10
  connection = Socky::Server::WebSocket.new.call(env)
11
- connection.stub!(:send_data)
11
+ send_data_method = connection.method(:send_data)
12
+ connection.stub!(:send_data).and_return do |*args|
13
+ a = send_data_method.call(*args)
14
+ end
12
15
  connection
13
16
  end
14
17
 
15
18
  def mock_connection(application)
16
19
  websocket = mock_websocket(application)
17
-
20
+
18
21
  env = { 'PATH_INFO' => '/websocket/' + application }
19
22
  websocket.on_open(env)
20
23
  end
@@ -24,4 +27,4 @@ def auth_token(socket, channel_name, remains = {})
24
27
  'connection_id' => socket.connection.id,
25
28
  'channel' => channel_name
26
29
  }.merge(remains), :allow_changing_rights => true, :secret => 'test_secret')['auth']
27
- end
30
+ end
@@ -0,0 +1,11 @@
1
+ require 'rspec/core'
2
+ require 'rspec/core/rake_task'
3
+
4
+ namespace :spec do
5
+ desc "Run the performance tests"
6
+ RSpec::Core::RakeTask.new("performance") do |t|
7
+ t.pattern = "./spec/**/*_performance.rb"
8
+ t.rspec_opts = ["-c", "-f documentation"]
9
+ end
10
+ end
11
+
metadata CHANGED
@@ -1,42 +1,41 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: socky-server
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0.beta1
5
- prerelease: 6
4
+ version: 0.5.0
5
+ prerelease:
6
6
  platform: ruby
7
7
  authors:
8
8
  - Bernard Potocki
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-08-01 00:00:00.000000000 +02:00
13
- default_executable:
12
+ date: 2012-02-16 00:00:00.000000000Z
14
13
  dependencies:
15
14
  - !ruby/object:Gem::Dependency
16
15
  name: websocket-rack
17
- requirement: &70321806627380 !ruby/object:Gem::Requirement
16
+ requirement: &70158364026200 !ruby/object:Gem::Requirement
18
17
  none: false
19
18
  requirements:
20
19
  - - ! '>='
21
20
  - !ruby/object:Gem::Version
22
- version: 0.2.1
21
+ version: 0.3.2
23
22
  type: :runtime
24
23
  prerelease: false
25
- version_requirements: *70321806627380
24
+ version_requirements: *70158364026200
26
25
  - !ruby/object:Gem::Dependency
27
26
  name: socky-authenticator
28
- requirement: &70321806626880 !ruby/object:Gem::Requirement
27
+ requirement: &70158364024620 !ruby/object:Gem::Requirement
29
28
  none: false
30
29
  requirements:
31
30
  - - ~>
32
31
  - !ruby/object:Gem::Version
33
- version: 0.5.0.beta5
32
+ version: 0.5.0
34
33
  type: :runtime
35
34
  prerelease: false
36
- version_requirements: *70321806626880
35
+ version_requirements: *70158364024620
37
36
  - !ruby/object:Gem::Dependency
38
37
  name: json
39
- requirement: &70321806626500 !ruby/object:Gem::Requirement
38
+ requirement: &70158364024140 !ruby/object:Gem::Requirement
40
39
  none: false
41
40
  requirements:
42
41
  - - ! '>='
@@ -44,10 +43,10 @@ dependencies:
44
43
  version: '0'
45
44
  type: :runtime
46
45
  prerelease: false
47
- version_requirements: *70321806626500
46
+ version_requirements: *70158364024140
48
47
  - !ruby/object:Gem::Dependency
49
48
  name: rspec
50
- requirement: &70321806625940 !ruby/object:Gem::Requirement
49
+ requirement: &70158364022880 !ruby/object:Gem::Requirement
51
50
  none: false
52
51
  requirements:
53
52
  - - ~>
@@ -55,7 +54,7 @@ dependencies:
55
54
  version: '2.0'
56
55
  type: :development
57
56
  prerelease: false
58
- version_requirements: *70321806625940
57
+ version_requirements: *70158364022880
59
58
  description: Socky is a WebSocket server and client for Ruby
60
59
  email:
61
60
  - bernard.potocki@imanel.org
@@ -73,6 +72,7 @@ files:
73
72
  - example/config.yml
74
73
  - lib/socky/server.rb
75
74
  - lib/socky/server/application.rb
75
+ - lib/socky/server/cached_json_hash.rb
76
76
  - lib/socky/server/channel.rb
77
77
  - lib/socky/server/channel/base.rb
78
78
  - lib/socky/server/channel/presence.rb
@@ -93,13 +93,17 @@ files:
93
93
  - spec/integration/ws_connection_spec.rb
94
94
  - spec/integration/ws_presence_spec.rb
95
95
  - spec/integration/ws_rights_spec.rb
96
+ - spec/performance/connectin_performance.rb
97
+ - spec/performance/send_many_messages_performance.rb
98
+ - spec/performance/send_message_to_many_listeners_performance.rb
99
+ - spec/performance_helper.rb
96
100
  - spec/spec_helper.rb
97
101
  - spec/support/websocket_application.rb
98
102
  - spec/unit/socky/server/application_spec.rb
99
103
  - spec/unit/socky/server/config_spec.rb
100
104
  - spec/unit/socky/server/connection_spec.rb
101
105
  - spec/unit/socky/server/message_spec.rb
102
- has_rdoc: true
106
+ - tasks/performance.rb
103
107
  homepage: http://socky.org
104
108
  licenses: []
105
109
  post_install_message:
@@ -115,12 +119,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
115
119
  required_rubygems_version: !ruby/object:Gem::Requirement
116
120
  none: false
117
121
  requirements:
118
- - - ! '>'
122
+ - - ! '>='
119
123
  - !ruby/object:Gem::Version
120
- version: 1.3.1
124
+ version: '0'
121
125
  requirements: []
122
126
  rubyforge_project:
123
- rubygems_version: 1.6.2
127
+ rubygems_version: 1.8.11
124
128
  signing_key:
125
129
  specification_version: 3
126
130
  summary: Socky is a WebSocket server and client for Ruby
@@ -130,6 +134,10 @@ test_files:
130
134
  - spec/integration/ws_connection_spec.rb
131
135
  - spec/integration/ws_presence_spec.rb
132
136
  - spec/integration/ws_rights_spec.rb
137
+ - spec/performance/connectin_performance.rb
138
+ - spec/performance/send_many_messages_performance.rb
139
+ - spec/performance/send_message_to_many_listeners_performance.rb
140
+ - spec/performance_helper.rb
133
141
  - spec/spec_helper.rb
134
142
  - spec/support/websocket_application.rb
135
143
  - spec/unit/socky/server/application_spec.rb