-
Notifications
You must be signed in to change notification settings - Fork 14
/
Copy pathwebsocket_rails.js.coffee
148 lines (119 loc) · 4.22 KB
/
websocket_rails.js.coffee
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
###
WebsocketRails JavaScript Client
Setting up the dispatcher:
var dispatcher = new WebSocketRails('localhost:3000/websocket');
dispatcher.on_open = function() {
// trigger a server event immediately after opening connection
dispatcher.trigger('new_user',{user_name: 'guest'});
})
Triggering a new event on the server
dispatcherer.trigger('event_name',object_to_be_serialized_to_json);
Listening for new events from the server
dispatcher.bind('event_name', function(data) {
console.log(data.user_name);
});
Stop listening for new events from the server
dispatcher.unbind('event')
###
class @WebSocketRails
constructor: (@url, @use_websockets = true) ->
@callbacks = {}
@channels = {}
@queue = {}
@connect()
connect: ->
@state = 'connecting'
unless @supports_websockets() and @use_websockets
@_conn = new WebSocketRails.HttpConnection @url, this
else
@_conn = new WebSocketRails.WebSocketConnection @url, this
@_conn.new_message = @new_message
disconnect: ->
if @_conn
@_conn.close()
delete @_conn._conn
delete @_conn
@state = 'disconnected'
# Reconnects the whole connection,
# keeping the messages queue and its' connected channels.
#
# After successfull connection, this will:
# - reconnect to all channels, that were active while disconnecting
# - resend all events from which we haven't received any response yet
reconnect: =>
old_connection_id = @_conn?.connection_id
@disconnect()
@connect()
# Resend all unfinished events from the previous connection.
for id, event of @queue
if event.connection_id == old_connection_id && !event.is_result()
@trigger_event event
@reconnect_channels()
new_message: (data) =>
event = new WebSocketRails.Event(data)
if event.is_result()
@queue[event.id]?.run_callbacks(event.success, event.data)
delete @queue[event.id]
else if event.is_channel()
@dispatch_channel event
else
@dispatch event
if @state == 'connecting' and event.name == 'client_connected'
@connection_established event
connection_established: (event) =>
@state = 'connected'
@_conn.setConnectionId(event.connection_id)
@_conn.flush_queue()
if @on_open?
@on_open(event.data)
bind: (event_name, callback) =>
@callbacks[event_name] ?= []
@callbacks[event_name].push callback
trigger: (event_name, data, success_callback, failure_callback) =>
event = new WebSocketRails.Event([event_name, data, {connection_id: @connection_id}], success_callback, failure_callback)
@queue[event.id] = event
@_conn.trigger event
trigger_event: (event) =>
@queue[event.id] ?= event # Prevent replacing an event that has callbacks stored
@_conn.trigger event
event
dispatch: (event) =>
return unless @callbacks[event.name]?
for callback in @callbacks[event.name]
callback event.data
subscribe: (channel_name, success_callback, failure_callback) =>
unless @channels[channel_name]?
channel = new WebSocketRails.Channel channel_name, @, false, success_callback, failure_callback
@channels[channel_name] = channel
channel
else
@channels[channel_name]
subscribe_private: (channel_name, success_callback, failure_callback) =>
unless @channels[channel_name]?
channel = new WebSocketRails.Channel channel_name, @, true, success_callback, failure_callback
@channels[channel_name] = channel
channel
else
@channels[channel_name]
unsubscribe: (channel_name) =>
return unless @channels[channel_name]?
@channels[channel_name].destroy()
delete @channels[channel_name]
dispatch_channel: (event) =>
return unless @channels[event.channel]?
@channels[event.channel].dispatch event.name, event.data
supports_websockets: =>
(typeof(WebSocket) == "function" or typeof(WebSocket) == "object")
connection_stale: =>
@state != 'connected'
reconnect_channels: ->
for name, channel of @channels
callbacks = channel._callbacks
channel.destroy()
delete @channels[name]
channel = if channel.is_private
@subscribe_private name
else
@subscribe name
channel._callbacks = callbacks
channel