socky-server 0.5.0.beta1 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +5 -1
- data/README.md +37 -27
- data/Rakefile +1 -0
- data/lib/socky/server.rb +11 -10
- data/lib/socky/server/cached_json_hash.rb +16 -0
- data/lib/socky/server/channel/base.rb +3 -2
- data/lib/socky/server/version.rb +1 -1
- data/socky-server.gemspec +3 -3
- data/spec/performance/connectin_performance.rb +26 -0
- data/spec/performance/send_many_messages_performance.rb +25 -0
- data/spec/performance/send_message_to_many_listeners_performance.rb +25 -0
- data/spec/performance_helper.rb +55 -0
- data/spec/spec_helper.rb +6 -3
- data/tasks/performance.rb +11 -0
- metadata +26 -18
data/CHANGELOG.md
CHANGED
@@ -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
|
-
|
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
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
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
|
-
|
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
|
-
|
49
|
+
``` ruby
|
50
|
+
require 'socky/server'
|
44
51
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
+
options = {
|
53
|
+
:debug => true,
|
54
|
+
:applications => {
|
55
|
+
:my_app => 'my_secret',
|
56
|
+
:other_app => 'other_secret'
|
57
|
+
}
|
58
|
+
}
|
52
59
|
|
53
|
-
|
54
|
-
|
55
|
-
|
60
|
+
map '/websocket' do
|
61
|
+
run Socky::Server::WebSocket.new options
|
62
|
+
end
|
56
63
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
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
|
-
|
72
|
+
``` bash
|
73
|
+
$ thin -R config.ru -p3001 start
|
74
|
+
```
|
65
75
|
|
66
76
|
## Setting other options
|
67
77
|
|
data/Rakefile
CHANGED
data/lib/socky/server.rb
CHANGED
@@ -10,14 +10,15 @@ module Socky
|
|
10
10
|
module Server
|
11
11
|
ROOT = File.expand_path(File.dirname(__FILE__))
|
12
12
|
|
13
|
-
autoload :Application,
|
14
|
-
autoload :Channel,
|
15
|
-
autoload :Config,
|
16
|
-
autoload :Connection,
|
17
|
-
autoload :HTTP,
|
18
|
-
autoload :Logger,
|
19
|
-
autoload :Message,
|
20
|
-
autoload :Misc,
|
21
|
-
autoload :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
|
@@ -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(
|
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(
|
55
|
+
send_data('event' => message.event, 'channel' => self.name, 'data' => message.user_data)
|
55
56
|
end
|
56
57
|
|
57
58
|
protected
|
data/lib/socky/server/version.rb
CHANGED
data/socky-server.gemspec
CHANGED
@@ -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
|
16
|
-
s.add_dependency 'socky-authenticator', '~> 0.5.0
|
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
|
+
|
data/spec/spec_helper.rb
CHANGED
@@ -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.
|
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
|
5
|
-
prerelease:
|
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:
|
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: &
|
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
|
21
|
+
version: 0.3.2
|
23
22
|
type: :runtime
|
24
23
|
prerelease: false
|
25
|
-
version_requirements: *
|
24
|
+
version_requirements: *70158364026200
|
26
25
|
- !ruby/object:Gem::Dependency
|
27
26
|
name: socky-authenticator
|
28
|
-
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
|
32
|
+
version: 0.5.0
|
34
33
|
type: :runtime
|
35
34
|
prerelease: false
|
36
|
-
version_requirements: *
|
35
|
+
version_requirements: *70158364024620
|
37
36
|
- !ruby/object:Gem::Dependency
|
38
37
|
name: json
|
39
|
-
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: *
|
46
|
+
version_requirements: *70158364024140
|
48
47
|
- !ruby/object:Gem::Dependency
|
49
48
|
name: rspec
|
50
|
-
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: *
|
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
|
-
|
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:
|
124
|
+
version: '0'
|
121
125
|
requirements: []
|
122
126
|
rubyforge_project:
|
123
|
-
rubygems_version: 1.
|
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
|