socker 0.0.2 → 0.0.3
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/lib/socker.rb +48 -25
- data/lib/socker/event_handlers.rb +11 -1
- data/lib/socker/helper.rb +17 -1
- metadata +1 -1
data/lib/socker.rb
CHANGED
@@ -23,6 +23,7 @@ module Socker
|
|
23
23
|
WEBSOCKET_STANDARD_EVENTS.each(®ister_handler(c, env))
|
24
24
|
end
|
25
25
|
end
|
26
|
+
# This is needed for Puma so we can log the requests to WebSockets
|
26
27
|
@application.class.instance_eval {
|
27
28
|
define_method(:log) { |message| Socker::App.log(message) }
|
28
29
|
}
|
@@ -30,34 +31,56 @@ module Socker
|
|
30
31
|
@application
|
31
32
|
end
|
32
33
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
34
|
+
# Helper method your application can use to register new handlers
|
35
|
+
# Supported events handlers are:
|
36
|
+
#
|
37
|
+
# * open - The connection was succesfully established
|
38
|
+
# * close - The connection was closed
|
39
|
+
# * error - An error occured on the client side
|
40
|
+
# * message - A message was received from the socket
|
41
|
+
#
|
42
|
+
# Handler could be anything that implements the .call method, like
|
43
|
+
# lambda, Proc or Method...
|
44
|
+
#
|
43
45
|
def on(event, handler)
|
44
46
|
@events ||= {}
|
47
|
+
raise "Unable register handler for unsupported event: #{event}" unless event_supported?(event)
|
45
48
|
@events[event] ||= lambda { |socket, ev| handler.call(socket, ev) }
|
46
49
|
end
|
47
50
|
|
51
|
+
# A method used for mounting the application to Rack:
|
52
|
+
#
|
53
|
+
# run Rack::URLMap.new('/' => MyServer.new.to_app)
|
54
|
+
#
|
48
55
|
def to_app
|
49
56
|
@application
|
50
57
|
end
|
51
58
|
|
59
|
+
# The default logging destination for the application.
|
60
|
+
# If you want to use custom logging or logging to a file, you can override
|
61
|
+
# this method.
|
62
|
+
#
|
52
63
|
def self.log(message, level=:info)
|
53
64
|
@log ||= Logger.new($stdout)
|
54
65
|
@log.send(level, message)
|
55
66
|
end
|
56
67
|
|
57
|
-
def log(message)
|
68
|
+
def log(message)
|
69
|
+
self.class.log(message)
|
70
|
+
end
|
58
71
|
|
59
72
|
private
|
60
73
|
|
74
|
+
def connection(env, opts={}, &block)
|
75
|
+
conn = Faye::WebSocket.new(env)
|
76
|
+
yield conn if block_given?
|
77
|
+
conn.rack_response
|
78
|
+
end
|
79
|
+
|
80
|
+
def event_supported?(event)
|
81
|
+
true if WEBSOCKET_STANDARD_EVENTS.include?(event.to_sym)
|
82
|
+
end
|
83
|
+
|
61
84
|
def is_websocket?(env)
|
62
85
|
Faye::WebSocket.websocket?(env)
|
63
86
|
end
|
@@ -67,24 +90,24 @@ module Socker
|
|
67
90
|
end
|
68
91
|
|
69
92
|
def handle_with(event, opts={})
|
70
|
-
if events[event]
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
end
|
93
|
+
return method(:handle_missing) if !events[event]
|
94
|
+
current_class = self.class
|
95
|
+
lambda do |ev|
|
96
|
+
@env = Rack::Request.new(opts[:env])
|
97
|
+
begin
|
98
|
+
handle(event, opts[:socket])
|
99
|
+
events[event].call(opts[:socket], ev)
|
100
|
+
rescue => error
|
101
|
+
current_class.log("[#{error.class}] #{error.message}\n#{error.backtrace.join("\n")}", :error)
|
80
102
|
end
|
81
|
-
else
|
82
|
-
method(:handle_undefined)
|
83
103
|
end
|
84
104
|
end
|
85
105
|
|
86
|
-
|
87
|
-
|
106
|
+
# When the browser sent an event which has no handler defined, show an error
|
107
|
+
# message in the log, but don't crash the application.
|
108
|
+
#
|
109
|
+
def handle_missing(event)
|
110
|
+
self.class.log("WARNING: I dont know how to handle the '#{event.type}' event.", :error)
|
88
111
|
end
|
89
112
|
|
90
113
|
end
|
@@ -2,18 +2,28 @@ module Socker
|
|
2
2
|
|
3
3
|
module EventHandlers
|
4
4
|
|
5
|
+
# The list of active connections.
|
6
|
+
# This list is used for 'broadcasting' messages to all active connections
|
7
|
+
#
|
5
8
|
def connections
|
6
9
|
@connections ||= []
|
7
10
|
end
|
8
11
|
|
12
|
+
# When a new connection is opened, we save it into the list
|
13
|
+
# of connections (so methods like 'broadcast' works). Also the :when_active
|
14
|
+
# callback is executed when this is a first connection.
|
15
|
+
#
|
9
16
|
def on_open(connection)
|
10
17
|
@callbacks[:when_active].call if connections.empty? and @callbacks[:when_active]
|
11
18
|
connections << connection
|
12
19
|
end
|
13
20
|
|
21
|
+
# When connection is closed, we remove it from the connections list and
|
22
|
+
# execute the :when_idle callback.
|
23
|
+
#
|
14
24
|
def on_close(connection)
|
15
25
|
connections.delete(connection)
|
16
|
-
@callbacks[:when_idle].call if connections.empty? and @callbacks[:
|
26
|
+
@callbacks[:when_idle].call if connections.empty? and @callbacks[:when_idle]
|
17
27
|
end
|
18
28
|
|
19
29
|
def handle(event, connection)
|
data/lib/socker/helper.rb
CHANGED
@@ -2,14 +2,30 @@ module Socker
|
|
2
2
|
|
3
3
|
module Helper
|
4
4
|
|
5
|
+
# This function send an broadcast message to all active connections.
|
6
|
+
# The message must be String (but you can sent a JSON, etc..)
|
7
|
+
#
|
5
8
|
def broadcast(message)
|
6
|
-
connections.each
|
9
|
+
connections.each do |c|
|
10
|
+
begin
|
11
|
+
c.send(message)
|
12
|
+
rescue => error
|
13
|
+
log("ERROR: Connection #{c} seems invalid, ignoring. (#{error.message})")
|
14
|
+
end
|
15
|
+
end
|
7
16
|
end
|
8
17
|
|
18
|
+
# If the protocol support PING, you can send this to all clients and when
|
19
|
+
# they replied with PONG message, you can handle that with callback.
|
20
|
+
#
|
9
21
|
def pbroadcast(message, callback)
|
10
22
|
connections.each { |c| c.ping(message, &callback) }
|
11
23
|
end
|
12
24
|
|
25
|
+
# Provide access to the Rack params used for WebSocket connection, ie:
|
26
|
+
#
|
27
|
+
# socket = new Socket('ws://' + location.hostname + ':' + '9292' + '/?param1=value')
|
28
|
+
#
|
13
29
|
def params
|
14
30
|
@env.params
|
15
31
|
end
|