websocket-rails 0.3.0 → 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.
- data/CHANGELOG.md +41 -0
- data/README.md +1 -1
- data/lib/generators/websocket_rails/install/templates/events.rb +15 -5
- data/lib/rails/tasks/websocket_rails.tasks +8 -10
- data/lib/spec_helpers/matchers/route_matchers.rb +2 -1
- data/lib/spec_helpers/spec_helper_event.rb +4 -0
- data/lib/websocket-rails.rb +50 -73
- data/lib/websocket_rails/base_controller.rb +9 -7
- data/lib/websocket_rails/channel.rb +8 -1
- data/lib/websocket_rails/channel_manager.rb +6 -0
- data/lib/websocket_rails/configuration.rb +112 -0
- data/lib/websocket_rails/connection_adapters.rb +13 -4
- data/lib/websocket_rails/connection_manager.rb +3 -2
- data/lib/websocket_rails/controller_factory.rb +70 -0
- data/lib/websocket_rails/data_store.rb +128 -62
- data/lib/websocket_rails/dispatcher.rb +17 -16
- data/lib/websocket_rails/event.rb +12 -2
- data/lib/websocket_rails/event_map.rb +6 -41
- data/lib/websocket_rails/internal_events.rb +0 -7
- data/lib/websocket_rails/logging.rb +103 -14
- data/lib/websocket_rails/synchronization.rb +6 -8
- data/lib/websocket_rails/version.rb +1 -1
- data/spec/dummy/app/controllers/chat_controller.rb +6 -14
- data/spec/dummy/log/test.log +0 -750
- data/spec/integration/connection_manager_spec.rb +8 -1
- data/spec/spec_helper.rb +3 -16
- data/spec/spec_helpers/matchers/route_matchers_spec.rb +2 -11
- data/spec/spec_helpers/matchers/trigger_matchers_spec.rb +2 -12
- data/spec/unit/channel_manager_spec.rb +8 -0
- data/spec/unit/channel_spec.rb +16 -2
- data/spec/unit/connection_adapters_spec.rb +32 -11
- data/spec/unit/controller_factory_spec.rb +63 -0
- data/spec/unit/data_store_spec.rb +91 -24
- data/spec/unit/dispatcher_spec.rb +6 -11
- data/spec/unit/event_map_spec.rb +17 -27
- data/spec/unit/event_spec.rb +14 -0
- data/spec/unit/logging_spec.rb +122 -17
- metadata +11 -6
data/CHANGELOG.md
CHANGED
@@ -1,19 +1,60 @@
|
|
1
1
|
# WebsocketRails Change Log
|
2
2
|
|
3
|
+
February 27 2013
|
4
|
+
|
5
|
+
## Version 0.4.0
|
6
|
+
|
7
|
+
__There have been a few breaking changes in the public API since the
|
8
|
+
last release. Please review the list below and consult the Wiki for more
|
9
|
+
information regarding the usage of the new features.__
|
10
|
+
|
11
|
+
* Controller instances no longer persist between events that are
|
12
|
+
triggered. Each event is processed by a new controller instance,
|
13
|
+
similar to a standard Rails request. Since you can no longer use
|
14
|
+
instance variables to temporarily persist data between events, there is
|
15
|
+
a new Controller Data Store that can be used for this purpose. This
|
16
|
+
change addresses issue #31.
|
17
|
+
|
18
|
+
* The original DataStore class has been deprecated. In it's place are
|
19
|
+
the new Controller Data Store and Connection Data Store. As mentioned
|
20
|
+
above, the Controller Data Store can be used to persist data between
|
21
|
+
events in much the same way that you would use instance variables. The
|
22
|
+
Connection Data Store acts like the Rails session store. Use it to store
|
23
|
+
data private to a connection. Data in the Connection Data Store can be
|
24
|
+
accessed from any controller. Check out the Wiki for more information on
|
25
|
+
both.
|
26
|
+
|
27
|
+
* The `websocket_rails.reload_controllers` event has been deprecated.
|
28
|
+
The new Controller instantiation model allows for automatic controller
|
29
|
+
class reloading while in the development environment. You no longer
|
30
|
+
need to trigger an event to pick up code changes in controllers while
|
31
|
+
connections are active.
|
32
|
+
|
33
|
+
* Real logging support has _finally_ been implemented. Check out the
|
34
|
+
configuration WIki for more information on the various logging options
|
35
|
+
available.
|
36
|
+
|
3
37
|
## Version 0.3.0
|
4
38
|
|
39
|
+
February 6 2013
|
40
|
+
|
5
41
|
* Extend the event router DSL to accept routes similar to the routes.rb
|
6
42
|
shorthand `controller#action`. - Thanks to @nessche.
|
43
|
+
|
7
44
|
* Add a custom RSpec matcher suite for verifying event routes
|
8
45
|
and easily asserting that WebsocketRails controller actions are
|
9
46
|
triggering events correctly. - Also thanks to @nessche.
|
47
|
+
|
10
48
|
* Fix fiber yielded across threads bug when running in standalone mode
|
11
49
|
by disabling Thin threaded mode as default option.
|
12
50
|
|
13
51
|
## Version 0.2.1
|
14
52
|
|
53
|
+
January 29 2013
|
54
|
+
|
15
55
|
* Fix default redis driver issue that was causing problems when using
|
16
56
|
redis while event machine was not running.
|
57
|
+
|
17
58
|
* Fix undefined data store value issue. Thanks to @burninggramma.
|
18
59
|
|
19
60
|
## Version 0.2.0
|
data/README.md
CHANGED
@@ -203,7 +203,7 @@ Read the [Private Channel Wiki](https://github.com/DanKnox/websocket-rails/wiki/
|
|
203
203
|
private channels from the JavaScript client and handling the
|
204
204
|
authorization in your controller.
|
205
205
|
|
206
|
-
## Credit where credit is due
|
206
|
+
## Credit where credit is due
|
207
207
|
|
208
208
|
Big thanks to our
|
209
209
|
[contributors](https://github.com/DanKnox/websocket-rails/graphs/contributors)
|
@@ -1,21 +1,31 @@
|
|
1
1
|
WebsocketRails.setup do |config|
|
2
2
|
|
3
|
-
#
|
4
|
-
|
3
|
+
# Uncomment to override the default log level. The log level can be
|
4
|
+
# any of the standard Logger log levels. By default it will mirror the
|
5
|
+
# current Rails environment log level.
|
6
|
+
# config.log_level = :debug
|
7
|
+
|
8
|
+
# Uncomment to change the default log file path.
|
9
|
+
# config.log_path = "#{Rails.root}/log/websocket_rails.log"
|
10
|
+
|
11
|
+
# Set to true if you wish to log the internal websocket_rails events
|
12
|
+
# such as the keepalive `websocket_rails.ping` event.
|
13
|
+
# config.log_internal_events = false
|
5
14
|
|
6
15
|
# Change to true to enable standalone server mode
|
7
16
|
# Start the standalone server with rake websocket_rails:start_server
|
8
|
-
# Requires Redis
|
17
|
+
# * Requires Redis
|
9
18
|
config.standalone = false
|
10
19
|
|
11
20
|
# Change to true to enable channel synchronization between
|
12
|
-
# multiple server instances.
|
21
|
+
# multiple server instances.
|
22
|
+
# * Requires Redis.
|
13
23
|
config.synchronize = false
|
14
24
|
|
15
25
|
# Uncomment and edit to point to a different redis instance.
|
16
26
|
# Will not be used unless standalone or synchronization mode
|
17
27
|
# is enabled.
|
18
|
-
#config.redis_options = {:host => 'localhost', :port => '6379'}
|
28
|
+
# config.redis_options = {:host => 'localhost', :port => '6379'}
|
19
29
|
end
|
20
30
|
|
21
31
|
WebsocketRails::EventMap.describe do
|
@@ -1,14 +1,12 @@
|
|
1
1
|
namespace :websocket_rails do
|
2
|
-
desc '
|
2
|
+
desc 'Start the WebsocketRails standalone server.'
|
3
3
|
task :start_server do
|
4
4
|
require "thin"
|
5
5
|
load "#{Rails.root}/config/initializers/events.rb"
|
6
6
|
|
7
|
-
options = WebsocketRails.thin_options
|
7
|
+
options = WebsocketRails.config.thin_options
|
8
8
|
|
9
|
-
|
10
|
-
warn_standalone_not_enabled!
|
11
|
-
end
|
9
|
+
warn_if_standalone_not_enabled!
|
12
10
|
|
13
11
|
fork do
|
14
12
|
Thin::Controllers::Controller.new(options).start
|
@@ -17,21 +15,21 @@ namespace :websocket_rails do
|
|
17
15
|
puts "Websocket Rails Standalone Server listening on port #{options[:port]}"
|
18
16
|
end
|
19
17
|
|
18
|
+
desc 'Stop the WebsocketRails standalone server.'
|
20
19
|
task :stop_server do
|
21
20
|
require "thin"
|
22
21
|
load "#{Rails.root}/config/initializers/events.rb"
|
23
22
|
|
24
|
-
options = WebsocketRails.thin_options
|
23
|
+
options = WebsocketRails.config.thin_options
|
25
24
|
|
26
|
-
|
27
|
-
warn_standalone_not_enabled!
|
28
|
-
end
|
25
|
+
warn_if_standalone_not_enabled!
|
29
26
|
|
30
27
|
Thin::Controllers::Controller.new(options).stop
|
31
28
|
end
|
32
29
|
end
|
33
30
|
|
34
|
-
def
|
31
|
+
def warn_if_standalone_not_enabled!
|
32
|
+
return if WebsocketRails.standalone?
|
35
33
|
puts "Fail!"
|
36
34
|
puts "You must enable standalone mode in your events.rb initializer to use the standalone server."
|
37
35
|
exit 1
|
@@ -9,8 +9,9 @@ module WebsocketRails
|
|
9
9
|
|
10
10
|
result = false
|
11
11
|
no_of_routes = 0
|
12
|
-
event.dispatcher.event_map.routes_for event do |
|
12
|
+
event.dispatcher.event_map.routes_for event do |controller_class, method|
|
13
13
|
no_of_routes += 1
|
14
|
+
controller = controller_class.new
|
14
15
|
if controller.class == target_class and method == target_method
|
15
16
|
result = true
|
16
17
|
end
|
data/lib/websocket-rails.rb
CHANGED
@@ -1,92 +1,41 @@
|
|
1
1
|
require "active_support/dependencies"
|
2
|
-
require
|
2
|
+
require "logger"
|
3
|
+
require "thin"
|
3
4
|
|
4
5
|
module WebsocketRails
|
5
|
-
mattr_accessor :app_root
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
def self.route_block=(routes)
|
12
|
-
@event_routes = routes
|
13
|
-
end
|
14
|
-
|
15
|
-
def self.route_block
|
16
|
-
@event_routes
|
17
|
-
end
|
7
|
+
class << self
|
8
|
+
def setup
|
9
|
+
yield config
|
10
|
+
end
|
18
11
|
|
19
|
-
|
20
|
-
|
21
|
-
|
12
|
+
def config
|
13
|
+
@config ||= Configuration.new
|
14
|
+
end
|
22
15
|
|
23
|
-
|
24
|
-
|
25
|
-
|
16
|
+
def synchronize?
|
17
|
+
config.synchronize == true || config.standalone == true
|
18
|
+
end
|
26
19
|
|
27
|
-
|
28
|
-
|
20
|
+
def standalone?
|
21
|
+
config.standalone == true
|
22
|
+
end
|
29
23
|
|
30
|
-
|
31
|
-
|
24
|
+
def logger
|
25
|
+
config.logger
|
26
|
+
end
|
32
27
|
end
|
33
28
|
|
34
|
-
def self.redis_options
|
35
|
-
@redis_options ||= redis_defaults
|
36
|
-
end
|
37
|
-
|
38
|
-
def self.redis_options=(options = {})
|
39
|
-
@redis_options = redis_defaults.merge(options)
|
40
|
-
end
|
41
|
-
|
42
|
-
def self.redis_defaults
|
43
|
-
{:host => '127.0.0.1', :port => 6379, :driver => :synchrony}
|
44
|
-
end
|
45
|
-
|
46
|
-
attr_accessor :standalone
|
47
|
-
module_function :standalone, :standalone=
|
48
|
-
|
49
|
-
def self.standalone?
|
50
|
-
@standalone == true
|
51
|
-
end
|
52
|
-
|
53
|
-
def self.standalone_port
|
54
|
-
@standalone_port ||= '3001'
|
55
|
-
end
|
56
|
-
|
57
|
-
def self.standalone_port=(port)
|
58
|
-
@standalone_port = port
|
59
|
-
end
|
60
|
-
|
61
|
-
def self.thin_options
|
62
|
-
@thin_options ||= thin_defaults
|
63
|
-
end
|
64
|
-
|
65
|
-
def self.thin_options=(options = {})
|
66
|
-
@thin_options = thin_defaults.merge(options)
|
67
|
-
end
|
68
|
-
|
69
|
-
def self.thin_defaults
|
70
|
-
{
|
71
|
-
:port => standalone_port,
|
72
|
-
:pid => "#{Rails.root}/tmp/pids/websocket_rails.pid",
|
73
|
-
:log => "#{Rails.root}/log/websocket_rails.log",
|
74
|
-
:tag => 'websocket_rails',
|
75
|
-
:rackup => "#{Rails.root}/config.ru",
|
76
|
-
:threaded => false,
|
77
|
-
:daemonize => true,
|
78
|
-
:dirname => Rails.root,
|
79
|
-
:max_persistent_conns => 1024,
|
80
|
-
:max_conns => 1024
|
81
|
-
}
|
82
|
-
end
|
83
29
|
end
|
84
30
|
|
85
31
|
require 'websocket_rails/engine'
|
32
|
+
|
33
|
+
require 'websocket_rails/configuration'
|
86
34
|
require 'websocket_rails/logging'
|
87
35
|
require 'websocket_rails/synchronization'
|
88
36
|
require 'websocket_rails/connection_manager'
|
89
37
|
require 'websocket_rails/dispatcher'
|
38
|
+
require 'websocket_rails/controller_factory'
|
90
39
|
require 'websocket_rails/event'
|
91
40
|
require 'websocket_rails/event_map'
|
92
41
|
require 'websocket_rails/event_queue'
|
@@ -99,13 +48,41 @@ require 'websocket_rails/connection_adapters'
|
|
99
48
|
require 'websocket_rails/connection_adapters/http'
|
100
49
|
require 'websocket_rails/connection_adapters/web_socket'
|
101
50
|
|
51
|
+
|
102
52
|
# Exceptions
|
103
|
-
class InvalidConnectionError < StandardError
|
53
|
+
class WebsocketRails::InvalidConnectionError < StandardError
|
104
54
|
def rack_response
|
105
55
|
[400,{'Content-Type' => 'text/plain'},['invalid connection']]
|
106
56
|
end
|
107
57
|
end
|
108
58
|
|
59
|
+
class WebsocketRails::EventRoutingError < StandardError
|
60
|
+
|
61
|
+
attr_reader :event, :controller, :method
|
62
|
+
|
63
|
+
def initialize(event, controller, method)
|
64
|
+
@event = event
|
65
|
+
@controller = controller
|
66
|
+
end
|
67
|
+
|
68
|
+
def to_s
|
69
|
+
out = "Routing Error:\n"
|
70
|
+
out << "Event: #{event.name}\n"
|
71
|
+
out << "Controller #{controller.class} does not respond to #{method}"
|
72
|
+
out
|
73
|
+
end
|
74
|
+
|
75
|
+
def to_json
|
76
|
+
super({
|
77
|
+
error: "EventRoutingError",
|
78
|
+
event: event.name,
|
79
|
+
method: method,
|
80
|
+
reason: "Controller #{controller.class} does not respond to #{method}"
|
81
|
+
})
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
|
109
86
|
# Deprecation Notices
|
110
87
|
class WebsocketRails::Dispatcher
|
111
88
|
def self.describe_events(&block)
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require "websocket_rails/data_store"
|
2
2
|
|
3
3
|
module WebsocketRails
|
4
4
|
# Provides controller helper methods for developing a WebsocketRails controller. Action methods
|
@@ -18,6 +18,8 @@ module WebsocketRails
|
|
18
18
|
#
|
19
19
|
class BaseController
|
20
20
|
|
21
|
+
# Tell Rails that BaseController and children can be reloaded when in
|
22
|
+
# the Development environment.
|
21
23
|
def self.inherited(controller)
|
22
24
|
unloadable controller
|
23
25
|
end
|
@@ -49,10 +51,6 @@ module WebsocketRails
|
|
49
51
|
# Stores the observer Procs for the current controller. See {observe} for details.
|
50
52
|
@@observers = Hash.new {|h,k| h[k] = Array.new}
|
51
53
|
|
52
|
-
def initialize
|
53
|
-
@data_store = DataStore.new(self)
|
54
|
-
end
|
55
|
-
|
56
54
|
# Provides direct access to the connection object for the client that
|
57
55
|
# initiated the event that is currently being executed.
|
58
56
|
def connection
|
@@ -142,8 +140,12 @@ module WebsocketRails
|
|
142
140
|
# Provides access to the {DataStore} for the current controller. The {DataStore} provides convenience
|
143
141
|
# methods for keeping track of data associated with active connections. See it's documentation for
|
144
142
|
# more information.
|
145
|
-
def
|
146
|
-
@
|
143
|
+
def controller_store
|
144
|
+
@_controller_store
|
145
|
+
end
|
146
|
+
|
147
|
+
def connection_store
|
148
|
+
connection.data_store
|
147
149
|
end
|
148
150
|
|
149
151
|
private
|
@@ -12,10 +12,16 @@ module WebsocketRails
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def subscribe(connection)
|
15
|
-
|
15
|
+
info "#{connection} subscribed to channel #{name}"
|
16
16
|
@subscribers << connection
|
17
17
|
end
|
18
18
|
|
19
|
+
def unsubscribe(connection)
|
20
|
+
return unless @subscribers.include? connection
|
21
|
+
info "#{connection} unsubscribed from channel #{name}"
|
22
|
+
@subscribers.delete connection
|
23
|
+
end
|
24
|
+
|
19
25
|
def trigger(event_name,data={},options={})
|
20
26
|
options.merge! :channel => name
|
21
27
|
options[:data] = data
|
@@ -26,6 +32,7 @@ module WebsocketRails
|
|
26
32
|
end
|
27
33
|
|
28
34
|
def trigger_event(event)
|
35
|
+
info "(processing_channel_event) name: #{event.name} namespace: #{event.namespace} connection: #{event.connection.id}"
|
29
36
|
send_data event
|
30
37
|
end
|
31
38
|
|
@@ -0,0 +1,112 @@
|
|
1
|
+
module WebsocketRails
|
2
|
+
class Configuration
|
3
|
+
|
4
|
+
def route_block=(routes)
|
5
|
+
@event_routes = routes
|
6
|
+
end
|
7
|
+
|
8
|
+
def route_block
|
9
|
+
@event_routes
|
10
|
+
end
|
11
|
+
|
12
|
+
def log_level
|
13
|
+
@log_level ||= begin
|
14
|
+
case Rails.env.to_sym
|
15
|
+
when :production then :info
|
16
|
+
when :development then :debug
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def log_level=(level)
|
22
|
+
@log_level = level
|
23
|
+
end
|
24
|
+
|
25
|
+
def logger
|
26
|
+
@logger ||= begin
|
27
|
+
logger = Logger.new(log_path)
|
28
|
+
Logging.configure(logger)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def logger=(logger)
|
33
|
+
@logger = logger
|
34
|
+
end
|
35
|
+
|
36
|
+
def log_path
|
37
|
+
@log_path ||= "#{Rails.root}/log/websocket_rails.log"
|
38
|
+
end
|
39
|
+
|
40
|
+
def log_path=(path)
|
41
|
+
@log_path = path
|
42
|
+
end
|
43
|
+
|
44
|
+
def log_internal_events?
|
45
|
+
@log_internal_events ||= false
|
46
|
+
end
|
47
|
+
|
48
|
+
def log_internal_events=(value)
|
49
|
+
@log_internal_events = value
|
50
|
+
end
|
51
|
+
|
52
|
+
def synchronize
|
53
|
+
@synchronize ||= false
|
54
|
+
end
|
55
|
+
|
56
|
+
def synchronize=(synchronize)
|
57
|
+
@synchronize = synchronize
|
58
|
+
end
|
59
|
+
|
60
|
+
def redis_options
|
61
|
+
@redis_options ||= redis_defaults
|
62
|
+
end
|
63
|
+
|
64
|
+
def redis_options=(options = {})
|
65
|
+
@redis_options = redis_defaults.merge(options)
|
66
|
+
end
|
67
|
+
|
68
|
+
def redis_defaults
|
69
|
+
{:host => '127.0.0.1', :port => 6379, :driver => :synchrony}
|
70
|
+
end
|
71
|
+
|
72
|
+
def standalone
|
73
|
+
@standalone ||= false
|
74
|
+
end
|
75
|
+
|
76
|
+
def standalone=(standalone)
|
77
|
+
@standalone = standalone
|
78
|
+
end
|
79
|
+
|
80
|
+
def standalone_port
|
81
|
+
@standalone_port ||= '3001'
|
82
|
+
end
|
83
|
+
|
84
|
+
def standalone_port=(port)
|
85
|
+
@standalone_port = port
|
86
|
+
end
|
87
|
+
|
88
|
+
def thin_options
|
89
|
+
@thin_options ||= thin_defaults
|
90
|
+
end
|
91
|
+
|
92
|
+
def thin_options=(options = {})
|
93
|
+
@thin_options = thin_defaults.merge(options)
|
94
|
+
end
|
95
|
+
|
96
|
+
def thin_defaults
|
97
|
+
{
|
98
|
+
:port => standalone_port,
|
99
|
+
:pid => "#{Rails.root}/tmp/pids/websocket_rails.pid",
|
100
|
+
:log => "#{Rails.root}/log/websocket_rails_server.log",
|
101
|
+
:tag => 'websocket_rails',
|
102
|
+
:rackup => "#{Rails.root}/config.ru",
|
103
|
+
:threaded => false,
|
104
|
+
:daemonize => true,
|
105
|
+
:dirname => Rails.root,
|
106
|
+
:max_persistent_conns => 1024,
|
107
|
+
:max_conns => 1024
|
108
|
+
}
|
109
|
+
end
|
110
|
+
|
111
|
+
end
|
112
|
+
end
|