wwl-websocket-rails 0.7.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (120) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +328 -0
  3. data/Gemfile +27 -0
  4. data/MIT-LICENSE +20 -0
  5. data/README.md +239 -0
  6. data/Rakefile +72 -0
  7. data/bin/thin-socketrails +45 -0
  8. data/lib/assets/javascripts/websocket_rails/abstract_connection.js.coffee +45 -0
  9. data/lib/assets/javascripts/websocket_rails/channel.js.coffee +70 -0
  10. data/lib/assets/javascripts/websocket_rails/event.js.coffee +46 -0
  11. data/lib/assets/javascripts/websocket_rails/http_connection.js.coffee +66 -0
  12. data/lib/assets/javascripts/websocket_rails/main.js +6 -0
  13. data/lib/assets/javascripts/websocket_rails/websocket_connection.js.coffee +29 -0
  14. data/lib/assets/javascripts/websocket_rails/websocket_rails.js.coffee +158 -0
  15. data/lib/config.ru +3 -0
  16. data/lib/generators/websocket_rails/install/install_generator.rb +33 -0
  17. data/lib/generators/websocket_rails/install/templates/events.rb +14 -0
  18. data/lib/generators/websocket_rails/install/templates/websocket_rails.rb +68 -0
  19. data/lib/rails/app/controllers/websocket_rails/delegation_controller.rb +13 -0
  20. data/lib/rails/config/routes.rb +7 -0
  21. data/lib/rails/tasks/websocket_rails.tasks +42 -0
  22. data/lib/spec_helpers/matchers/route_matchers.rb +65 -0
  23. data/lib/spec_helpers/matchers/trigger_matchers.rb +138 -0
  24. data/lib/spec_helpers/spec_helper_event.rb +34 -0
  25. data/lib/websocket-rails.rb +108 -0
  26. data/lib/websocket_rails/base_controller.rb +208 -0
  27. data/lib/websocket_rails/channel.rb +97 -0
  28. data/lib/websocket_rails/channel_manager.rb +55 -0
  29. data/lib/websocket_rails/configuration.rb +177 -0
  30. data/lib/websocket_rails/connection_adapters/http.rb +120 -0
  31. data/lib/websocket_rails/connection_adapters/web_socket.rb +35 -0
  32. data/lib/websocket_rails/connection_adapters.rb +195 -0
  33. data/lib/websocket_rails/connection_manager.rb +119 -0
  34. data/lib/websocket_rails/controller_factory.rb +80 -0
  35. data/lib/websocket_rails/data_store.rb +145 -0
  36. data/lib/websocket_rails/dispatcher.rb +129 -0
  37. data/lib/websocket_rails/engine.rb +26 -0
  38. data/lib/websocket_rails/event.rb +193 -0
  39. data/lib/websocket_rails/event_map.rb +184 -0
  40. data/lib/websocket_rails/event_queue.rb +33 -0
  41. data/lib/websocket_rails/internal_events.rb +37 -0
  42. data/lib/websocket_rails/logging.rb +133 -0
  43. data/lib/websocket_rails/spec_helpers.rb +3 -0
  44. data/lib/websocket_rails/synchronization.rb +178 -0
  45. data/lib/websocket_rails/user_manager.rb +276 -0
  46. data/lib/websocket_rails/version.rb +3 -0
  47. data/spec/dummy/Rakefile +7 -0
  48. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  49. data/spec/dummy/app/controllers/chat_controller.rb +53 -0
  50. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  51. data/spec/dummy/app/models/user.rb +2 -0
  52. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  53. data/spec/dummy/config/application.rb +45 -0
  54. data/spec/dummy/config/boot.rb +10 -0
  55. data/spec/dummy/config/database.yml +22 -0
  56. data/spec/dummy/config/environment.rb +5 -0
  57. data/spec/dummy/config/environments/development.rb +26 -0
  58. data/spec/dummy/config/environments/production.rb +49 -0
  59. data/spec/dummy/config/environments/test.rb +34 -0
  60. data/spec/dummy/config/events.rb +7 -0
  61. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  62. data/spec/dummy/config/initializers/inflections.rb +10 -0
  63. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  64. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  65. data/spec/dummy/config/initializers/session_store.rb +8 -0
  66. data/spec/dummy/config/locales/en.yml +5 -0
  67. data/spec/dummy/config/routes.rb +58 -0
  68. data/spec/dummy/config.ru +4 -0
  69. data/spec/dummy/db/development.sqlite3 +0 -0
  70. data/spec/dummy/db/migrate/20130902222552_create_users.rb +10 -0
  71. data/spec/dummy/db/schema.rb +23 -0
  72. data/spec/dummy/db/test.sqlite3 +0 -0
  73. data/spec/dummy/log/development.log +17 -0
  74. data/spec/dummy/log/production.log +0 -0
  75. data/spec/dummy/log/server.log +0 -0
  76. data/spec/dummy/log/test.log +0 -0
  77. data/spec/dummy/public/404.html +26 -0
  78. data/spec/dummy/public/422.html +26 -0
  79. data/spec/dummy/public/500.html +26 -0
  80. data/spec/dummy/public/favicon.ico +0 -0
  81. data/spec/dummy/public/javascripts/application.js +2 -0
  82. data/spec/dummy/public/javascripts/controls.js +965 -0
  83. data/spec/dummy/public/javascripts/dragdrop.js +974 -0
  84. data/spec/dummy/public/javascripts/effects.js +1123 -0
  85. data/spec/dummy/public/javascripts/prototype.js +6001 -0
  86. data/spec/dummy/public/javascripts/rails.js +202 -0
  87. data/spec/dummy/script/rails +6 -0
  88. data/spec/integration/connection_manager_spec.rb +135 -0
  89. data/spec/javascripts/support/jasmine.yml +52 -0
  90. data/spec/javascripts/support/jasmine_helper.rb +38 -0
  91. data/spec/javascripts/support/vendor/sinon-1.7.1.js +4343 -0
  92. data/spec/javascripts/websocket_rails/channel_spec.coffee +112 -0
  93. data/spec/javascripts/websocket_rails/event_spec.coffee +81 -0
  94. data/spec/javascripts/websocket_rails/helpers.coffee +6 -0
  95. data/spec/javascripts/websocket_rails/websocket_connection_spec.coffee +158 -0
  96. data/spec/javascripts/websocket_rails/websocket_rails_spec.coffee +273 -0
  97. data/spec/spec_helper.rb +41 -0
  98. data/spec/spec_helpers/matchers/route_matchers_spec.rb +109 -0
  99. data/spec/spec_helpers/matchers/trigger_matchers_spec.rb +358 -0
  100. data/spec/spec_helpers/spec_helper_event_spec.rb +66 -0
  101. data/spec/support/helper_methods.rb +42 -0
  102. data/spec/support/mock_web_socket.rb +41 -0
  103. data/spec/unit/base_controller_spec.rb +74 -0
  104. data/spec/unit/channel_manager_spec.rb +58 -0
  105. data/spec/unit/channel_spec.rb +169 -0
  106. data/spec/unit/connection_adapters/http_spec.rb +88 -0
  107. data/spec/unit/connection_adapters/web_socket_spec.rb +30 -0
  108. data/spec/unit/connection_adapters_spec.rb +259 -0
  109. data/spec/unit/connection_manager_spec.rb +148 -0
  110. data/spec/unit/controller_factory_spec.rb +76 -0
  111. data/spec/unit/data_store_spec.rb +106 -0
  112. data/spec/unit/dispatcher_spec.rb +203 -0
  113. data/spec/unit/event_map_spec.rb +120 -0
  114. data/spec/unit/event_queue_spec.rb +36 -0
  115. data/spec/unit/event_spec.rb +181 -0
  116. data/spec/unit/logging_spec.rb +162 -0
  117. data/spec/unit/synchronization_spec.rb +150 -0
  118. data/spec/unit/target_validator_spec.rb +88 -0
  119. data/spec/unit/user_manager_spec.rb +165 -0
  120. metadata +320 -0
