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.
- 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
|