isomorfeus-transport 1.0.0.zeta24 → 2.0.0.rc3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +21 -21
  3. data/README.md +27 -36
  4. data/lib/isomorfeus/transport/client_processor.rb +35 -35
  5. data/lib/isomorfeus/transport/config.rb +182 -166
  6. data/lib/isomorfeus/transport/hamster_session_store.rb +96 -0
  7. data/lib/isomorfeus/transport/handler/authentication_handler.rb +70 -70
  8. data/lib/isomorfeus/transport/imports.rb +9 -0
  9. data/lib/isomorfeus/transport/middlewares.rb +13 -13
  10. data/lib/isomorfeus/transport/rack_middleware.rb +59 -55
  11. data/lib/isomorfeus/transport/request_agent.rb +34 -34
  12. data/lib/isomorfeus/transport/response_agent.rb +23 -23
  13. data/lib/isomorfeus/transport/server_processor.rb +129 -129
  14. data/lib/isomorfeus/transport/server_socket_processor.rb +54 -54
  15. data/lib/isomorfeus/transport/ssr_login.rb +28 -28
  16. data/lib/isomorfeus/transport/version.rb +5 -5
  17. data/lib/isomorfeus/transport/{websocket.rb → websocket_client.rb} +123 -123
  18. data/lib/isomorfeus/transport.rb +200 -196
  19. data/lib/isomorfeus-transport.rb +70 -61
  20. data/lib/lucid_authentication/mixin.rb +122 -122
  21. data/lib/lucid_channel/base.rb +8 -9
  22. data/lib/lucid_channel/mixin.rb +105 -105
  23. data/lib/lucid_handler/base.rb +8 -9
  24. data/lib/lucid_handler/mixin.rb +27 -27
  25. data/node_modules/.package-lock.json +27 -0
  26. data/node_modules/ws/LICENSE +19 -0
  27. data/node_modules/ws/README.md +496 -0
  28. data/node_modules/ws/browser.js +8 -0
  29. data/node_modules/ws/index.js +13 -0
  30. data/node_modules/ws/lib/buffer-util.js +126 -0
  31. data/node_modules/ws/lib/constants.js +12 -0
  32. data/node_modules/ws/lib/event-target.js +266 -0
  33. data/node_modules/ws/lib/extension.js +203 -0
  34. data/node_modules/ws/lib/limiter.js +55 -0
  35. data/node_modules/ws/lib/permessage-deflate.js +511 -0
  36. data/node_modules/ws/lib/receiver.js +612 -0
  37. data/node_modules/ws/lib/sender.js +414 -0
  38. data/node_modules/ws/lib/stream.js +180 -0
  39. data/node_modules/ws/lib/subprotocol.js +62 -0
  40. data/node_modules/ws/lib/validation.js +124 -0
  41. data/node_modules/ws/lib/websocket-server.js +485 -0
  42. data/node_modules/ws/lib/websocket.js +1144 -0
  43. data/node_modules/ws/package.json +61 -0
  44. data/node_modules/ws/wrapper.mjs +8 -0
  45. data/package.json +6 -0
  46. metadata +76 -54
  47. data/lib/isomorfeus/transport/dbm_session_store.rb +0 -51