@@ -0,0 +1,45 @@
1
+ #!/usr/bin/env ruby
2
+ # * Borrowed from the <tt>websocket-rack</tt>
3
+ # Gem as a temporary workaround for the
4
+ # timeout problem.
5
+ #
6
+ # Modified Thin command line interface script.
7
+ # This is fallback for WebSocket-Rack.
8
+ # Use it when you have EventMachine version < 1.0.0
9
+ # Rationale:
10
+ # Older versions of EM have bug that prevent to
11
+ # clearing connection inactivity once it's set.
12
+ # This one will set connection timeout to 0 at
13
+ # default, so there will be no need to overwrite it.
14
+ # Be aware that this will also change inactivity
15
+ # timeout for "normal" connection, so it will be
16
+ # easy to make DoS attack.
17
+
18
+ require 'rubygems'
19
+ require 'thin'
20
+
21
+ puts <<END
22
+ *** Deprecation Notice***
23
+
24
+ The thin-socketrails executable is now deprecated and
25
+ will be removed in the next release.
26
+
27
+ You may use the regular thin executable to launch the
28
+ server now.
29
+
30
+ Other EventMachine based web servers should now be
31
+ supported but have not yet been tested.
32
+
33
+ *************************
34
+ END
35
+
36
+ if EM::VERSION < "1.0.0"
37
+ begin
38
+ old_verbose, $VERBOSE = $VERBOSE, nil
39
+ ::Thin::Server.const_set 'DEFAULT_TIMEOUT', 0
40
+ ensure
41
+ $VERBOSE = old_verbose
42
+ end
43
+ end
44
+
45
+ Thin::Runner.new(ARGV).run!
@@ -0,0 +1,45 @@
1
+ ###
2
+ Abstract Interface for the WebSocketRails client.
3
+ ###
4
+ class WebSocketRails.AbstractConnection
5
+
6
+ constructor: (url, @dispatcher) ->
7
+ @message_queue = []
8
+
9
+ close: ->
10
+
11
+ trigger: (event) ->
12
+ if @dispatcher.state != 'connected'
13
+ @message_queue.push event
14
+ else
15
+ @send_event event
16
+
17
+ send_event: (event) ->
18
+ # Events queued before connecting do not have the correct
19
+ # connection_id set yet. We need to update it before dispatching.
20
+ event.connection_id = @connection_id if @connection_id?
21
+
22
+ # ...
23
+
24
+ on_close: (event) ->
25
+ if @dispatcher && @dispatcher._conn == @
26
+ close_event = new WebSocketRails.Event(['connection_closed', event])
27
+ @dispatcher.state = 'disconnected'
28
+ @dispatcher.dispatch close_event
29
+
30
+ on_error: (event) ->
31
+ if @dispatcher && @dispatcher._conn == @
32
+ error_event = new WebSocketRails.Event(['connection_error', event])
33
+ @dispatcher.state = 'disconnected'
34
+ @dispatcher.dispatch error_event
35
+
36
+ on_message: (event_data) ->
37
+ if @dispatcher && @dispatcher._conn == @
38
+ @dispatcher.new_message event_data
39
+
40
+ setConnectionId: (@connection_id) ->
41
+
42
+ flush_queue: ->
43
+ for event in @message_queue
44
+ @trigger event
45
+ @message_queue = []
@@ -0,0 +1,70 @@
1
+ ###
2
+ The channel object is returned when you subscribe to a channel.
3
+
4
+ For instance:
5
+ var dispatcher = new WebSocketRails('localhost:3000/websocket');
6
+ var awesome_channel = dispatcher.subscribe('awesome_channel');
7
+ awesome_channel.bind('event', function(data) { console.log('channel event!'); });
8
+ awesome_channel.trigger('awesome_event', awesome_object);
9
+
10
+ If you want to unbind an event, you can use the unbind function :
11
+ awesome_channel.unbind('event')
12
+ ###
13
+ class WebSocketRails.Channel
14
+
15
+ constructor: (@name, @_dispatcher, @is_private = false, @on_success, @on_failure) ->
16
+ @_callbacks = {}
17
+ @_token = undefined
18
+ @_queue = []
19
+ if @is_private
20
+ event_name = 'websocket_rails.subscribe_private'
21
+ else
22
+ event_name = 'websocket_rails.subscribe'
23
+
24
+ @connection_id = @_dispatcher._conn?.connection_id
25
+ event = new WebSocketRails.Event( [event_name, {data: {channel: @name}}, @connection_id], @_success_launcher, @_failure_launcher)
26
+ @_dispatcher.trigger_event event
27
+
28
+ destroy: ->
29
+ if @connection_id == @_dispatcher._conn?.connection_id
30
+ event_name = 'websocket_rails.unsubscribe'
31
+ event = new WebSocketRails.Event( [event_name, {data: {channel: @name}}, @connection_id] )
32
+ @_dispatcher.trigger_event event
33
+ @_callbacks = {}
34
+
35
+ bind: (event_name, callback) ->
36
+ @_callbacks[event_name] ?= []
37
+ @_callbacks[event_name].push callback
38
+
39
+ unbind: (event_name) ->
40
+ delete @_callbacks[event_name]
41
+
42
+ trigger: (event_name, message) ->
43
+ event = new WebSocketRails.Event( [event_name, {channel: @name, data: message, token: @_token}, @connection_id] )
44
+ if !@_token
45
+ @_queue.push event
46
+ else
47
+ @_dispatcher.trigger_event event
48
+
49
+ dispatch: (event_name, message) ->
50
+ if event_name == 'websocket_rails.channel_token'
51
+ @connection_id = @_dispatcher._conn?.connection_id
52
+ @_token = message['token']
53
+ @flush_queue()
54
+ else
55
+ return unless @_callbacks[event_name]?
56
+ for callback in @_callbacks[event_name]
57
+ callback message
58
+
59
+ # using this method because @on_success will not be defined when the constructor is executed
60
+ _success_launcher: (data) =>
61
+ @on_success(data) if @on_success?
62
+
63
+ # using this method because @on_failure will not be defined when the constructor is executed
64
+ _failure_launcher: (data) =>
65
+ @on_failure(data) if @on_failure?
66
+
67
+ flush_queue: ->
68
+ for event in @_queue
69
+ @_dispatcher.trigger_event event
70
+ @_queue = []
@@ -0,0 +1,46 @@
1
+ ###
2
+ The Event object stores all the relevant event information.
3
+ ###
4
+
5
+ class WebSocketRails.Event
6
+
7
+ SUCCEEDED: 0
8
+ FAILED: 1
9
+ FINISHED_WITHOUT_FAILURE: 2
10
+
11
+ constructor: (data, @success_callback, @failure_callback) ->
12
+ @name = data[0]
13
+ attr = data[1]
14
+ if attr?
15
+ @id = if attr['id']? then attr['id'] else (((1+Math.random())*0x10000)|0)
16
+ @channel = if attr.channel? then attr.channel
17
+ @data = if attr.data? then attr.data else attr
18
+ @token = if attr.token? then attr.token
19
+ @connection_id = data[2]
20
+ if attr.success?
21
+ @result = true
22
+ @success = attr.success
23
+
24
+ is_channel: ->
25
+ @channel?
26
+
27
+ is_result: ->
28
+ typeof @result != 'undefined'
29
+
30
+ is_ping: ->
31
+ @name == 'websocket_rails.ping'
32
+
33
+ serialize: ->
34
+ JSON.stringify [@name, @attributes()]
35
+
36
+ attributes: ->
37
+ id: @id,
38
+ channel: @channel,
39
+ data: @data
40
+ token: @token
41
+
42
+ run_callbacks: (@success, @result) ->
43
+ if @success == @SUCCEEDED
44
+ @success_callback?(@result)
45
+ else if @success == @FAILED
46
+ @failure_callback?(@result)
@@ -0,0 +1,66 @@
1
+ ###
2
+ HTTP Interface for the WebSocketRails client.
3
+ ###
4
+ class WebSocketRails.HttpConnection extends WebSocketRails.AbstractConnection
5
+ connection_type: 'http'
6
+
7
+ _httpFactories: -> [
8
+ -> new XDomainRequest(),
9
+ -> new XMLHttpRequest(),
10
+ -> new ActiveXObject("Msxml2.XMLHTTP"),
11
+ -> new ActiveXObject("Msxml3.XMLHTTP"),
12
+ -> new ActiveXObject("Microsoft.XMLHTTP")
13
+ ]
14
+
15
+ constructor: (url, @dispatcher) ->
16
+ super
17
+ @_url = "http://#{url}"
18
+ @_conn = @_createXMLHttpObject()
19
+ @last_pos = 0
20
+ try
21
+ @_conn.onreadystatechange = => @_parse_stream()
22
+ @_conn.addEventListener("load", @on_close, false)
23
+ catch e
24
+ @_conn.onprogress = => @_parse_stream()
25
+ @_conn.onload = @on_close
26
+ # set this as 3 always for parse_stream as the object does not have this property at all
27
+ @_conn.readyState = 3
28
+ @_conn.open "GET", @_url, true
29
+ @_conn.send()
30
+
31
+ close: ->
32
+ @_conn.abort()
33
+
34
+ send_event: (event) ->
35
+ super
36
+ @_post_data event.serialize()
37
+
38
+ _post_data: (payload) ->
39
+ $.ajax @_url,
40
+ type: 'POST'
41
+ data:
42
+ client_id: @connection_id
43
+ data: payload
44
+ success: ->
45
+
46
+ _createXMLHttpObject: ->
47
+ xmlhttp = false
48
+ factories = @_httpFactories()
49
+ for factory in factories
50
+ try
51
+ xmlhttp = factory()
52
+ catch e
53
+ continue
54
+ break
55
+ xmlhttp
56
+
57
+ _parse_stream: ->
58
+ if @_conn.readyState == 3
59
+ data = @_conn.responseText.substring @last_pos
60
+ @last_pos = @_conn.responseText.length
61
+ data = data.replace( /\]\]\[\[/g, "],[" )
62
+ try
63
+ event_data = JSON.parse data
64
+ @on_message(event_data)
65
+ catch e
66
+ # just ignore if it cannot be parsed, probably whitespace
@@ -0,0 +1,6 @@
1
+ //= require ./websocket_rails
2
+ //= require ./event
3
+ //= require ./abstract_connection
4
+ //= require ./http_connection
5
+ //= require ./websocket_connection
6
+ //= require ./channel
@@ -0,0 +1,29 @@
1
+ ###
2
+ WebSocket Interface for the WebSocketRails client.
3
+ ###
4
+ class WebSocketRails.WebSocketConnection extends WebSocketRails.AbstractConnection
5
+ connection_type: 'websocket'
6
+
7
+ constructor: (@url, @dispatcher) ->
8
+ super
9
+ if @url.match(/^wss?:\/\//)
10
+ console.log "WARNING: Using connection urls with protocol specified is depricated"
11
+ else if window.location.protocol == 'https:'
12
+ @url = "wss://#{@url}"
13
+ else
14
+ @url = "ws://#{@url}"
15
+ @_conn = new WebSocket(@url)
16
+ @_conn.onmessage = (event) =>
17
+ event_data = JSON.parse event.data
18
+ @on_message(event_data)
19
+ @_conn.onclose = (event) =>
20
+ @on_close(event)
21
+ @_conn.onerror = (event) =>
22
+ @on_error(event)
23
+
24
+ close: ->
25
+ @_conn.close()
26
+
27
+ send_event: (event) ->
28
+ super
29
+ @_conn.send event.serialize()
@@ -0,0 +1,158 @@
1
+ ###
2
+ WebsocketRails JavaScript Client
3
+
4
+ Setting up the dispatcher:
5
+ var dispatcher = new WebSocketRails('localhost:3000/websocket');
6
+ dispatcher.on_open = function() {
7
+ // trigger a server event immediately after opening connection
8
+ dispatcher.trigger('new_user',{user_name: 'guest'});
9
+ })
10
+
11
+ Triggering a new event on the server
12
+ dispatcherer.trigger('event_name',object_to_be_serialized_to_json);
13
+
14
+ Listening for new events from the server
15
+ dispatcher.bind('event_name', function(data) {
16
+ console.log(data.user_name);
17
+ });
18
+
19
+ Stop listening for new events from the server
20
+ dispatcher.unbind('event')
21
+ ###
22
+ class @WebSocketRails
23
+ constructor: (@url, @use_websockets = true) ->
24
+ @callbacks = {}
25
+ @channels = {}
26
+ @queue = {}
27
+
28
+ @connect()
29
+
30
+ connect: ->
31
+ @state = 'connecting'
32
+
33
+ unless @supports_websockets() and @use_websockets
34
+ @_conn = new WebSocketRails.HttpConnection @url, @
35
+ else
36
+ @_conn = new WebSocketRails.WebSocketConnection @url, @
37
+
38
+ @_conn.new_message = @new_message
39
+
40
+ disconnect: ->
41
+ if @_conn
42
+ @_conn.close()
43
+ delete @_conn._conn
44
+ delete @_conn
45
+
46
+ @state = 'disconnected'
47
+
48
+ # Reconnects the whole connection,
49
+ # keeping the messages queue and its' connected channels.
50
+ #
51
+ # After successfull connection, this will:
52
+ # - reconnect to all channels, that were active while disconnecting
53
+ # - resend all events from which we haven't received any response yet
54
+ reconnect: =>
55
+ old_connection_id = @_conn?.connection_id
56
+
57
+ @disconnect()
58
+ @connect()
59
+
60
+ # Resend all unfinished events from the previous connection.
61
+ for id, event of @queue
62
+ if event.connection_id == old_connection_id && !event.is_result()
63
+ @trigger_event event
64
+
65
+ @reconnect_channels()
66
+
67
+ new_message: (data) =>
68
+ for socket_message in data
69
+ event = new WebSocketRails.Event( socket_message )
70
+ if event.is_result()
71
+ @queue[event.id]?.run_callbacks(event.success, event.data)
72
+ delete @queue[event.id]
73
+ else if event.is_channel()
74
+ @dispatch_channel event
75
+ else if event.is_ping()
76
+ @pong()
77
+ else
78
+ @dispatch event
79
+
80
+ if @state == 'connecting' and event.name == 'client_connected'
81
+ @connection_established event.data
82
+
83
+ connection_established: (data) =>
84
+ @state = 'connected'
85
+ @_conn.setConnectionId(data.connection_id)
86
+ @_conn.flush_queue()
87
+ if @on_open?
88
+ @on_open(data)
89
+
90
+ bind: (event_name, callback) =>
91
+ @callbacks[event_name] ?= []
92
+ @callbacks[event_name].push callback
93
+
94
+ unbind: (event_name) =>
95
+ delete @callbacks[event_name]
96
+
97
+ trigger: (event_name, data, success_callback, failure_callback) =>
98
+ event = new WebSocketRails.Event( [event_name, data, @_conn?.connection_id], success_callback, failure_callback )
99
+ @trigger_event event
100
+
101
+ trigger_event: (event) =>
102
+ @queue[event.id] ?= event # Prevent replacing an event that has callbacks stored
103
+ @_conn.trigger event if @_conn
104
+ event
105
+
106
+ dispatch: (event) =>
107
+ return unless @callbacks[event.name]?
108
+ for callback in @callbacks[event.name]
109
+ callback event.data
110
+
111
+ subscribe: (channel_name, success_callback, failure_callback) =>
112
+ unless @channels[channel_name]?
113
+ channel = new WebSocketRails.Channel channel_name, @, false, success_callback, failure_callback
114
+ @channels[channel_name] = channel
115
+ channel
116
+ else
117
+ @channels[channel_name]
118
+
119
+ subscribe_private: (channel_name, success_callback, failure_callback) =>
120
+ unless @channels[channel_name]?
121
+ channel = new WebSocketRails.Channel channel_name, @, true, success_callback, failure_callback
122
+ @channels[channel_name] = channel
123
+ channel
124
+ else
125
+ @channels[channel_name]
126
+
127
+ unsubscribe: (channel_name) =>
128
+ return unless @channels[channel_name]?
129
+ @channels[channel_name].destroy()
130
+ delete @channels[channel_name]
131
+
132
+ dispatch_channel: (event) =>
133
+ return unless @channels[event.channel]?
134
+ @channels[event.channel].dispatch event.name, event.data
135
+
136
+ supports_websockets: =>
137
+ (typeof(WebSocket) == "function" or typeof(WebSocket) == "object")
138
+
139
+ pong: =>
140
+ pong = new WebSocketRails.Event( ['websocket_rails.pong', {}, @_conn?.connection_id] )
141
+ @_conn.trigger pong
142
+
143
+ connection_stale: =>
144
+ @state != 'connected'
145
+
146
+ # Destroy and resubscribe to all existing @channels.
147
+ reconnect_channels: ->
148
+ for name, channel of @channels
149
+ callbacks = channel._callbacks
150
+ channel.destroy()
151
+ delete @channels[name]
152
+
153
+ channel = if channel.is_private
154
+ @subscribe_private name
155
+ else
156
+ @subscribe name
157
+ channel._callbacks = callbacks
158
+ channel
data/lib/config.ru ADDED
@@ -0,0 +1,3 @@
1
+ require "websocket-rails"
2
+
3
+ run WebsocketRails::ConnectionManager.new
@@ -0,0 +1,33 @@
1
+ require 'rails'
2
+
3
+ module WebsocketRails
4
+ module Generators
5
+ class InstallGenerator < Rails::Generators::Base
6
+ source_root File.expand_path("../templates", __FILE__)
7
+
8
+ desc "Create the events.rb initializer and require the JS client in the application.js manifest."
9
+
10
+ class_option :manifest, :type => :string, :aliases => "-m", :default => 'application.js',
11
+ :desc => "Javascript manifest file to modify (or create)"
12
+
13
+ def create_events_initializer_file
14
+ template 'events.rb', File.join('config', 'events.rb')
15
+ template 'websocket_rails.rb', File.join('config', 'initializers', 'websocket_rails.rb')
16
+ end
17
+
18
+ def inject_websocket_rails_client
19
+ manifest = options[:manifest]
20
+ js_path = "app/assets/javascripts"
21
+
22
+ create_file("#{js_path}/#{manifest}") unless File.exists?("#{js_path}/#{manifest}")
23
+
24
+ append_to_file "#{js_path}/#{manifest}" do
25
+ out = ""
26
+ out << "//= require websocket_rails/main"
27
+ out << "\n"
28
+ out << "\n"
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,14 @@
1
+ WebsocketRails::EventMap.describe do
2
+ # You can use this file to map incoming events to controller actions.
3
+ # One event can be mapped to any number of controller actions. The
4
+ # actions will be executed in the order they were subscribed.
5
+ #
6
+ # Uncomment and edit the next line to handle the client connected event:
7
+ # subscribe :client_connected, :to => Controller, :with_method => :method_name
8
+ #
9
+ # Here is an example of mapping namespaced events:
10
+ # namespace :product do
11
+ # subscribe :new, :to => ProductController, :with_method => :new_product
12
+ # end
13
+ # The above will handle an event triggered on the client like `product.new`.
14
+ end
@@ -0,0 +1,68 @@
1
+ WebsocketRails.setup do |config|
2
+
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
14
+
15
+ # Change to true to enable standalone server mode
16
+ # Start the standalone server with rake websocket_rails:start_server
17
+ # * Requires Redis
18
+ config.standalone = false
19
+
20
+ # Change to true to enable channel synchronization between
21
+ # multiple server instances.
22
+ # * Requires Redis.
23
+ config.synchronize = false
24
+
25
+ # Prevent Thin from daemonizing (default is true)
26
+ # config.daemonize = false
27
+
28
+ # Uncomment and edit to point to a different redis instance.
29
+ # Will not be used unless standalone or synchronization mode
30
+ # is enabled.
31
+ # config.redis_options = {:host => 'localhost', :port => '6379'}
32
+
33
+ # By default, all subscribers in to a channel will be removed
34
+ # when that channel is made private. If you don't wish active
35
+ # subscribers to be removed from a previously public channel
36
+ # when making it private, set the following to true.
37
+ # config.keep_subscribers_when_private = false
38
+
39
+ # Set to true if you wish to broadcast channel subscriber_join and
40
+ # subscriber_part events. All subscribers of a channel will be
41
+ # notified when other clients join and part the channel. If you are
42
+ # using the UserManager, the current_user object will be sent along
43
+ # with the event.
44
+ # config.broadcast_subscriber_events = true
45
+
46
+ # Used as the key for the WebsocketRails.users Hash. This method
47
+ # will be called on the `current_user` object in your controller
48
+ # if one exists. If `current_user` does not exist or does not
49
+ # respond to the identifier, the key will default to `connection.id`
50
+ # config.user_identifier = :id
51
+
52
+ # Uncomment and change this option to override the class associated
53
+ # with your `current_user` object. This class will be used when
54
+ # synchronization is enabled and you trigger events from background
55
+ # jobs using the WebsocketRails.users UserManager.
56
+ # config.user_class = User
57
+
58
+ # Supporting HTTP streaming on Internet Explorer versions 8 & 9
59
+ # requires CORS to be enabled for GET "/websocket" request.
60
+ # List here the origin domains allowed to perform the request.
61
+ # config.allowed_origins = ['http://localhost:3000']
62
+
63
+ # Uncomment this option to change the default behavior when
64
+ # trigger_success or trigger_failure are not called in the action
65
+ # of the WebsocketController. (default is true)
66
+ # confid.trigger_success_by_default = false
67
+
68
+ end
@@ -0,0 +1,13 @@
1
+ module WebsocketRails
2
+ # This class provides a means for accessing the Rails
3
+ # controller helper methods defined in a user's application
4
+ # or in gems that the user has added to the project.
5
+ #
6
+ # Each active connection creates and stores it's own
7
+ # instance with the correct @_request and @_env objects
8
+ # set. WebsocketRails::BaseController sends missing
9
+ # methods to the active connection's delegation controller
10
+ # instance.
11
+ class DelegationController < ApplicationController
12
+ end
13
+ end
@@ -0,0 +1,7 @@
1
+ Rails.application.routes.draw do
2
+ if Rails.version >= '4.0.0'
3
+ match "/websocket", :to => WebsocketRails::ConnectionManager.new, via: [:get, :post]
4
+ else
5
+ match "/websocket", :to => WebsocketRails::ConnectionManager.new
6
+ end
7
+ end
@@ -0,0 +1,42 @@
1
+ namespace :websocket_rails do
2
+ desc 'Start the WebsocketRails standalone server.'
3
+ task :start_server do
4
+ require "thin"
5
+ load "#{Rails.root}/config/initializers/websocket_rails.rb"
6
+ load "#{Rails.root}/config/events.rb"
7
+
8
+ options = WebsocketRails.config.thin_options
9
+
10
+ warn_if_standalone_not_enabled!
11
+
12
+ if options[:daemonize]
13
+ fork do
14
+ Thin::Controllers::Controller.new(options).start
15
+ end
16
+ else
17
+ Thin::Controllers::Controller.new(options).start
18
+ end
19
+
20
+ puts "Websocket Rails Standalone Server listening on port #{options[:port]}"
21
+ end
22
+
23
+ desc 'Stop the WebsocketRails standalone server.'
24
+ task :stop_server do
25
+ require "thin"
26
+ load "#{Rails.root}/config/initializers/websocket_rails.rb"
27
+ load "#{Rails.root}/config/events.rb"
28
+
29
+ options = WebsocketRails.config.thin_options
30
+
31
+ warn_if_standalone_not_enabled!
32
+
33
+ Thin::Controllers::Controller.new(options).stop
34
+ end
35
+ end
36
+
37
+ def warn_if_standalone_not_enabled!
38
+ return if WebsocketRails.standalone?
39
+ puts "Fail!"
40
+ puts "You must enable standalone mode in your websocket_rails.rb initializer to use the standalone server."
41
+ exit 1
42
+ end