socky-server 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,95 @@
1
+ module Socky
2
+ # default runner class - creates server and runs it
3
+ class Runner
4
+ include Socky::Misc
5
+
6
+ class << self
7
+ # create new eventmachine server
8
+ def run(argv = ARGV)
9
+ server = self.new(argv)
10
+
11
+ if options[:kill]
12
+ server.kill_pid
13
+ elsif options[:daemonize]
14
+ server.daemonize
15
+ else
16
+ server.start
17
+ end
18
+ end
19
+ end
20
+
21
+ # set server-wide options from args
22
+ def initialize(argv = ARGV)
23
+ Options.prepare(argv)
24
+ end
25
+
26
+ # start eventmachine server
27
+ # require options to be parsed earlier
28
+ def start
29
+ EventMachine.epoll
30
+
31
+ EventMachine.run do
32
+
33
+ trap("TERM") { stop }
34
+ trap("INT") { stop }
35
+
36
+ EventMachine::start_server("0.0.0.0", options[:port], EventMachine::WebSocket::Connection,
37
+ :debug => options[:deep_debug], :secure => options[:secure], :tls_options => options[:tls_options]) do |ws|
38
+
39
+ connection = Socky::Connection.new(ws)
40
+ ws.onopen { connection.subscribe }
41
+ ws.onmessage { |msg| connection.process_message(msg) }
42
+ ws.onclose { connection.unsubscribe }
43
+
44
+ end
45
+
46
+ info ["Server started"]
47
+ end
48
+ end
49
+
50
+ # stop eventmachine server
51
+ def stop
52
+ info ["Server stopping"]
53
+ EventMachine.stop
54
+ end
55
+
56
+ # run server in daemon mode
57
+ def daemonize
58
+ fork do
59
+ Process.setsid
60
+ exit if fork
61
+ store_pid(Process.pid)
62
+ # Dir.chdir "/" # Mucks up logs
63
+ File.umask 0000
64
+ STDIN.reopen "/dev/null"
65
+ STDOUT.reopen "/dev/null", "a"
66
+ STDERR.reopen STDOUT
67
+ start
68
+ end
69
+ end
70
+
71
+ # kill daemonized server according to pid file in pid_path
72
+ def kill_pid
73
+ begin
74
+ pid = IO.read(pid_path).chomp.to_i
75
+ FileUtils.rm pid_path
76
+ Process.kill(9, pid)
77
+ puts "killed PID: #{pid}"
78
+ rescue => e
79
+ puts e
80
+ end
81
+ exit
82
+ end
83
+
84
+ private
85
+
86
+ def store_pid(pid)
87
+ FileUtils.mkdir_p(File.dirname(pid_path))
88
+ File.open(pid_path, 'w'){|f| f.write("#{pid}\n")}
89
+ rescue => e
90
+ puts e
91
+ exit
92
+ end
93
+
94
+ end
95
+ end
@@ -0,0 +1,36 @@
1
+ require 'spec_helper'
2
+
3
+ describe EM::WebSocket::Connection do
4
+
5
+ it "should not receive debug message if :debug option is false" do
6
+ EM.run do
7
+ Socky.logger.should_not_receive(:debug)
8
+ EM.add_timer(0.1) do
9
+ http = EventMachine::HttpRequest.new('ws://127.0.0.1:9999/').get(:timeout => 0)
10
+ http.errback { http.close_connection }
11
+ http.callback { http.close_connection }
12
+ end
13
+
14
+ EM::WebSocket.start(:host => "127.0.0.1", :port => 9999, :debug => false) do |ws|
15
+ ws.onclose { EM.stop }
16
+ end
17
+ end
18
+ end
19
+
20
+ it "should use Socky.logger.debug instead of pp when instance call #debug" do
21
+ EM.run do
22
+ Socky.logger.should_receive(:debug).with("Socket initialize")
23
+ Socky.logger.should_receive(:debug).with(anything()).at_least(:once)
24
+ EM.add_timer(0.1) do
25
+ http = EventMachine::HttpRequest.new('ws://127.0.0.1:9999/').get(:timeout => 0)
26
+ http.errback { http.close_connection }
27
+ http.callback { http.close_connection }
28
+ end
29
+
30
+ EM::WebSocket.start(:host => "127.0.0.1", :port => 9999, :debug => true) do |ws|
31
+ ws.onclose { EM.stop }
32
+ end
33
+ end
34
+ end
35
+
36
+ end
@@ -0,0 +1,18 @@
1
+ :port: 8080
2
+ :debug: false
3
+
4
+ # :subscribe_url: http://localhost:3000/socky/subscribe
5
+ # :unsubscribe_url: http://localhost:3000/socky/unsubscribe
6
+
7
+ :secret: my_secret_key
8
+
9
+ :secure: false
10
+
11
+ # :timeout: 3
12
+
13
+ # :log_path: /var/log/socky.log
14
+ # :pid_path: /var/run/socky.pid
15
+
16
+ # :tls_options:
17
+ # :private_key_file: /private/key
18
+ # :cert_chain_file: /ssl/certificate
@@ -0,0 +1 @@
1
+ invalid data
@@ -0,0 +1,183 @@
1
+ require 'spec_helper'
2
+
3
+ describe Socky::Connection::Authentication do
4
+ include Socky::Connection::Authentication
5
+
6
+ context "instance" do
7
+ context "#subscribe_request" do
8
+ before(:each) do
9
+ stub!(:admin).and_return(false)
10
+ stub!(:send_data)
11
+ end
12
+ it "should not call #send_subscribe_request if already authenticated" do
13
+ stub!(:authenticated?).and_return(true)
14
+ should_not_receive(:send_subscribe_request)
15
+ subscribe_request
16
+ end
17
+ it "should call #send_subscribe_request if unauthenticated" do
18
+ stub!(:authenticated?).and_return(false)
19
+ should_receive(:send_subscribe_request)
20
+ subscribe_request
21
+ end
22
+ it "should add self to connection list if #send_subscribe_request block is true" do
23
+ EM.run do
24
+ stub!(:authenticated?).and_return(false)
25
+ stub!(:send_subscribe_request).and_yield(true)
26
+ should_receive(:add_to_pool)
27
+ subscribe_request
28
+ EM.stop
29
+ end
30
+ end
31
+ it "should be authenticated by url if #send_subscribe_request block is true" do
32
+ EM.run do
33
+ stub!(:authenticated?).and_return(false)
34
+ stub!(:send_subscribe_request).and_yield(true)
35
+ stub!(:add_to_pool)
36
+ subscribe_request
37
+ authenticated_by_url?.should be_true
38
+ EM.stop
39
+ end
40
+ end
41
+ it "should disconnect if #send_subscribe_request block is false" do
42
+ EM.run do
43
+ stub!(:send_subscribe_request).and_yield(false)
44
+ should_receive(:disconnect)
45
+ subscribe_request
46
+ EM.add_timer(0.1) do
47
+ EM.stop
48
+ end
49
+ end
50
+ end
51
+ end
52
+ context "#unsubscribe_request" do
53
+ it "should remove self from connection list if authenticated" do
54
+ stub!(:admin).and_return(false)
55
+ stub!(:authenticated?).and_return(true)
56
+ should_receive(:remove_from_pool)
57
+ unsubscribe_request
58
+ end
59
+ it "should send unsubscribe request if authenticated but not admin" do
60
+ stub!(:admin).and_return(false)
61
+ stub!(:authenticated?).and_return(true)
62
+ stub!(:remove_from_pool)
63
+ should_receive(:send_unsubscribe_request)
64
+ unsubscribe_request
65
+ end
66
+ it "should not send unsubscribe request if authenticated and admin" do
67
+ stub!(:admin).and_return(true)
68
+ stub!(:authenticated?).and_return(true)
69
+ stub!(:remove_from_pool)
70
+ should_not_receive(:send_unsubscribe_request)
71
+ unsubscribe_request
72
+ end
73
+ it "should not send unsubscribe request if unauthenticated" do
74
+ stub!(:authenticated?).and_return(false)
75
+ should_not_receive(:send_unsubscribe_request)
76
+ unsubscribe_request
77
+ end
78
+ end
79
+ context "#authenticated?" do
80
+ it "should authenticate as admin if admin" do
81
+ stub!(:admin).and_return(true)
82
+ should_receive(:authenticate_as_admin)
83
+ authenticated?
84
+ end
85
+ it "should authenticate as user if not admin" do
86
+ stub!(:admin).and_return(false)
87
+ should_receive(:authenticate_as_user)
88
+ authenticated?
89
+ end
90
+ end
91
+ context "#authenticate_as_admin" do
92
+ it "should return true if client secret is equal server secret" do
93
+ stub!(:secret).and_return("test")
94
+ Socky.stub!(:options).and_return({:secret => "test"})
95
+ authenticate_as_admin.should be_true
96
+ end
97
+ it "should return false if client secret is not equal server secret" do
98
+ stub!(:secret).and_return("abstract")
99
+ Socky.stub!(:options).and_return({:secret => "test"})
100
+ authenticate_as_admin.should be_false
101
+ end
102
+ it "should return true if server secret is nil" do
103
+ stub!(:secret).and_return("abstract")
104
+ Socky.stub!(:options).and_return({:secret => nil})
105
+ authenticate_as_admin.should be_true
106
+ end
107
+ end
108
+ it "#authenticate_as_user should call #authenticated_by_url?" do
109
+ should_receive(:authenticated_by_url?)
110
+ authenticate_as_user
111
+ end
112
+ it "#authenticated_by_url? should return current status" do
113
+ instance_variable_set('@authenticated_by_url',true)
114
+ authenticated_by_url?.should be_true
115
+ instance_variable_set('@authenticated_by_url',false)
116
+ authenticated_by_url?.should be_false
117
+ end
118
+ context "#send_subscribe_request" do
119
+ it "should build params for request if socky option subscribe_url is not nil" do
120
+ Socky.stub!(:options).and_return({:subscribe_url => "any"})
121
+ should_receive(:params_for_request)
122
+ send_subscribe_request
123
+ end
124
+ it "should call Socky::NetRequest#post if socky option subscribe_url is not nil" do
125
+ Socky.stub!(:options).and_return({:subscribe_url => "any"})
126
+ stub!(:params_for_request)
127
+ Socky::NetRequest.should_receive(:post)
128
+ send_subscribe_request
129
+ end
130
+ it "should not call Socky::NetRequest#post if socky option subscribe_url is nil" do
131
+ Socky.stub!(:options).and_return({:subscribe_url => nil})
132
+ Socky::NetRequest.should_not_receive(:post)
133
+ send_subscribe_request{}
134
+ end
135
+ end
136
+ context "#send_unsubscribe_request" do
137
+ it "should build params for request if socky option unsubscribe_url is not nil" do
138
+ Socky.stub!(:options).and_return({:unsubscribe_url => "any"})
139
+ should_receive(:params_for_request)
140
+ send_unsubscribe_request{}
141
+ end
142
+ it "should call Socky::NetRequest#post if socky option unsubscribe_url is not nil" do
143
+ Socky.stub!(:options).and_return({:unsubscribe_url => "any"})
144
+ stub!(:params_for_request)
145
+ Socky::NetRequest.should_receive(:post)
146
+ send_unsubscribe_request{}
147
+ end
148
+ it "should not call Socky::NetRequest#post if socky option unsubscribe_url is nil" do
149
+ Socky.stub!(:options).and_return({:unsubscribe_url => nil})
150
+ Socky::NetRequest.should_not_receive(:post)
151
+ send_unsubscribe_request{}
152
+ end
153
+ end
154
+ context "#params_for_request" do
155
+ before(:each) do
156
+ stub!(:client)
157
+ stub!(:secret)
158
+ stub!(:channels).and_return([])
159
+ end
160
+ it "should return empty hash if none of (client,secret,channels) are set" do
161
+ params_for_request.should eql({})
162
+ end
163
+ it "should return client as client_id if set" do
164
+ stub!(:client).and_return("some client")
165
+ params_for_request.should eql({:client_id => "some client"})
166
+ end
167
+ it "should return secret as client_secret if set" do
168
+ stub!(:secret).and_return("some secret")
169
+ params_for_request.should eql({:client_secret => "some secret"})
170
+ end
171
+ it "should return channels if not empty" do
172
+ stub!(:channels).and_return(["some channel"])
173
+ params_for_request.should eql({:channels => ["some channel"]})
174
+ end
175
+ it "should return client, secret and channels as hash if all are set" do
176
+ stub!(:client).and_return("some client")
177
+ stub!(:secret).and_return("some secret")
178
+ stub!(:channels).and_return(["some channel"])
179
+ params_for_request.should eql({:client_id => "some client", :client_secret => "some secret", :channels => ["some channel"]})
180
+ end
181
+ end
182
+ end
183
+ end
@@ -0,0 +1,188 @@
1
+ require 'spec_helper'
2
+
3
+ describe Socky::Connection::Finders do
4
+ include Socky::Connection::Finders
5
+ include Socky::Misc
6
+
7
+ context "class" do
8
+ before(:each) do
9
+ @connection1 = mock(:connection1, :client => "client1", :channels => [nil])
10
+ @connection2 = mock(:connection2, :client => "client1", :channels => ["1", "3", "5"])
11
+ @connection3 = mock(:connection3, :client => "client2", :channels => ["2", "5"])
12
+ @connection4 = mock(:connection4, :client => "client3", :channels => ["3", "5"])
13
+ @connections = [@connection1,@connection2,@connection3,@connection4]
14
+ @connections.collect { |connection| Socky::Connection.connections << connection }
15
+ end
16
+ after(:each) do
17
+ Socky::Connection.connections.clear
18
+ end
19
+
20
+ it "#find_all should return all connections" do
21
+ find_all.should eql(@connections)
22
+ end
23
+ context "#find" do
24
+ it "should return all connections if no options specified" do
25
+ find.should eql(@connections)
26
+ end
27
+ context "on :to" do
28
+ context "if :clients option is specified" do
29
+ it "should return all connections if :clients is nil" do
30
+ find(:to => {:clients => nil}).should eql(@connections)
31
+ end
32
+ it "should return none connections if :clients is empty" do
33
+ find(:to => {:clients => []}).should eql([])
34
+ end
35
+ it "should return only connections from specified client" do
36
+ find(:to => {:clients => "client1"}).should eql([@connection1,@connection2])
37
+ end
38
+ it "should return only connections from specified clients if array provided" do
39
+ find(:to => {:clients => ["client1","client2"]}).should eql([@connection1,@connection2,@connection3])
40
+ end
41
+ end
42
+ context "if :channels option is specified" do
43
+ it "should return all connections if :channels is nil" do
44
+ find(:to => {:channels => nil}).should eql(@connections)
45
+ end
46
+ it "should return none connections if :channels is empty" do
47
+ find(:to => {:channels => []}).should eql([])
48
+ end
49
+ it "should return all connections that include specified channel" do
50
+ find(:to => {:channels => "3"}).should eql([@connection2,@connection4])
51
+ end
52
+ it "should return all connections that include at last one of specified channels" do
53
+ find(:to => {:channels => ["2","3"]}).should eql([@connection2,@connection3,@connection4])
54
+ end
55
+ end
56
+ context "if both :clients and :channels options are provided" do
57
+ context "but :channels are nil" do
58
+ it "should return only connections from specified client" do
59
+ find(:to => {:channels => nil,:clients => "client1"}).should eql([@connection1,@connection2])
60
+ end
61
+ it "should return only connections from specified clients if array provided" do
62
+ find(:to => {:channels => nil,:clients => ["client1","client2"]}).should eql([@connection1,@connection2,@connection3])
63
+ end
64
+ end
65
+ context "but :channels are empty" do
66
+ it "should return none connections" do
67
+ find(:to => {:channels => [],:clients => "client1"}).should eql([])
68
+ end
69
+ it "should return none connections if array provided" do
70
+ find(:to => {:channels => [],:clients => ["client1","client2"]}).should eql([])
71
+ end
72
+ end
73
+ context "but :clients are nil" do
74
+ it "should return all connections that include specified channel" do
75
+ find(:to => {:clients => nil,:channels => "3"}).should eql([@connection2,@connection4])
76
+ end
77
+ it "should return all connections that include at last one of specified channels" do
78
+ find(:to => {:clients => nil,:channels => ["2","3"]}).should eql([@connection2,@connection3,@connection4])
79
+ end
80
+ end
81
+ context "but :clients are empty" do
82
+ it "should return none connections" do
83
+ find(:to => {:clients => [],:channels => "3"}).should eql([])
84
+ end
85
+ it "should return none connections if array provided" do
86
+ find(:to => {:clients => [],:channels => ["2","3"]}).should eql([])
87
+ end
88
+ end
89
+ it "should return only connections from specified client that include specified channel" do
90
+ find(:to => {:clients => "client1",:channels => "3"}).should eql([@connection2])
91
+ find(:to => {:clients => "client1",:channels => "2"}).should eql([])
92
+ end
93
+ it "should return only connections from specified client that include one of specified channels" do
94
+ find(:to => {:clients => "client1",:channels => ["2","3"]}).should eql([@connection2])
95
+ end
96
+ it "should return only connections from specified clients that include specified channel" do
97
+ find(:to => {:clients => ["client1","client2"],:channels => "2"}).should eql([@connection3])
98
+ end
99
+ it "should return only connections from specified clients that include at last one of specified channels" do
100
+ find(:to => {:clients => ["client1","client2"],:channels => ["2","1"]}).should eql([@connection2,@connection3])
101
+ end
102
+ end
103
+ end
104
+
105
+ context "on :except" do
106
+ context "if :clients option is specified" do
107
+ it "should return all connections if :clients is nil" do
108
+ find(:except => {:clients => nil}).should eql(@connections)
109
+ end
110
+ it "should return all connections if :clients is empty" do
111
+ find(:except => {:clients => []}).should eql(@connections)
112
+ end
113
+ it "should return all connections except of specified client" do
114
+ find(:except => {:clients => "client1"}).should eql([@connection3,@connection4])
115
+ end
116
+ it "should return all connections except of specified clients if array provided" do
117
+ find(:except => {:clients => ["client1","client2"]}).should eql([@connection4])
118
+ end
119
+ end
120
+ context "if :channels option is specified" do
121
+ it "should return all connections if :channels is nil" do
122
+ find(:except => {:channels => nil}).should eql(@connections)
123
+ end
124
+ it "should return all connections if :channels is empty" do
125
+ find(:except => {:channels => []}).should eql(@connections)
126
+ end
127
+ it "should return all connections except of that include all specified channels" do
128
+ find(:except => {:channels => ["2","5"]}).should eql([@connection1,@connection2,@connection4])
129
+ end
130
+ end
131
+ context "if both :clients and :channels options are provided" do
132
+ context "but :channels are nil" do
133
+ it "should return all connections except of specified client" do
134
+ find(:except => {:channels => nil,:clients => "client1"}).should eql([@connection3,@connection4])
135
+ end
136
+ it "should return all connections except of specified clients if array provided" do
137
+ find(:except => {:channels => nil,:clients => ["client1","client2"]}).should eql([@connection4])
138
+ end
139
+ end
140
+ context "but :channels are empty" do
141
+ it "should return all connections except of specified client" do
142
+ find(:except => {:channels => [],:clients => "client1"}).should eql([@connection3,@connection4])
143
+ end
144
+ it "should return all connections except of provided clients if array provided" do
145
+ find(:except => {:channels => [],:clients => ["client1","client2"]}).should eql([@connection4])
146
+ end
147
+ end
148
+ context "but :clients are nil" do
149
+ it "should return all connections except of that include all of specified channels" do
150
+ find(:except => {:clients => nil,:channels => ["2","5"]}).should eql([@connection1,@connection2,@connection4])
151
+ end
152
+ end
153
+ context "but :clients are empty" do
154
+ it "should return all connections except of that include all of specified channels " do
155
+ find(:except => {:clients => [],:channels => ["2","5"]}).should eql([@connection1,@connection2,@connection4])
156
+ end
157
+ end
158
+ it "should return all connections except of specified client or all specified channels" do
159
+ find(:except => {:clients => "client2",:channels => "3"}).should eql([@connection1,@connection2,@connection4])
160
+ find(:except => {:clients => "client2",:channels => ["3","5"]}).should eql([@connection1,@connection2])
161
+ end
162
+ it "should return only connections from specified clients that include specified channel" do
163
+ find(:except => {:clients => ["client1","client2"],:channels => "3"}).should eql([@connection4])
164
+ find(:except => {:clients => ["client1","client2"],:channels => ["3","5"]}).should eql([])
165
+ end
166
+ end
167
+ end
168
+
169
+ context "on :to and :except" do
170
+ context "should value 'except' more that 'to'" do
171
+ it "on :client" do
172
+ find(:to => {:clients => "client1"},:except => {:clients => "client1"}).should eql([])
173
+ end
174
+ it "on :channels" do
175
+ find(:to => {:channels => "5"},:except => {:channels => "5"}).should eql([])
176
+ end
177
+ it "on :client allow and :channels except" do
178
+ find(:to => {:clients => "client2"},:except => {:channels => ["2","5"]}).should eql([])
179
+ end
180
+ it "on :channels allow and :clients except" do
181
+ find(:to => {:channels => ["5"]},:except => {:clients => "client2"}).should eql([@connection2,@connection4])
182
+ end
183
+ end
184
+ end
185
+ end
186
+
187
+ end
188
+ end