@@ -1,123 +1,123 @@
1
- module Isomorfeus
2
- module Transport
3
- class Websocket
4
- attr_reader :url
5
-
6
- if RUBY_ENGINE == 'opal'
7
- CONNECTING = 0
8
- OPEN = 1
9
- CLOSING = 2
10
- CLOSED = 3
11
-
12
- class SendError < StandardError; end
13
-
14
- def initialize(url, protocols = nil)
15
- @url = url
16
- @native_websocket = if protocols
17
- `new Opal.global.WebSocket(url, protocols)`
18
- else
19
- `new Opal.global.WebSocket(url)`
20
- end
21
- end
22
-
23
- def close
24
- @native_websocket.JS.close
25
- nil
26
- end
27
-
28
- def on_close(&block)
29
- @native_websocket.JS[:onclose] = `function(event) { block.$call(event); }`
30
- end
31
-
32
- def on_error(&block)
33
- @native_websocket.JS[:onerror] = `function(event) { block.$call(event); }`
34
- end
35
-
36
- def on_message(&block)
37
- @native_websocket.JS[:onmessage] = `function(event) { block.$call(event); }`
38
- end
39
-
40
- def on_open(&block)
41
- @native_websocket.JS[:onopen] = `function(event) { block.$call(event); }`
42
- end
43
-
44
- def protocol
45
- @native_websocket.JS[:protocol]
46
- end
47
-
48
- def send(data)
49
- case ready_state
50
- when OPEN then @native_websocket.JS.send(data)
51
- when CONNECTING then Isomorfeus::Transport.delay(50) { send(data) }
52
- when CLOSING then Isomorfeus.raise_error(error_class: SendError, message: 'Cant send, connection is closing!')
53
- when CLOSED then Isomorfeus.raise_error(error_class: SendError.new, message: 'Cant send, connection is closed!')
54
- end
55
- end
56
-
57
- private
58
-
59
- def ready_state
60
- @native_websocket.JS[:readyState]
61
- end
62
- else
63
- def initialize(url, protocols = nil)
64
- @url = url
65
- parsed_url = URI.parse(url)
66
- host = parsed_url.host
67
- port = parsed_url.port
68
- @socket = TCPSocket.new(host, port)
69
- @driver = ::WebSocket::Driver.client(self)
70
- @driver.on(:close, &method(:internal_on_close))
71
-
72
- @thread = Thread.new do
73
- begin
74
- while data = @sock.readpartial(512)
75
- @driver.parse(data)
76
- end
77
- end
78
- end
79
-
80
- @driver.start
81
- end
82
-
83
- def close
84
- @driver.close
85
- @thread.kill
86
- end
87
-
88
- def on_close(&block)
89
- @on_close_block = block
90
- end
91
-
92
- def on_error(&block)
93
- @driver.on(:error, block)
94
- end
95
-
96
- def on_message(&block)
97
- @on_message_block = block
98
- end
99
-
100
- def on_open(&block)
101
- @driver.on(:open, block)
102
- end
103
-
104
- def protocol
105
- @driver.protocol
106
- end
107
-
108
- def send(data)
109
- @socket.write(data)
110
- end
111
-
112
- private
113
-
114
- def internal_on_close(event)
115
- @on_close_block.call(event)
116
- @thread.kill
117
- end
118
- end
119
-
120
- alias_method :write, :send
121
- end
122
- end
123
- end
1
+ module Isomorfeus
2
+ module Transport
3
+ class WebsocketClient
4
+ attr_reader :url
5
+
6
+ if RUBY_ENGINE == 'opal'
7
+ CONNECTING = 0
8
+ OPEN = 1
9
+ CLOSING = 2
10
+ CLOSED = 3
11
+
12
+ class SendError < StandardError; end
13
+
14
+ def initialize(url, protocols = nil)
15
+ @url = url
16
+ @native_websocket = if protocols
17
+ `new Opal.global.WebSocket(url, protocols)`
18
+ else
19
+ `new Opal.global.WebSocket(url)`
20
+ end
21
+ end
22
+
23
+ def close
24
+ @native_websocket.JS.close
25
+ nil
26
+ end
27
+
28
+ def on_close(&block)
29
+ @native_websocket.JS[:onclose] = `function(event) { block.$call(event); }`
30
+ end
31
+
32
+ def on_error(&block)
33
+ @native_websocket.JS[:onerror] = `function(event) { block.$call(event); }`
34
+ end
35
+
36
+ def on_message(&block)
37
+ @native_websocket.JS[:onmessage] = `function(event) { block.$call(event); }`
38
+ end
39
+
40
+ def on_open(&block)
41
+ @native_websocket.JS[:onopen] = `function(event) { block.$call(event); }`
42
+ end
43
+
44
+ def protocol
45
+ @native_websocket.JS[:protocol]
46
+ end
47
+
48
+ def send(data)
49
+ case ready_state
50
+ when OPEN then @native_websocket.JS.send(data)
51
+ when CONNECTING then after(50) { send(data) }
52
+ when CLOSING then Isomorfeus.raise_error(error_class: SendError, message: 'Cant send, connection is closing!')
53
+ when CLOSED then Isomorfeus.raise_error(error_class: SendError.new, message: 'Cant send, connection is closed!')
54
+ end
55
+ end
56
+
57
+ private
58
+
59
+ def ready_state
60
+ @native_websocket.JS[:readyState]
61
+ end
62
+ else
63
+ def initialize(url, protocols = nil)
64
+ @url = url
65
+ parsed_url = URI.parse(url)
66
+ host = parsed_url.host
67
+ port = parsed_url.port
68
+ @socket = TCPSocket.new(host, port)
69
+ @driver = ::WebSocket::Driver.client(self)
70
+ @driver.on(:close, &method(:internal_on_close))
71
+
72
+ @thread = Thread.new do
73
+ begin
74
+ while data = @sock.readpartial(512)
75
+ @driver.parse(data)
76
+ end
77
+ end
78
+ end
79
+
80
+ @driver.start
81
+ end
82
+
83
+ def close
84
+ @driver.close
85
+ @thread.kill
86
+ end
87
+
88
+ def on_close(&block)
89
+ @on_close_block = block
90
+ end
91
+
92
+ def on_error(&block)
93
+ @driver.on(:error, block)
94
+ end
95
+
96
+ def on_message(&block)
97
+ @on_message_block = block
98
+ end
99
+
100
+ def on_open(&block)
101
+ @driver.on(:open, block)
102
+ end
103
+
104
+ def protocol
105
+ @driver.protocol
106
+ end
107
+
108
+ def send(data)
109
+ @socket.write(data)
110
+ end
111
+
112
+ private
113
+
114
+ def internal_on_close(event)
115
+ @on_close_block.call(event)
116
+ @thread.kill
117
+ end
118
+ end
119
+
120
+ alias_method :write, :send
121
+ end
122
+ end
123
+ end
@@ -1,196 +1,200 @@
1
- module Isomorfeus
2
- module Transport
3
- class << self
4
- if RUBY_ENGINE == 'opal'
5
- attr_accessor :socket
6
-
7
- def init
8
- @requests_in_progress = { requests: {}, agent_ids: {} }
9
- @socket = nil
10
- @initialized = false
11
- promise_connect if Isomorfeus.on_browser?
12
- true
13
- end
14
-
15
- def promise_connect
16
- promise = Promise.new
17
- if @socket && @socket.ready_state < 2
18
- promise.resolve(true)
19
- return promise
20
- end
21
- if Isomorfeus.on_browser?
22
- window_protocol = `window.location.protocol`
23
- ws_protocol = window_protocol == 'https:' ? 'wss:' : 'ws:'
24
- ws_url = "#{ws_protocol}//#{`window.location.host`}#{Isomorfeus.api_websocket_path}"
25
- else
26
- ws_url = Isomorfeus::TopLevel.transport_ws_url
27
- end
28
- @socket = Isomorfeus::Transport::Websocket.new(ws_url)
29
- @socket.on_error do
30
- @socket.close
31
- after 1000 do
32
- Isomorfeus::Transport.promise_connect
33
- end
34
- end
35
- @socket.on_message do |event|
36
- json_hash = `Opal.Hash.$new(JSON.parse(event.data))`
37
- Isomorfeus::Transport::ClientProcessor.process(json_hash)
38
- end
39
- @socket.on_open do |event|
40
- if @initialized
41
- requests_in_progress[:requests].each_key do |request|
42
- agent = get_agent_for_request_in_progress(request)
43
- promise_send_request(request) if agent && !agent.sent
44
- end
45
- promise.resolve(true)
46
- else
47
- @initialized = true
48
- init_promises = []
49
- Isomorfeus.transport_init_class_names.each do |constant|
50
- result = constant.constantize.send(:init)
51
- init_promises << result if result.class == Promise
52
- end
53
- if init_promises.size > 0
54
- Promise.when(*init_promises).then { promise.resolve(true) }
55
- end
56
- end
57
- end
58
- promise
59
- end
60
-
61
- def disconnect
62
- @socket.close if @socket
63
- @socket = nil
64
- end
65
-
66
- def promise_send_path(*path, &block)
67
- request = {}
68
- inject_path = path[0...-1]
69
- last_inject_path_el = inject_path.last
70
- last_path_el = path.last
71
- inject_path.inject(request) do |memo, key|
72
- if key == last_inject_path_el
73
- memo[key] = last_path_el
74
- else
75
- memo[key] = {}
76
- end
77
- end
78
- Isomorfeus::Transport.promise_send_request(request, &block)
79
- end
80
-
81
- def promise_send_request(request, &block)
82
- agent = if request_in_progress?(request)
83
- get_agent_for_request_in_progress(request)
84
- else
85
- Isomorfeus::Transport::RequestAgent.new(request)
86
- end
87
- unless agent.sent
88
- if block_given?
89
- agent.promise.then do |response|
90
- block.call(response)
91
- end
92
- end
93
- register_request_in_progress(request, agent.id)
94
- Isomorfeus.raise_error(message: 'No socket!') unless @socket
95
- begin
96
- @socket.send(`JSON.stringify(#{{request: { agent_ids: { agent.id => request }}}.to_n})`)
97
- agent.sent = true
98
- after(Isomorfeus.on_ssr? ? 8000 : 20000) do
99
- unless agent.promise.realized?
100
- agent.promise.reject({agent_response: { error: 'Request timeout!' }, full_response: {}})
101
- end
102
- end
103
- rescue
104
- @socket.close
105
- after 5000 do
106
- Isomorfeus::Transport.promise_connect
107
- end
108
- end
109
- end
110
- agent.promise
111
- end
112
-
113
- def send_message(channel_class, channel, message)
114
- Isomorfeus.raise_error(message: 'No socket!') unless @socket
115
- @socket.send(`JSON.stringify(#{{ notification: { class: channel_class.name, channel: channel, message: message }}.to_n})`)
116
- true
117
- end
118
-
119
- def promise_subscribe(channel_class_name, channel)
120
- request = { subscribe: true, class: channel_class_name, channel: channel }
121
- if request_in_progress?(request)
122
- agent = get_agent_for_request_in_progress(request)
123
- else
124
- agent = Isomorfeus::Transport::RequestAgent.new(request)
125
- register_request_in_progress(request, agent.id)
126
- Isomorfeus.raise_error(message: 'No socket!') unless @socket
127
- @socket.send(`JSON.stringify(#{{ subscribe: { agent_ids: { agent.id => request }}}.to_n})`)
128
- end
129
- result_promise = agent.promise.then do |agent|
130
- agent.response
131
- end
132
- result_promise
133
- end
134
-
135
- def promise_unsubscribe(channel_class_name, channel)
136
- request = { unsubscribe: true, class: channel_class_name, channel: channel }
137
- if request_in_progress?(request)
138
- agent = get_agent_for_request_in_progress(request)
139
- else
140
- agent = Isomorfeus::Transport::RequestAgent.new(request)
141
- register_request_in_progress(request, agent.id)
142
- Isomorfeus.raise_error(message: 'No socket!') unless @socket
143
- @socket.send(`JSON.stringify(#{{ unsubscribe: { agent_ids: { agent.id => request }}}.to_n})`)
144
- end
145
- result_promise = agent.promise.then do |agent|
146
- agent.response
147
- end
148
- result_promise
149
- end
150
-
151
- def busy?
152
- @requests_in_progress[:requests].size != 0
153
- end
154
-
155
- def requests_in_progress
156
- @requests_in_progress
157
- end
158
-
159
- def request_in_progress?(request)
160
- @requests_in_progress[:requests].key?(request)
161
- end
162
-
163
- def get_agent_for_request_in_progress(request)
164
- agent_id = @requests_in_progress[:requests][request]
165
- Isomorfeus::Transport::RequestAgent.get(agent_id)
166
- end
167
-
168
- def register_request_in_progress(request, agent_id)
169
- @requests_in_progress[:requests][request] = agent_id
170
- @requests_in_progress[:agent_ids][agent_id] = request
171
- end
172
-
173
- def unregister_request_in_progress(agent_id)
174
- request = @requests_in_progress[:agent_ids].delete(agent_id)
175
- @requests_in_progress[:requests].delete(request)
176
- end
177
- else # RUBY_ENGINE
178
- def send_message(channel_class, channel, message)
179
- channel_class_name = channel_class.name
180
- Isomorfeus.pub_sub_client.publish("#{channel_class_name}_#{channel}", Oj.dump({notification: { class: channel_class_name, channel: channel, message: message}}, mode: :strict))
181
- true
182
- end
183
-
184
- def promise_subscribe(channel_class, channel, &block)
185
- Isomorfeus.pub_sub_client.subscribe(channel)
186
- Promise.new.resolve({ success: channel })
187
- end
188
-
189
- def promise_unsubscribe(channel_class, channel, &block)
190
- Isomorfeus.pub_sub_client.unsubscribe(channel)
191
- Promise.new.resolve({ success: channel })
192
- end
193
- end # RUBY_ENGINE
194
- end
195
- end
196
- end
1
+ module Isomorfeus
2
+ module Transport
3
+ class << self
4
+ if RUBY_ENGINE == 'opal'
5
+ attr_accessor :socket
6
+
7
+ def init
8
+ @socket = nil
9
+ @initialized = false
10
+ promise_connect if Isomorfeus.on_browser? || Isomorfeus.on_mobile?
11
+ true
12
+ end
13
+
14
+ def promise_connect
15
+ promise = Promise.new
16
+ if @socket && @socket.ready_state < 2
17
+ promise.resolve(true)
18
+ return promise
19
+ end
20
+ if Isomorfeus.on_browser?
21
+ window_protocol = `window.location.protocol`
22
+ ws_protocol = window_protocol == 'https:' ? 'wss:' : 'ws:'
23
+ ws_url = "#{ws_protocol}//#{`window.location.host`}#{Isomorfeus.api_websocket_path}"
24
+ else
25
+ ws_url = "#{Isomorfeus::TopLevel.transport_ws_url}"
26
+ end
27
+ @socket = Isomorfeus::Transport::WebsocketClient.new(ws_url)
28
+ @socket.on_error do |error|
29
+ if Isomorfeus.on_browser?
30
+ `console.warn('Isomorfeus::Transport: Will try again, but so far error connecting:', error)`
31
+ @socket.close
32
+ after 1000 do
33
+ Isomorfeus::Transport.promise_connect
34
+ end
35
+ else
36
+ Isomorfeus.raise_error(message: error.JS[:message], stack: error.JS[:stack])
37
+ end
38
+ end
39
+ @socket.on_message do |event|
40
+ json_hash = `Opal.Hash.$new(JSON.parse(event.data))`
41
+ Isomorfeus::Transport::ClientProcessor.process(json_hash)
42
+ end
43
+ @socket.on_open do |event|
44
+ if @initialized
45
+ requests_in_progress[:requests].each_key do |request|
46
+ agent = get_agent_for_request_in_progress(request)
47
+ promise_send_request(request) if agent && !agent.sent
48
+ end
49
+ promise.resolve(true)
50
+ else
51
+ @initialized = true
52
+ init_promises = []
53
+ Isomorfeus.transport_init_class_names.each do |constant|
54
+ result = constant.constantize.send(:init)
55
+ init_promises << result if result.class == Promise
56
+ end
57
+ if init_promises.size > 0
58
+ Promise.when(*init_promises).then { promise.resolve(true) }
59
+ end
60
+ end
61
+ end
62
+ promise
63
+ end
64
+
65
+ def disconnect
66
+ @socket.close if @socket
67
+ @socket = nil
68
+ end
69
+
70
+ def promise_send_path(*path, &block)
71
+ request = {}
72
+ inject_path = path[0...-1]
73
+ last_inject_path_el = inject_path.last
74
+ last_path_el = path.last
75
+ inject_path.inject(request) do |memo, key|
76
+ if key == last_inject_path_el
77
+ memo[key] = last_path_el
78
+ else
79
+ memo[key] = {}
80
+ end
81
+ end
82
+ Isomorfeus::Transport.promise_send_request(request, &block)
83
+ end
84
+
85
+ def promise_send_request(request, &block)
86
+ agent = if request_in_progress?(request)
87
+ get_agent_for_request_in_progress(request)
88
+ else
89
+ Isomorfeus::Transport::RequestAgent.new(request)
90
+ end
91
+ unless agent.sent
92
+ if block_given?
93
+ agent.promise.then do |response|
94
+ block.call(response)
95
+ end
96
+ end
97
+ register_request_in_progress(request, agent.id)
98
+ Isomorfeus.raise_error(message: 'No socket!') unless @socket
99
+ begin
100
+ @socket.send(`JSON.stringify(#{{request: { agent_ids: { agent.id => request }}}.to_n})`)
101
+ agent.sent = true
102
+ after(Isomorfeus.on_ssr? ? 8000 : 20000) do
103
+ unless agent.promise.realized?
104
+ agent.promise.reject({agent_response: { error: 'Request timeout!' }, full_response: {}})
105
+ end
106
+ end
107
+ rescue
108
+ @socket.close
109
+ after 5000 do
110
+ Isomorfeus::Transport.promise_connect
111
+ end
112
+ end
113
+ end
114
+ agent.promise
115
+ end
116
+
117
+ def send_message(channel_class, channel, message)
118
+ Isomorfeus.raise_error(message: 'No socket!') unless @socket
119
+ @socket.send(`JSON.stringify(#{{ notification: { class: channel_class.name, channel: channel, message: message }}.to_n})`)
120
+ true
121
+ end
122
+
123
+ def promise_subscribe(channel_class_name, channel)
124
+ request = { subscribe: true, class: channel_class_name, channel: channel }
125
+ if request_in_progress?(request)
126
+ agent = get_agent_for_request_in_progress(request)
127
+ else
128
+ agent = Isomorfeus::Transport::RequestAgent.new(request)
129
+ register_request_in_progress(request, agent.id)
130
+ Isomorfeus.raise_error(message: 'No socket!') unless @socket
131
+ @socket.send(`JSON.stringify(#{{ subscribe: { agent_ids: { agent.id => request }}}.to_n})`)
132
+ end
133
+ result_promise = agent.promise.then do |agent|
134
+ agent.response
135
+ end
136
+ result_promise
137
+ end
138
+
139
+ def promise_unsubscribe(channel_class_name, channel)
140
+ request = { unsubscribe: true, class: channel_class_name, channel: channel }
141
+ if request_in_progress?(request)
142
+ agent = get_agent_for_request_in_progress(request)
143
+ else
144
+ agent = Isomorfeus::Transport::RequestAgent.new(request)
145
+ register_request_in_progress(request, agent.id)
146
+ Isomorfeus.raise_error(message: 'No socket!') unless @socket
147
+ @socket.send(`JSON.stringify(#{{ unsubscribe: { agent_ids: { agent.id => request }}}.to_n})`)
148
+ end
149
+ result_promise = agent.promise.then do |agent|
150
+ agent.response
151
+ end
152
+ result_promise
153
+ end
154
+
155
+ def busy?
156
+ requests_in_progress[:requests].size != 0
157
+ end
158
+
159
+ def requests_in_progress
160
+ @requests_in_progress ||= { requests: {}, agent_ids: {} }
161
+ end
162
+
163
+ def request_in_progress?(request)
164
+ requests_in_progress[:requests].key?(request)
165
+ end
166
+
167
+ def get_agent_for_request_in_progress(request)
168
+ agent_id = requests_in_progress[:requests][request]
169
+ Isomorfeus::Transport::RequestAgent.get(agent_id)
170
+ end
171
+
172
+ def register_request_in_progress(request, agent_id)
173
+ requests_in_progress[:requests][request] = agent_id
174
+ requests_in_progress[:agent_ids][agent_id] = request
175
+ end
176
+
177
+ def unregister_request_in_progress(agent_id)
178
+ request = requests_in_progress[:agent_ids].delete(agent_id)
179
+ requests_in_progress[:requests].delete(request)
180
+ end
181
+ else # RUBY_ENGINE
182
+ def send_message(channel_class, channel, message)
183
+ channel_class_name = channel_class.name
184
+ Isomorfeus.pub_sub_client.publish("#{channel_class_name}_#{channel}", Oj.dump({notification: { class: channel_class_name, channel: channel, message: message}}, mode: :strict))
185
+ true
186
+ end
187
+
188
+ def promise_subscribe(channel_class, channel, &block)
189
+ Isomorfeus.pub_sub_client.subscribe(channel)
190
+ Promise.new.resolve({ success: channel })
191
+ end
192
+
193
+ def promise_unsubscribe(channel_class, channel, &block)
194
+ Isomorfeus.pub_sub_client.unsubscribe(channel)
195
+ Promise.new.resolve({ success: channel })
196
+ end
197
+ end # RUBY_ENGINE
198
+ end
199
+ end
200
+ end