isomorfeus-transport 1.0.0.delta7
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.
- checksums.yaml +7 -0
- data/LICENSE +21 -0
- data/README.md +63 -0
- data/lib/isomorfeus-transport.rb +44 -0
- data/lib/isomorfeus/handler.rb +5 -0
- data/lib/isomorfeus/transport.rb +141 -0
- data/lib/isomorfeus/transport/client_processor.rb +26 -0
- data/lib/isomorfeus/transport/config.rb +42 -0
- data/lib/isomorfeus/transport/middlewares.rb +11 -0
- data/lib/isomorfeus/transport/rack_middleware.rb +27 -0
- data/lib/isomorfeus/transport/request_agent.rb +28 -0
- data/lib/isomorfeus/transport/server_processor.rb +51 -0
- data/lib/isomorfeus/transport/server_socket_processor.rb +30 -0
- data/lib/isomorfeus/transport/version.rb +5 -0
- data/lib/isomorfeus/transport/websocket.rb +115 -0
- data/lib/lucid_channel/base.rb +5 -0
- data/lib/lucid_channel/mixin.rb +31 -0
- metadata +156 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: e31570f39250ea91f27fdc953fa0658868e4d56d7cd848483431863acf005d1a
|
4
|
+
data.tar.gz: 2d00bbef87e55ff8f5873f3faf603b55c48cb0ac874970f2fccd4bf8978b2dc0
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: cffbfe276aaf67746cb3f6ec0e8b47333169d0fc60b278cc034bef2ed3684d536dcfffd8038905aa2b97c16ac7bbf8cd6b9db25c9dfc25a4f063acc17be61dac
|
7
|
+
data.tar.gz: 667055f7067f7aef78ae133556e75d930ac4782c787b517e5db964834c2e8e0a6998c275de00687a6dbe0823a6463a6fd87d2131486a6a5a2963f7af9e436b9a
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2018 Jan Biedermann
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
# isomorfeus-transport
|
2
|
+
|
3
|
+
Transport and PubSub for isomorfeus.
|
4
|
+
|
5
|
+
### Community and Support
|
6
|
+
At the [Isomorfeus Framework Project](http://isomorfeus.com)
|
7
|
+
|
8
|
+
## Installation
|
9
|
+
isomorfeus-transport is usually installed with the installer.
|
10
|
+
Otherwise add to your Gemfile:
|
11
|
+
```ruby
|
12
|
+
gem 'isomorfeus-transport'
|
13
|
+
```
|
14
|
+
and bundle install/update
|
15
|
+
|
16
|
+
## Server Side Rendering
|
17
|
+
`yarn add ws`
|
18
|
+
|
19
|
+
The 'ws' module then needs to be imported in application_ssr.js:
|
20
|
+
```
|
21
|
+
import WebSocket from 'ws';
|
22
|
+
global.WebSocket = WebSocket;
|
23
|
+
```
|
24
|
+
|
25
|
+
## Configuration options
|
26
|
+
|
27
|
+
Client and Server:
|
28
|
+
- Isomorfeus.api_websocket_path - path for server side endpoint, default: `/isomorfeus/api/websocket`
|
29
|
+
|
30
|
+
Server only:
|
31
|
+
- Isomorfeus.middlewares - all the rack middlewares to load
|
32
|
+
|
33
|
+
|
34
|
+
## LucidChannel
|
35
|
+
|
36
|
+
Isomorfeus-transport provides the LucidChannel::Mixin and LucidChannel::Base class.
|
37
|
+
These can be used for subscriptions and publishing messages.
|
38
|
+
|
39
|
+
### Subscriptions
|
40
|
+
```ruby
|
41
|
+
class MyChannel < LucidChannel::Base
|
42
|
+
end
|
43
|
+
|
44
|
+
# subscribe to channel
|
45
|
+
MyChannel.subscribe
|
46
|
+
|
47
|
+
# unsubscribe
|
48
|
+
MyChannel.unsubscribe
|
49
|
+
```
|
50
|
+
|
51
|
+
### Processing messages
|
52
|
+
```ruby
|
53
|
+
class MyChannel < LucidChannel::Base
|
54
|
+
on_message do |message|
|
55
|
+
puts "received: " + message
|
56
|
+
end
|
57
|
+
end
|
58
|
+
```
|
59
|
+
|
60
|
+
### Sending mesages
|
61
|
+
```ruby
|
62
|
+
MyChannel.send_message('uiuiui')
|
63
|
+
```
|
@@ -0,0 +1,44 @@
|
|
1
|
+
if RUBY_ENGINE == 'opal'
|
2
|
+
require 'json'
|
3
|
+
require 'isomorfeus/config'
|
4
|
+
require 'isomorfeus/execution_environment'
|
5
|
+
require 'isomorfeus/transport/version'
|
6
|
+
require 'isomorfeus/transport/config'
|
7
|
+
require 'isomorfeus/transport/request_agent'
|
8
|
+
require 'isomorfeus/transport/client_processor'
|
9
|
+
require 'isomorfeus/transport/websocket'
|
10
|
+
require 'isomorfeus/transport'
|
11
|
+
require 'lucid_channel/mixin'
|
12
|
+
require 'lucid_channel/base'
|
13
|
+
Isomorfeus::Transport.init!
|
14
|
+
else
|
15
|
+
require 'base64'
|
16
|
+
require 'digest'
|
17
|
+
require 'socket'
|
18
|
+
require 'oj'
|
19
|
+
require 'websocket/driver'
|
20
|
+
require 'active_support'
|
21
|
+
require 'iodine'
|
22
|
+
require 'isomorfeus/config'
|
23
|
+
require 'isomorfeus/promise'
|
24
|
+
require 'isomorfeus/transport/version'
|
25
|
+
require 'isomorfeus/transport/config'
|
26
|
+
require 'isomorfeus/transport/middlewares'
|
27
|
+
require 'isomorfeus/transport/request_agent'
|
28
|
+
require 'isomorfeus/transport/server_processor'
|
29
|
+
require 'isomorfeus/transport/server_socket_processor'
|
30
|
+
require 'isomorfeus/transport/websocket'
|
31
|
+
require 'isomorfeus/handler'
|
32
|
+
require 'isomorfeus/transport/rack_middleware'
|
33
|
+
Opal.append_path(__dir__.untaint) unless Opal.paths.include?(__dir__.untaint)
|
34
|
+
|
35
|
+
require 'isomorfeus/transport/middlewares'
|
36
|
+
|
37
|
+
Isomorfeus.add_middleware(Isomorfeus::Transport::RackMiddleware)
|
38
|
+
|
39
|
+
if Dir.exist?(File.join('app', 'isomorfeus'))
|
40
|
+
$LOAD_PATH.unshift(File.expand_path(File.join('app', 'isomorfeus', 'handlers')))
|
41
|
+
elsif Dir.exist?(File.join('isomorfeus'))
|
42
|
+
$LOAD_PATH.unshift(File.expand_path(File.join('isomorfeus', 'handlers')))
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,141 @@
|
|
1
|
+
module Isomorfeus
|
2
|
+
module Transport
|
3
|
+
class << self
|
4
|
+
attr_accessor :socket
|
5
|
+
|
6
|
+
def delay(ms = 1000, &block)
|
7
|
+
`setTimeout(#{block.to_n}, ms)`
|
8
|
+
end
|
9
|
+
|
10
|
+
def init!
|
11
|
+
@requests_in_progress = { requests: {}, agent_ids: {} }
|
12
|
+
@socket = nil
|
13
|
+
connect if Isomorfeus.on_browser?
|
14
|
+
end
|
15
|
+
|
16
|
+
def connect
|
17
|
+
return if @socket && @socket.ready_state < 2
|
18
|
+
if Isomorfeus.on_browser?
|
19
|
+
window_protocol = `window.location.protocol`
|
20
|
+
ws_protocol = window_protocol == 'https:' ? 'wss:' : 'ws:'
|
21
|
+
ws_url = "#{ws_protocol}#{`window.location.host`}#{Isomorfeus.api_websocket_path}"
|
22
|
+
else
|
23
|
+
ws_url = Isomorfeus::TopLevel.transport_ws_url
|
24
|
+
end
|
25
|
+
@socket = Isomorfeus::Transport::Websocket.new(ws_url)
|
26
|
+
@socket.on_error do
|
27
|
+
@socket.close
|
28
|
+
delay do
|
29
|
+
Isomorfeus::Transport.connect
|
30
|
+
end
|
31
|
+
end
|
32
|
+
@socket.on_message do |event|
|
33
|
+
json_hash = `Opal.Hash.$new(JSON.parse(event.data))`
|
34
|
+
Isomorfeus::Transport::ClientProcessor.process(json_hash)
|
35
|
+
end
|
36
|
+
true
|
37
|
+
end
|
38
|
+
|
39
|
+
def disconnect
|
40
|
+
@socket.close if @socket
|
41
|
+
@socket = nil
|
42
|
+
end
|
43
|
+
|
44
|
+
def promise_send_path(*path, &block)
|
45
|
+
request = {}
|
46
|
+
path.inject(request) do |memo, key|
|
47
|
+
memo[key] = {}
|
48
|
+
end
|
49
|
+
Isomorfeus::Transport.promise_send_request(request, &block)
|
50
|
+
end
|
51
|
+
|
52
|
+
def promise_send_request(request, &block)
|
53
|
+
if request_in_progress?(request)
|
54
|
+
agent = get_agent_for_request_in_progress(request)
|
55
|
+
else
|
56
|
+
agent = Isomorfeus::Transport::RequestAgent.new(request)
|
57
|
+
if block_given?
|
58
|
+
agent.promise.then do |response|
|
59
|
+
block.call(response)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
register_request_in_progress(request, agent.id)
|
63
|
+
@socket.send(`JSON.stringify(#{{request: { agent_ids: { agent.id => request }}}.to_n})`)
|
64
|
+
end
|
65
|
+
agent.promise
|
66
|
+
end
|
67
|
+
|
68
|
+
def send_notification(processor_class, message)
|
69
|
+
@socket.send(`JSON.stringify(#{{notification: { class: processor_class.to_s, message: message}}.to_n})`)
|
70
|
+
true
|
71
|
+
end
|
72
|
+
|
73
|
+
def subscribe(processor_class, &block)
|
74
|
+
request = { subscribe: true, class: processor_class.to_s }
|
75
|
+
if request_in_progress?(request)
|
76
|
+
agent = get_agent_for_request_in_progress(request)
|
77
|
+
else
|
78
|
+
agent = Isomorfeus::Transport::RequestAgent.new(request)
|
79
|
+
register_request_in_progress(request, agent.id)
|
80
|
+
@socket.send(`JSON.stringify(#{{subscribe: { agent_ids: { agent.id => request }}}.to_n})`)
|
81
|
+
end
|
82
|
+
result_promise = agent.promise.then do |response|
|
83
|
+
response[:agent_response]
|
84
|
+
end
|
85
|
+
if block_given?
|
86
|
+
result_promise = result_promise.then do |response|
|
87
|
+
block.call(response)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
result_promise
|
91
|
+
end
|
92
|
+
|
93
|
+
def unsubscribe(processor_class, &block)
|
94
|
+
request = { unsubscribe: true, class: processor_class.to_s }
|
95
|
+
if request_in_progress?(request)
|
96
|
+
agent = get_agent_for_request_in_progress(request)
|
97
|
+
else
|
98
|
+
agent = Isomorfeus::Transport::RequestAgent.new(request)
|
99
|
+
register_request_in_progress(request, agent.id)
|
100
|
+
@socket.send(`JSON.stringify(#{{unsubscribe: { agent_ids: { agent.id => request }}}.to_n})`)
|
101
|
+
end
|
102
|
+
result_promise = agent.promise.then do |response|
|
103
|
+
response[:agent_response]
|
104
|
+
end
|
105
|
+
if block_given?
|
106
|
+
result_promise = result_promise.then do |response|
|
107
|
+
block.call(response)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
result_promise
|
111
|
+
end
|
112
|
+
|
113
|
+
def busy?
|
114
|
+
@requests_in_progress.size != 0
|
115
|
+
end
|
116
|
+
|
117
|
+
def requests_in_progress
|
118
|
+
@requests_in_progress
|
119
|
+
end
|
120
|
+
|
121
|
+
def request_in_progress?(request)
|
122
|
+
@requests_in_progress[:requests].key?(request)
|
123
|
+
end
|
124
|
+
|
125
|
+
def get_agent_for_request_in_progress(request)
|
126
|
+
agent_id = @requests_in_progress[:requests][request]
|
127
|
+
Isomorfeus::Transport::RequestAgent.get(agent_id)
|
128
|
+
end
|
129
|
+
|
130
|
+
def register_request_in_progress(request, agent_id)
|
131
|
+
@requests_in_progress[:requests][request] = agent_id
|
132
|
+
@requests_in_progress[:agent_ids][agent_id] = request
|
133
|
+
end
|
134
|
+
|
135
|
+
def unregister_request_in_progress(agent_id)
|
136
|
+
request = @requests_in_progress[:agent_ids].delete(agent_id)
|
137
|
+
@requests_in_progress[:requests].delete(request)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Isomorfeus
|
2
|
+
module Transport
|
3
|
+
class ClientProcessor
|
4
|
+
def self.process(json_hash)
|
5
|
+
if json_hash.key?(:response)
|
6
|
+
process_response(json_hash)
|
7
|
+
elsif json_hash.key?(:notification)
|
8
|
+
process_notification(json_hash)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.process_notification(notification_hash)
|
13
|
+
processor_class = "::#{notification_hash[:notification][:class]}".constantize
|
14
|
+
processor_class.process_message(notification_hash[:notification][:message])
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.process_response(response_hash)
|
18
|
+
response_hash[:response][:agent_ids].keys.each do |agent_id|
|
19
|
+
agent = Isomorfeus::Transport::RequestAgent.get!(agent_id)
|
20
|
+
Isomorfeus::Transport.unregister_request_in_progress(agent_id)
|
21
|
+
agent.promise.resolve(agent_response: response_hash[:response][:agent_ids][agent_id], full_response: response_hash)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Isomorfeus
|
2
|
+
# available settings
|
3
|
+
|
4
|
+
if RUBY_ENGINE == 'opal'
|
5
|
+
add_client_option(:api_websocket_path)
|
6
|
+
else
|
7
|
+
# defaults
|
8
|
+
class << self
|
9
|
+
attr_accessor :api_websocket_path
|
10
|
+
attr_accessor :middlewares
|
11
|
+
|
12
|
+
def add_middleware(middleware)
|
13
|
+
Isomorfeus.middlewares << middleware unless Isomorfeus.middlewares.include?(middleware)
|
14
|
+
end
|
15
|
+
|
16
|
+
def insert_middleware_after(existing_middleware, new_middleware)
|
17
|
+
index_of_existing = Isomorfeus.middlewares.index(existing_middleware)
|
18
|
+
unless Isomorfeus.middlewares.include?(new_middleware)
|
19
|
+
if index_of_existing
|
20
|
+
Isomorfeus.middlewares.insert(index_of_existing + 1, new_middleware)
|
21
|
+
else
|
22
|
+
Isomorfeus.middlewares << new_middleware
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def insert_middleware_before(existing_middleware, new_middleware)
|
28
|
+
index_of_existing = Isomorfeus.middlewares.index(existing_middleware)
|
29
|
+
unless Isomorfeus.middlewares.include?(new_middleware)
|
30
|
+
if index_of_existing
|
31
|
+
Isomorfeus.middlewares.insert(index_of_existing, new_middleware)
|
32
|
+
else
|
33
|
+
Isomorfeus.middlewares << new_middleware
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
self.middlewares = Set.new
|
39
|
+
end
|
40
|
+
|
41
|
+
self.api_websocket_path = '/isomorfeus/api/websocket'
|
42
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Isomorfeus
|
4
|
+
module Transport
|
5
|
+
class RackMiddleware
|
6
|
+
include Isomorfeus::Transport::ServerProcessor
|
7
|
+
|
8
|
+
WS_RESPONSE = [0, {}, []]
|
9
|
+
|
10
|
+
def initialize(app)
|
11
|
+
@app = app
|
12
|
+
end
|
13
|
+
|
14
|
+
def call(env)
|
15
|
+
if env['PATH_INFO'] == Isomorfeus.api_websocket_path
|
16
|
+
user = defined?(Warden::Manager) ? env['warden'].user : nil
|
17
|
+
if env['rack.upgrade?'] == :websocket
|
18
|
+
env['rack.upgrade'] = Isomorfeus::Transport::ServerSocketProcessor.new(env['rack.session'], user)
|
19
|
+
end
|
20
|
+
WS_RESPONSE
|
21
|
+
else
|
22
|
+
@app.call(env)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Isomorfeus
|
2
|
+
module Transport
|
3
|
+
class RequestAgent
|
4
|
+
def self.agents
|
5
|
+
@_agents ||= {}
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.get(object_id)
|
9
|
+
agents[object_id]
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.get!(object_id)
|
13
|
+
agents.delete(object_id.to_s)
|
14
|
+
end
|
15
|
+
|
16
|
+
attr_reader :id
|
17
|
+
attr_reader :promise
|
18
|
+
attr_reader :request
|
19
|
+
|
20
|
+
def initialize(request = nil)
|
21
|
+
@id = object_id.to_s
|
22
|
+
self.class.agents[@id] = self
|
23
|
+
@promise = Promise.new
|
24
|
+
@request = request
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Isomorfeus
|
4
|
+
module Transport
|
5
|
+
module ServerProcessor
|
6
|
+
def process_request(client, session_id, current_user, request)
|
7
|
+
response = { response: { agent_ids: {}} }
|
8
|
+
|
9
|
+
if request.key?('request') && request['request'].key?('agent_ids')
|
10
|
+
request['request']['agent_ids'].keys.each do |agent_id|
|
11
|
+
request['request']['agent_ids'][agent_id].keys.each do |key|
|
12
|
+
handler = "::#{key.underscore.camelize}Handler".constantize
|
13
|
+
if handler
|
14
|
+
response[:response][:agent_ids][agent_id] = handler.new.process_request(client, session_id, current_user, request['request']['agent_ids'][agent_id][key], response)
|
15
|
+
else
|
16
|
+
response[:response][:agent_ids][agent_id] = { error: { key => 'No such handler!'}}
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
elsif request.key?('notification')
|
21
|
+
if request['notification'].key?('class')
|
22
|
+
client.publish(request['notification']['class'], Oj.dump({ 'notification' => request['notification'] }, mode: :strict))
|
23
|
+
else
|
24
|
+
response[:response] = 'No such thing!'
|
25
|
+
end
|
26
|
+
elsif request.key?('subscribe') && request['subscribe'].key?('agent_ids')
|
27
|
+
agent_id = request['subscribe']['agent_ids'].keys.first
|
28
|
+
channel = request['subscribe']['agent_ids'][agent_id]['class']
|
29
|
+
if channel
|
30
|
+
client.subscribe(channel)
|
31
|
+
response[:response][:agent_ids][agent_id] = { success: channel }
|
32
|
+
else
|
33
|
+
response[:response][:agent_ids][agent_id] = { error: "No such thing!"}
|
34
|
+
end
|
35
|
+
elsif request.key?('unsubscribe') && request['unsubscribe'].key?('agent_ids')
|
36
|
+
agent_id = request['unsubscribe']['agent_ids'].keys.first
|
37
|
+
channel = request['unsubscribe']['agent_ids'][agent_id]['class']
|
38
|
+
if channel
|
39
|
+
client.unsubscribe(channel)
|
40
|
+
response[:response][:agent_ids][agent_id] = { success: channel }
|
41
|
+
else
|
42
|
+
response[:response][:agent_ids][agent_id] = { error: 'No such thing!'}
|
43
|
+
end
|
44
|
+
else
|
45
|
+
response[:response] = 'No such thing!'
|
46
|
+
end
|
47
|
+
response
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Isomorfeus
|
2
|
+
module Transport
|
3
|
+
class ServerSocketProcessor
|
4
|
+
include Isomorfeus::Transport::ServerProcessor
|
5
|
+
|
6
|
+
def initialize(session_id, user)
|
7
|
+
@session_id = session_id
|
8
|
+
@user = user
|
9
|
+
end
|
10
|
+
|
11
|
+
def on_message(client, data)
|
12
|
+
request_hash = Oj.load(data, mode: :strict)
|
13
|
+
result = process_request(client, @session_id, @user, request_hash)
|
14
|
+
client.write Oj.dump(result, mode: :strict)
|
15
|
+
end
|
16
|
+
|
17
|
+
def on_close(client)
|
18
|
+
# nothing for now
|
19
|
+
end
|
20
|
+
|
21
|
+
def on_open(client)
|
22
|
+
# nothing for now
|
23
|
+
end
|
24
|
+
|
25
|
+
def on_shutdown(client)
|
26
|
+
# nothing for now
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,115 @@
|
|
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 send(data)
|
41
|
+
case ready_state
|
42
|
+
when OPEN then @native_websocket.JS.send(data)
|
43
|
+
when CONNECTING then Isomorfeus::Transport.delay(50) { send(data) }
|
44
|
+
when CLOSING then raise SendError.new('Cant send, connection is closing!')
|
45
|
+
when CLOSED then raise SendError.new('Cant send, connection is closed!')
|
46
|
+
end
|
47
|
+
end
|
48
|
+
alias_method :write, :send
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def ready_state
|
53
|
+
@native_websocket.JS[:readyState]
|
54
|
+
end
|
55
|
+
else
|
56
|
+
def initialize(url, protocols = nil)
|
57
|
+
@url = url
|
58
|
+
parsed_url = URI.parse(url)
|
59
|
+
host = parsed_url.host
|
60
|
+
port = parsed_url.port
|
61
|
+
@socket = TCPSocket.new(host, port)
|
62
|
+
@driver = ::WebSocket::Driver.client(self)
|
63
|
+
@driver.on(:close, &method(:internal_on_close))
|
64
|
+
|
65
|
+
@thread = Thread.new do
|
66
|
+
begin
|
67
|
+
while data = @sock.readpartial(512)
|
68
|
+
@driver.parse(data)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
@driver.start
|
74
|
+
end
|
75
|
+
|
76
|
+
def close
|
77
|
+
@driver.close
|
78
|
+
@thread.kill
|
79
|
+
end
|
80
|
+
|
81
|
+
def on_close(&block)
|
82
|
+
@on_close_block = block
|
83
|
+
end
|
84
|
+
|
85
|
+
def on_error(&block)
|
86
|
+
@driver.on(:error, block)
|
87
|
+
end
|
88
|
+
|
89
|
+
def on_message(&block)
|
90
|
+
@on_message_block = block
|
91
|
+
end
|
92
|
+
|
93
|
+
def on_open(&block)
|
94
|
+
@driver.on(:open, block)
|
95
|
+
end
|
96
|
+
|
97
|
+
def protocol
|
98
|
+
@driver.protocol
|
99
|
+
end
|
100
|
+
|
101
|
+
def send(data)
|
102
|
+
@socket.write(data)
|
103
|
+
end
|
104
|
+
alias_method :write, :send
|
105
|
+
|
106
|
+
private
|
107
|
+
|
108
|
+
def internal_on_close(event)
|
109
|
+
@on_close_block.call(event)
|
110
|
+
@thread.kill
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module LucidChannel
|
2
|
+
module Mixin
|
3
|
+
def self.included(base)
|
4
|
+
base.instance_exec do
|
5
|
+
def process_message(message)
|
6
|
+
if @message_processor
|
7
|
+
@message_processor.call(message)
|
8
|
+
else
|
9
|
+
puts "#{self} received: #{message}, but no processor defined!"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def on_message(&block)
|
14
|
+
@message_processor = block
|
15
|
+
end
|
16
|
+
|
17
|
+
def send_message(message)
|
18
|
+
Isomorfeus::Transport.send_notification(self, message)
|
19
|
+
end
|
20
|
+
|
21
|
+
def subscribe
|
22
|
+
Isomorfeus::Transport.subscribe(self)
|
23
|
+
end
|
24
|
+
|
25
|
+
def unsubscribe
|
26
|
+
Isomorfeus::Transport.unsubscribe(self)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
metadata
ADDED
@@ -0,0 +1,156 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: isomorfeus-transport
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0.delta7
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jan Biedermann
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2019-06-27 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: activesupport
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '5.0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '5.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: iodine
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.7.32
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 0.7.32
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: oj
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.6'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.6'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: opal
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 0.11.0
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 0.11.0
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: isomorfeus-redux
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 4.0.7
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 4.0.7
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: isomorfeus-react
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: 16.8.7
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: 16.8.7
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: websocket-driver
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: 0.7.0
|
104
|
+
type: :runtime
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: 0.7.0
|
111
|
+
description: Various transport options for Isomorfeus.
|
112
|
+
email: jan@kursator.de
|
113
|
+
executables: []
|
114
|
+
extensions: []
|
115
|
+
extra_rdoc_files: []
|
116
|
+
files:
|
117
|
+
- LICENSE
|
118
|
+
- README.md
|
119
|
+
- lib/isomorfeus-transport.rb
|
120
|
+
- lib/isomorfeus/handler.rb
|
121
|
+
- lib/isomorfeus/transport.rb
|
122
|
+
- lib/isomorfeus/transport/client_processor.rb
|
123
|
+
- lib/isomorfeus/transport/config.rb
|
124
|
+
- lib/isomorfeus/transport/middlewares.rb
|
125
|
+
- lib/isomorfeus/transport/rack_middleware.rb
|
126
|
+
- lib/isomorfeus/transport/request_agent.rb
|
127
|
+
- lib/isomorfeus/transport/server_processor.rb
|
128
|
+
- lib/isomorfeus/transport/server_socket_processor.rb
|
129
|
+
- lib/isomorfeus/transport/version.rb
|
130
|
+
- lib/isomorfeus/transport/websocket.rb
|
131
|
+
- lib/lucid_channel/base.rb
|
132
|
+
- lib/lucid_channel/mixin.rb
|
133
|
+
homepage: http://isomorfeus.com
|
134
|
+
licenses:
|
135
|
+
- MIT
|
136
|
+
metadata: {}
|
137
|
+
post_install_message:
|
138
|
+
rdoc_options: []
|
139
|
+
require_paths:
|
140
|
+
- lib
|
141
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ">="
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0'
|
146
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
147
|
+
requirements:
|
148
|
+
- - ">"
|
149
|
+
- !ruby/object:Gem::Version
|
150
|
+
version: 1.3.1
|
151
|
+
requirements: []
|
152
|
+
rubygems_version: 3.0.3
|
153
|
+
signing_key:
|
154
|
+
specification_version: 4
|
155
|
+
summary: Various transport options for Isomorfeus.
|
156
|
+
test_files: []
|