socky-server 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.textile +95 -0
- data/README.md +30 -0
- data/Rakefile +31 -0
- data/VERSION +1 -0
- data/bin/socky +5 -0
- data/lib/em-websocket_hacks.rb +15 -0
- data/lib/socky.rb +75 -0
- data/lib/socky/connection.rb +137 -0
- data/lib/socky/connection/authentication.rb +99 -0
- data/lib/socky/connection/finders.rb +67 -0
- data/lib/socky/message.rb +85 -0
- data/lib/socky/misc.rb +74 -0
- data/lib/socky/net_request.rb +27 -0
- data/lib/socky/options.rb +39 -0
- data/lib/socky/options/config.rb +79 -0
- data/lib/socky/options/parser.rb +93 -0
- data/lib/socky/runner.rb +95 -0
- data/spec/em-websocket_spec.rb +36 -0
- data/spec/files/default.yml +18 -0
- data/spec/files/invalid.yml +1 -0
- data/spec/socky/connection/authentication_spec.rb +183 -0
- data/spec/socky/connection/finders_spec.rb +188 -0
- data/spec/socky/connection_spec.rb +151 -0
- data/spec/socky/message_spec.rb +102 -0
- data/spec/socky/misc_spec.rb +74 -0
- data/spec/socky/net_request_spec.rb +42 -0
- data/spec/socky/options/config_spec.rb +72 -0
- data/spec/socky/options/parser_spec.rb +76 -0
- data/spec/socky/options_spec.rb +60 -0
- data/spec/socky/runner_spec.rb +88 -0
- data/spec/socky_spec.rb +89 -0
- data/spec/spec_helper.rb +5 -0
- data/spec/support/stallion.rb +96 -0
- metadata +198 -0
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Socky::Options do
|
4
|
+
|
5
|
+
context "class" do
|
6
|
+
before(:all) do
|
7
|
+
@default_options = Socky.options
|
8
|
+
end
|
9
|
+
after(:each) do
|
10
|
+
Socky.options = @default_options
|
11
|
+
end
|
12
|
+
|
13
|
+
context "#prepare" do
|
14
|
+
before(:each) do
|
15
|
+
Socky::Options::Parser.stub!(:parse).and_return({})
|
16
|
+
Socky::Options::Config.stub!(:read).and_return({})
|
17
|
+
end
|
18
|
+
it "should call parser with self option" do
|
19
|
+
Socky::Options::Parser.should_receive(:parse).with([:a,:b,:c])
|
20
|
+
Socky::Options.prepare([:a,:b,:c])
|
21
|
+
end
|
22
|
+
it "should call read_config with patch" do
|
23
|
+
Socky::Options::Config.should_receive(:read).with("/var/run/socky.yml", :kill => nil)
|
24
|
+
Socky::Options.prepare([])
|
25
|
+
end
|
26
|
+
it "should set Socky options to default hash when parse_options and read_config don't do anything" do
|
27
|
+
Socky::Options.prepare([])
|
28
|
+
Socky.options.should eql(default_options)
|
29
|
+
end
|
30
|
+
it "should value parse_options over default values" do
|
31
|
+
Socky::Options::Parser.stub!(:parse).and_return(:log_path => "parsed")
|
32
|
+
Socky::Options.prepare([])
|
33
|
+
Socky.options.should eql(default_options.merge(:log_path=>"parsed"))
|
34
|
+
end
|
35
|
+
it "should value read_config over default values" do
|
36
|
+
Socky::Options::Config.stub!(:read).and_return(:log_path => "from config")
|
37
|
+
Socky::Options.prepare([])
|
38
|
+
Socky.options.should eql(default_options.merge(:log_path=>"from config"))
|
39
|
+
end
|
40
|
+
it "should value parse_options over read_config" do
|
41
|
+
Socky::Options::Config.stub!(:read).and_return(:log_path => "from config")
|
42
|
+
Socky::Options::Parser.stub!(:parse).and_return(:log_path => "parsed")
|
43
|
+
Socky::Options.prepare([])
|
44
|
+
Socky.options.should eql(default_options.merge(:log_path=>"parsed"))
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def default_options
|
50
|
+
{
|
51
|
+
:port => 8080,
|
52
|
+
:log_path => nil,
|
53
|
+
:debug => false,
|
54
|
+
:deep_debug => false,
|
55
|
+
:secure => false,
|
56
|
+
:config_path => "/var/run/socky.yml"
|
57
|
+
}
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Socky::Runner do
|
4
|
+
|
5
|
+
context "#class" do
|
6
|
+
context "#run" do
|
7
|
+
before(:each) do
|
8
|
+
@server = mock(:server, :start => nil)
|
9
|
+
described_class.stub!(:new).and_return(@server)
|
10
|
+
end
|
11
|
+
it "should create new instance of self" do
|
12
|
+
described_class.should_receive(:new).with("some args")
|
13
|
+
described_class.run("some args")
|
14
|
+
end
|
15
|
+
it "should call #start on new instance of self if daemonize option is false" do
|
16
|
+
Socky.stub(:options).and_return({:daemonize => false})
|
17
|
+
@server.should_receive(:start)
|
18
|
+
described_class.run
|
19
|
+
end
|
20
|
+
it "should call #daemonize on new instance of self if daemonize option is true" do
|
21
|
+
Socky.stub(:options).and_return({:daemonize => true})
|
22
|
+
@server.should_receive(:daemonize)
|
23
|
+
described_class.run
|
24
|
+
end
|
25
|
+
it "should call #kill_pid on new instance of self if kill option is true" do
|
26
|
+
Socky.stub(:options).and_return({:kill => true})
|
27
|
+
@server.should_receive(:kill_pid)
|
28
|
+
described_class.run
|
29
|
+
end
|
30
|
+
end
|
31
|
+
context "#new" do
|
32
|
+
it "should prepare options from args" do
|
33
|
+
begin
|
34
|
+
described_class.new(["-c", File.dirname(__FILE__) + "/../files/default.yml"])
|
35
|
+
Socky.options.class.should eql(Hash)
|
36
|
+
Socky.options.should_not be_empty
|
37
|
+
ensure
|
38
|
+
Socky.options = nil
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
context "#instance" do
|
45
|
+
before(:each) do
|
46
|
+
Socky::Options.stub!(:prepare)
|
47
|
+
@runner = described_class.new
|
48
|
+
end
|
49
|
+
|
50
|
+
context "#start" do
|
51
|
+
it "should create valid websocket server" do
|
52
|
+
begin
|
53
|
+
EM.run do
|
54
|
+
MSG = "Hello World!"
|
55
|
+
EventMachine.add_timer(0.1) do
|
56
|
+
http = EventMachine::HttpRequest.new('ws://127.0.0.1:12345/').get :timeout => 0
|
57
|
+
http.errback {
|
58
|
+
EM.stop
|
59
|
+
fail
|
60
|
+
}
|
61
|
+
http.callback {
|
62
|
+
http.response_header.status.should == 101
|
63
|
+
EM.stop
|
64
|
+
}
|
65
|
+
end
|
66
|
+
|
67
|
+
Socky.stub!(:options).and_return({:port => 12345})
|
68
|
+
Socky.logger = mock(:logger, :info => nil, :debug => nil)
|
69
|
+
@runner.start
|
70
|
+
end
|
71
|
+
ensure
|
72
|
+
Socky.logger = nil
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
it "#stop should call EM.stop" do
|
78
|
+
begin
|
79
|
+
Socky.logger = mock(:logger, :info => nil, :debug => nil)
|
80
|
+
EM.should_receive(:stop)
|
81
|
+
@runner.stop
|
82
|
+
ensure
|
83
|
+
Socky.logger = nil
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
end
|
data/spec/socky_spec.rb
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Socky do
|
4
|
+
|
5
|
+
context "class" do
|
6
|
+
|
7
|
+
it "should have non-blank version" do
|
8
|
+
Socky::VERSION.should_not be_nil
|
9
|
+
end
|
10
|
+
it "should have options in hash form" do
|
11
|
+
Socky.options.should_not be_nil
|
12
|
+
Socky.options.class.should eql(Hash)
|
13
|
+
end
|
14
|
+
it "should allow to set options" do
|
15
|
+
Socky.options.should eql(Hash.new)
|
16
|
+
begin
|
17
|
+
Socky.options = {:key => :value}
|
18
|
+
Socky.options.should eql({:key => :value})
|
19
|
+
ensure
|
20
|
+
Socky.options = Hash.new
|
21
|
+
end
|
22
|
+
end
|
23
|
+
it "should have logger" do
|
24
|
+
Socky.logger.should_not be_nil
|
25
|
+
Socky.logger.class.should eql(Logger)
|
26
|
+
end
|
27
|
+
it "should have logger with STDOUT at default" do
|
28
|
+
Socky.logger.instance_variable_get('@logdev').dev.class.should eql(IO)
|
29
|
+
end
|
30
|
+
it "should be able to set logger" do
|
31
|
+
begin
|
32
|
+
logger = Logger.new(STDOUT)
|
33
|
+
Socky.logger.should_not equal(logger)
|
34
|
+
Socky.logger = logger
|
35
|
+
Socky.logger.should equal(logger)
|
36
|
+
ensure
|
37
|
+
Socky.logger = nil
|
38
|
+
end
|
39
|
+
end
|
40
|
+
it "should be able to change verbosity of logger by setting debug option" do
|
41
|
+
begin
|
42
|
+
Socky.logger.level.should eql(Logger::INFO)
|
43
|
+
Socky.logger = nil
|
44
|
+
Socky.stub!(:options).and_return({:debug => true})
|
45
|
+
Socky.logger.level.should eql(Logger::DEBUG)
|
46
|
+
Socky.logger = nil
|
47
|
+
Socky.stub!(:options).and_return({:debug => false})
|
48
|
+
Socky.logger.level.should eql(Logger::INFO)
|
49
|
+
ensure
|
50
|
+
Socky.logger = nil
|
51
|
+
end
|
52
|
+
end
|
53
|
+
it "should not have default log path" do
|
54
|
+
Socky.log_path.should be_nil
|
55
|
+
end
|
56
|
+
it "should be able to change log path by settion log_path option" do
|
57
|
+
Socky.stub!(:options).and_return({:log_path => "abstract"})
|
58
|
+
Socky.log_path.should eql("abstract")
|
59
|
+
end
|
60
|
+
it "should be able to change logger write place" do
|
61
|
+
begin
|
62
|
+
Socky.options = {:log_path => File.join(File.dirname(__FILE__), 'files', 'socky.log')}
|
63
|
+
Socky.logger.should_not be_nil
|
64
|
+
Socky.logger.instance_variable_get('@logdev').dev.class.should eql(File)
|
65
|
+
ensure
|
66
|
+
Socky.logger = nil
|
67
|
+
Socky.options = {}
|
68
|
+
end
|
69
|
+
end
|
70
|
+
it "should have default pid path" do
|
71
|
+
Socky.pid_path.should_not be_nil
|
72
|
+
Socky.pid_path.should eql("/var/run/socky.pid")
|
73
|
+
end
|
74
|
+
it "should be able to change pid path by settion pid_path option" do
|
75
|
+
Socky.stub!(:options).and_return({:pid_path => "abstract"})
|
76
|
+
Socky.pid_path.should eql("abstract")
|
77
|
+
end
|
78
|
+
it "should have default config path" do
|
79
|
+
Socky.config_path.should_not be_nil
|
80
|
+
Socky.config_path.should eql("/var/run/socky.yml")
|
81
|
+
end
|
82
|
+
it "should be able to change config path by settion config_path option" do
|
83
|
+
Socky.stub!(:options).and_return({:config_path => "abstract"})
|
84
|
+
Socky.config_path.should eql("abstract")
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
# #--
|
2
|
+
# Includes portion originally Copyright (C)2008 Michael Fellinger
|
3
|
+
# license See file LICENSE for details
|
4
|
+
# #--
|
5
|
+
|
6
|
+
require 'rack'
|
7
|
+
|
8
|
+
module Stallion
|
9
|
+
class Mount
|
10
|
+
def initialize(name, *methods, &block)
|
11
|
+
@name, @methods, @block = name, methods, block
|
12
|
+
end
|
13
|
+
|
14
|
+
def ride
|
15
|
+
@block.call
|
16
|
+
end
|
17
|
+
|
18
|
+
def match?(request)
|
19
|
+
method = request['REQUEST_METHOD']
|
20
|
+
right_method = @methods.empty? or @methods.include?(method)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class Stable
|
25
|
+
attr_reader :request, :response
|
26
|
+
|
27
|
+
def initialize
|
28
|
+
@boxes = {}
|
29
|
+
end
|
30
|
+
|
31
|
+
def in(path, *methods, &block)
|
32
|
+
mount = Mount.new(path, *methods, &block)
|
33
|
+
@boxes[[path, methods]] = mount
|
34
|
+
mount
|
35
|
+
end
|
36
|
+
|
37
|
+
def call(request, response)
|
38
|
+
@request, @response = request, response
|
39
|
+
@boxes.each do |(path, methods), mount|
|
40
|
+
if mount.match?(request)
|
41
|
+
mount.ride
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
STABLES = {}
|
48
|
+
|
49
|
+
def self.saddle(name = nil)
|
50
|
+
STABLES[name] = stable = Stable.new
|
51
|
+
yield stable
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.run(options = {})
|
55
|
+
options = {:Host => "127.0.0.1", :Port => 8080}.merge(options)
|
56
|
+
Rack::Handler::Mongrel.run(Rack::Lint.new(self), options)
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.call(env)
|
60
|
+
request = Rack::Request.new(env)
|
61
|
+
response = Rack::Response.new
|
62
|
+
|
63
|
+
STABLES.each do |name, stable|
|
64
|
+
stable.call(request, response)
|
65
|
+
end
|
66
|
+
|
67
|
+
response.finish
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
Stallion.saddle :spec do |stable|
|
72
|
+
stable.in '/' do
|
73
|
+
|
74
|
+
if stable.request.path_info == '/fail'
|
75
|
+
stable.response.status = 404
|
76
|
+
|
77
|
+
elsif stable.request.path_info == '/timeout'
|
78
|
+
sleep(10)
|
79
|
+
stable.response.write 'timeout'
|
80
|
+
|
81
|
+
elsif
|
82
|
+
stable.response.write 'Hello, World!'
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
Thread.new do
|
89
|
+
begin
|
90
|
+
Stallion.run :Host => '127.0.0.1', :Port => 8765
|
91
|
+
rescue Exception => e
|
92
|
+
print e
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
sleep(1)
|
metadata
ADDED
@@ -0,0 +1,198 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: socky-server
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 15
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 4
|
9
|
+
- 0
|
10
|
+
version: 0.4.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Bernard Potocki
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2010-10-28 00:00:00 +02:00
|
19
|
+
default_executable: socky
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: em-websocket
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 19
|
30
|
+
segments:
|
31
|
+
- 0
|
32
|
+
- 1
|
33
|
+
- 4
|
34
|
+
version: 0.1.4
|
35
|
+
type: :runtime
|
36
|
+
version_requirements: *id001
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: em-http-request
|
39
|
+
prerelease: false
|
40
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ">="
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
hash: 3
|
46
|
+
segments:
|
47
|
+
- 0
|
48
|
+
version: "0"
|
49
|
+
type: :runtime
|
50
|
+
version_requirements: *id002
|
51
|
+
- !ruby/object:Gem::Dependency
|
52
|
+
name: json
|
53
|
+
prerelease: false
|
54
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
55
|
+
none: false
|
56
|
+
requirements:
|
57
|
+
- - ">="
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
hash: 3
|
60
|
+
segments:
|
61
|
+
- 0
|
62
|
+
version: "0"
|
63
|
+
type: :runtime
|
64
|
+
version_requirements: *id003
|
65
|
+
- !ruby/object:Gem::Dependency
|
66
|
+
name: rspec
|
67
|
+
prerelease: false
|
68
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
69
|
+
none: false
|
70
|
+
requirements:
|
71
|
+
- - ~>
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
hash: 3
|
74
|
+
segments:
|
75
|
+
- 2
|
76
|
+
- 0
|
77
|
+
version: "2.0"
|
78
|
+
type: :development
|
79
|
+
version_requirements: *id004
|
80
|
+
- !ruby/object:Gem::Dependency
|
81
|
+
name: rack
|
82
|
+
prerelease: false
|
83
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
84
|
+
none: false
|
85
|
+
requirements:
|
86
|
+
- - ">="
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
hash: 3
|
89
|
+
segments:
|
90
|
+
- 0
|
91
|
+
version: "0"
|
92
|
+
type: :development
|
93
|
+
version_requirements: *id005
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: mongrel
|
96
|
+
prerelease: false
|
97
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
98
|
+
none: false
|
99
|
+
requirements:
|
100
|
+
- - ">="
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
hash: 3
|
103
|
+
segments:
|
104
|
+
- 0
|
105
|
+
version: "0"
|
106
|
+
type: :development
|
107
|
+
version_requirements: *id006
|
108
|
+
description: Socky is a WebSocket server and client for Ruby
|
109
|
+
email: bernard.potocki@imanel.org
|
110
|
+
executables:
|
111
|
+
- socky
|
112
|
+
extensions: []
|
113
|
+
|
114
|
+
extra_rdoc_files:
|
115
|
+
- README.md
|
116
|
+
files:
|
117
|
+
- CHANGELOG.textile
|
118
|
+
- README.md
|
119
|
+
- Rakefile
|
120
|
+
- VERSION
|
121
|
+
- bin/socky
|
122
|
+
- lib/em-websocket_hacks.rb
|
123
|
+
- lib/socky.rb
|
124
|
+
- lib/socky/connection.rb
|
125
|
+
- lib/socky/connection/authentication.rb
|
126
|
+
- lib/socky/connection/finders.rb
|
127
|
+
- lib/socky/message.rb
|
128
|
+
- lib/socky/misc.rb
|
129
|
+
- lib/socky/net_request.rb
|
130
|
+
- lib/socky/options.rb
|
131
|
+
- lib/socky/options/config.rb
|
132
|
+
- lib/socky/options/parser.rb
|
133
|
+
- lib/socky/runner.rb
|
134
|
+
- spec/em-websocket_spec.rb
|
135
|
+
- spec/files/default.yml
|
136
|
+
- spec/files/invalid.yml
|
137
|
+
- spec/socky/connection/authentication_spec.rb
|
138
|
+
- spec/socky/connection/finders_spec.rb
|
139
|
+
- spec/socky/connection_spec.rb
|
140
|
+
- spec/socky/message_spec.rb
|
141
|
+
- spec/socky/misc_spec.rb
|
142
|
+
- spec/socky/net_request_spec.rb
|
143
|
+
- spec/socky/options/config_spec.rb
|
144
|
+
- spec/socky/options/parser_spec.rb
|
145
|
+
- spec/socky/options_spec.rb
|
146
|
+
- spec/socky/runner_spec.rb
|
147
|
+
- spec/socky_spec.rb
|
148
|
+
- spec/spec_helper.rb
|
149
|
+
- spec/support/stallion.rb
|
150
|
+
has_rdoc: true
|
151
|
+
homepage: http://imanel.org/projects/socky
|
152
|
+
licenses: []
|
153
|
+
|
154
|
+
post_install_message:
|
155
|
+
rdoc_options:
|
156
|
+
- --charset=UTF-8
|
157
|
+
require_paths:
|
158
|
+
- lib
|
159
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
160
|
+
none: false
|
161
|
+
requirements:
|
162
|
+
- - ">="
|
163
|
+
- !ruby/object:Gem::Version
|
164
|
+
hash: 3
|
165
|
+
segments:
|
166
|
+
- 0
|
167
|
+
version: "0"
|
168
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
169
|
+
none: false
|
170
|
+
requirements:
|
171
|
+
- - ">="
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
hash: 3
|
174
|
+
segments:
|
175
|
+
- 0
|
176
|
+
version: "0"
|
177
|
+
requirements: []
|
178
|
+
|
179
|
+
rubyforge_project:
|
180
|
+
rubygems_version: 1.3.7
|
181
|
+
signing_key:
|
182
|
+
specification_version: 3
|
183
|
+
summary: Socky is a WebSocket server and client for Ruby
|
184
|
+
test_files:
|
185
|
+
- spec/em-websocket_spec.rb
|
186
|
+
- spec/socky/connection/authentication_spec.rb
|
187
|
+
- spec/socky/connection/finders_spec.rb
|
188
|
+
- spec/socky/connection_spec.rb
|
189
|
+
- spec/socky/message_spec.rb
|
190
|
+
- spec/socky/misc_spec.rb
|
191
|
+
- spec/socky/net_request_spec.rb
|
192
|
+
- spec/socky/options/config_spec.rb
|
193
|
+
- spec/socky/options/parser_spec.rb
|
194
|
+
- spec/socky/options_spec.rb
|
195
|
+
- spec/socky/runner_spec.rb
|
196
|
+
- spec/socky_spec.rb
|
197
|
+
- spec/spec_helper.rb
|
198
|
+
- spec/support/stallion.rb
|