socky-server 0.4.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.
@@ -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