anycable-rack-server 0.0.1 → 0.3.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.
- checksums.yaml +4 -4
- data/LICENSE +1 -1
- data/README.md +101 -15
- data/lib/anycable-rack-server.rb +15 -1
- data/lib/anycable/rack/broadcast_subscribers/base_subscriber.rb +41 -0
- data/lib/anycable/rack/broadcast_subscribers/http_subscriber.rb +44 -0
- data/lib/anycable/rack/broadcast_subscribers/redis_subscriber.rb +57 -0
- data/lib/anycable/{rack-server → rack}/coders/json.rb +4 -2
- data/lib/anycable/rack/config.rb +21 -0
- data/lib/anycable/rack/connection.rb +197 -0
- data/lib/anycable/{rack-server → rack}/errors.rb +1 -2
- data/lib/anycable/{rack-server → rack}/hub.rb +42 -1
- data/lib/anycable/{rack-server → rack}/logging.rb +2 -2
- data/lib/anycable/rack/middleware.rb +95 -0
- data/lib/anycable/{rack-server → rack}/pinger.rb +4 -5
- data/lib/anycable/rack/railtie.rb +31 -0
- data/lib/anycable/rack/rpc/client.rb +70 -0
- data/lib/anycable/{rack-server → rack}/rpc/rpc.proto +18 -4
- data/lib/anycable/rack/server.rb +117 -0
- data/lib/anycable/{rack-server → rack}/socket.rb +21 -28
- data/lib/anycable/{rack-server → rack}/version.rb +2 -2
- metadata +106 -40
- data/lib/anycable/rack-server.rb +0 -107
- data/lib/anycable/rack-server/broadcast_subscribers/redis_subscriber.rb +0 -40
- data/lib/anycable/rack-server/connection.rb +0 -189
- data/lib/anycable/rack-server/middleware.rb +0 -82
- data/lib/anycable/rack-server/rpc/client.rb +0 -42
@@ -1,9 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "anycable/rack/logging"
|
4
4
|
|
5
5
|
module AnyCable
|
6
|
-
module
|
6
|
+
module Rack
|
7
|
+
# Socket wrapper
|
7
8
|
class Socket
|
8
9
|
include Logging
|
9
10
|
attr_reader :version, :socket
|
@@ -14,11 +15,11 @@ module AnyCable
|
|
14
15
|
@socket = socket
|
15
16
|
@version = version
|
16
17
|
|
17
|
-
@_open_handlers
|
18
|
+
@_open_handlers = []
|
18
19
|
@_message_handlers = []
|
19
|
-
@_close_handlers
|
20
|
-
@_error_handlers
|
21
|
-
@_active
|
20
|
+
@_close_handlers = []
|
21
|
+
@_error_handlers = []
|
22
|
+
@_active = true
|
22
23
|
end
|
23
24
|
|
24
25
|
def transmit(data, type: :text)
|
@@ -28,13 +29,13 @@ module AnyCable
|
|
28
29
|
type: type
|
29
30
|
)
|
30
31
|
socket.write(frame.to_s)
|
31
|
-
rescue
|
32
|
+
rescue Exception => e # rubocop:disable Lint/RescueException
|
32
33
|
log(:error, "Socket send failed: #{e}")
|
33
34
|
close
|
34
35
|
end
|
35
36
|
|
36
37
|
def request
|
37
|
-
@
|
38
|
+
@request ||= ::Rack::Request.new(@env)
|
38
39
|
end
|
39
40
|
|
40
41
|
def onopen(&block)
|
@@ -53,22 +54,19 @@ module AnyCable
|
|
53
54
|
@_error_handlers << block
|
54
55
|
end
|
55
56
|
|
56
|
-
# rubocop: disable Metrics/MethodLength
|
57
57
|
def listen
|
58
58
|
keepalive
|
59
59
|
Thread.new do
|
60
|
-
Thread.current.
|
60
|
+
Thread.current.report_on_exception = true
|
61
61
|
begin
|
62
62
|
@_open_handlers.each(&:call)
|
63
63
|
each_frame do |data|
|
64
64
|
@_message_handlers.each do |handler|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
close
|
71
|
-
end
|
65
|
+
handler.call(data)
|
66
|
+
rescue => e # rubocop: disable Style/RescueStandardError
|
67
|
+
log(:error, "Socket receive failed: #{e}")
|
68
|
+
@_error_handlers.each { |eh| eh.call(e, data) }
|
69
|
+
close
|
72
70
|
end
|
73
71
|
end
|
74
72
|
ensure
|
@@ -76,7 +74,6 @@ module AnyCable
|
|
76
74
|
end
|
77
75
|
end
|
78
76
|
end
|
79
|
-
# rubocop: enable Metrics/MethodLength
|
80
77
|
|
81
78
|
def close
|
82
79
|
return unless @_active
|
@@ -105,7 +102,7 @@ module AnyCable
|
|
105
102
|
frame = WebSocket::Frame::Outgoing::Server.new(version: version, type: :close, code: 1000)
|
106
103
|
socket.write(frame.to_s) if frame.supported?
|
107
104
|
socket.close
|
108
|
-
rescue
|
105
|
+
rescue Exception # rubocop:disable Lint/RescueException
|
109
106
|
# already closed
|
110
107
|
end
|
111
108
|
|
@@ -114,8 +111,7 @@ module AnyCable
|
|
114
111
|
Thread.current.abort_on_exception = true
|
115
112
|
loop do
|
116
113
|
sleep 5
|
117
|
-
|
118
|
-
transmit({ message: time, type: :ping }.to_json)
|
114
|
+
transmit nil, type: :ping
|
119
115
|
end
|
120
116
|
end
|
121
117
|
|
@@ -124,24 +120,21 @@ module AnyCable
|
|
124
120
|
end
|
125
121
|
end
|
126
122
|
|
127
|
-
# rubocop:disable Metrics/AbcSize
|
128
|
-
# rubocop:disable Metrics/CyclomaticComplexity
|
129
|
-
# rubocop:disable Metrics/PerceivedComplexity
|
130
|
-
# rubocop:disable Metrics/MethodLength
|
131
123
|
def each_frame
|
132
124
|
framebuffer = WebSocket::Frame::Incoming::Server.new(version: version)
|
133
125
|
while IO.select([socket])
|
134
126
|
if socket.respond_to?(:recvfrom)
|
135
127
|
data, _addrinfo = socket.recvfrom(2000)
|
136
128
|
else
|
137
|
-
data
|
129
|
+
data = socket.readpartial(2000)
|
130
|
+
_addrinfo = socket.peeraddr
|
138
131
|
end
|
139
132
|
|
140
133
|
break if data.empty?
|
141
134
|
|
142
135
|
framebuffer << data
|
143
136
|
|
144
|
-
while frame = framebuffer.next
|
137
|
+
while frame = framebuffer.next # rubocop:disable Lint/AssignmentInCondition
|
145
138
|
case frame.type
|
146
139
|
when :close
|
147
140
|
return
|
@@ -150,7 +143,7 @@ module AnyCable
|
|
150
143
|
end
|
151
144
|
end
|
152
145
|
end
|
153
|
-
rescue
|
146
|
+
rescue Exception => e # rubocop:disable Lint/RescueException
|
154
147
|
log(:error, "Socket frame error: #{e}")
|
155
148
|
nil # client disconnected or timed out
|
156
149
|
end
|
metadata
CHANGED
@@ -1,99 +1,162 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: anycable-rack-server
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Yulia Oletskaya
|
8
|
-
|
8
|
+
- Vladimir Dementyev
|
9
|
+
autorequire:
|
9
10
|
bindir: bin
|
10
11
|
cert_chain: []
|
11
|
-
date:
|
12
|
+
date: 2021-05-12 00:00:00.000000000 Z
|
12
13
|
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: anyway_config
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - ">="
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: 2.1.0
|
21
|
+
type: :runtime
|
22
|
+
prerelease: false
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: 2.1.0
|
13
28
|
- !ruby/object:Gem::Dependency
|
14
29
|
name: anycable
|
15
30
|
requirement: !ruby/object:Gem::Requirement
|
16
31
|
requirements:
|
17
|
-
- - "
|
32
|
+
- - ">"
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: 1.0.99
|
35
|
+
- - "<"
|
18
36
|
- !ruby/object:Gem::Version
|
19
|
-
version: '0
|
37
|
+
version: '2.0'
|
20
38
|
type: :runtime
|
21
39
|
prerelease: false
|
22
40
|
version_requirements: !ruby/object:Gem::Requirement
|
23
41
|
requirements:
|
24
|
-
- - "
|
42
|
+
- - ">"
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
version: 1.0.99
|
45
|
+
- - "<"
|
25
46
|
- !ruby/object:Gem::Version
|
26
|
-
version: '0
|
47
|
+
version: '2.0'
|
27
48
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
49
|
+
name: connection_pool
|
29
50
|
requirement: !ruby/object:Gem::Requirement
|
30
51
|
requirements:
|
31
52
|
- - "~>"
|
32
53
|
- !ruby/object:Gem::Version
|
33
|
-
version: '
|
54
|
+
version: '2.2'
|
34
55
|
type: :runtime
|
35
56
|
prerelease: false
|
36
57
|
version_requirements: !ruby/object:Gem::Requirement
|
37
58
|
requirements:
|
38
59
|
- - "~>"
|
39
60
|
- !ruby/object:Gem::Version
|
40
|
-
version: '
|
61
|
+
version: '2.2'
|
41
62
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
63
|
+
name: websocket
|
43
64
|
requirement: !ruby/object:Gem::Requirement
|
44
65
|
requirements:
|
45
66
|
- - "~>"
|
46
67
|
- !ruby/object:Gem::Version
|
47
|
-
version: '
|
68
|
+
version: '1.2'
|
48
69
|
type: :runtime
|
49
70
|
prerelease: false
|
50
71
|
version_requirements: !ruby/object:Gem::Requirement
|
51
72
|
requirements:
|
52
73
|
- - "~>"
|
53
74
|
- !ruby/object:Gem::Version
|
54
|
-
version: '
|
75
|
+
version: '1.2'
|
55
76
|
- !ruby/object:Gem::Dependency
|
56
77
|
name: anyt
|
57
78
|
requirement: !ruby/object:Gem::Requirement
|
58
79
|
requirements:
|
59
|
-
- - "
|
80
|
+
- - ">="
|
60
81
|
- !ruby/object:Gem::Version
|
61
|
-
version: '0
|
82
|
+
version: '0'
|
62
83
|
type: :development
|
63
84
|
prerelease: false
|
64
85
|
version_requirements: !ruby/object:Gem::Requirement
|
65
86
|
requirements:
|
66
|
-
- - "
|
87
|
+
- - ">="
|
67
88
|
- !ruby/object:Gem::Version
|
68
|
-
version: '0
|
89
|
+
version: '0'
|
69
90
|
- !ruby/object:Gem::Dependency
|
70
91
|
name: minitest
|
71
92
|
requirement: !ruby/object:Gem::Requirement
|
72
93
|
requirements:
|
73
94
|
- - "~>"
|
74
95
|
- !ruby/object:Gem::Version
|
75
|
-
version: '5.
|
96
|
+
version: '5.10'
|
76
97
|
type: :development
|
77
98
|
prerelease: false
|
78
99
|
version_requirements: !ruby/object:Gem::Requirement
|
79
100
|
requirements:
|
80
101
|
- - "~>"
|
81
102
|
- !ruby/object:Gem::Version
|
82
|
-
version: '5.
|
103
|
+
version: '5.10'
|
104
|
+
- !ruby/object:Gem::Dependency
|
105
|
+
name: puma
|
106
|
+
requirement: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
type: :development
|
112
|
+
prerelease: false
|
113
|
+
version_requirements: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
83
118
|
- !ruby/object:Gem::Dependency
|
84
119
|
name: rake
|
120
|
+
requirement: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '13.0'
|
125
|
+
type: :development
|
126
|
+
prerelease: false
|
127
|
+
version_requirements: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '13.0'
|
132
|
+
- !ruby/object:Gem::Dependency
|
133
|
+
name: redis
|
85
134
|
requirement: !ruby/object:Gem::Requirement
|
86
135
|
requirements:
|
87
136
|
- - "~>"
|
88
137
|
- !ruby/object:Gem::Version
|
89
|
-
version: '
|
138
|
+
version: '4'
|
90
139
|
type: :development
|
91
140
|
prerelease: false
|
92
141
|
version_requirements: !ruby/object:Gem::Requirement
|
93
142
|
requirements:
|
94
143
|
- - "~>"
|
95
144
|
- !ruby/object:Gem::Version
|
96
|
-
version: '
|
145
|
+
version: '4'
|
146
|
+
- !ruby/object:Gem::Dependency
|
147
|
+
name: rubocop
|
148
|
+
requirement: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - ">="
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '0.80'
|
153
|
+
type: :development
|
154
|
+
prerelease: false
|
155
|
+
version_requirements: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - ">="
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: '0.80'
|
97
160
|
description: AnyCable-compatible Ruby Rack middleware
|
98
161
|
email: yulia.oletskaya@gmail.com
|
99
162
|
executables: []
|
@@ -103,24 +166,28 @@ files:
|
|
103
166
|
- LICENSE
|
104
167
|
- README.md
|
105
168
|
- lib/anycable-rack-server.rb
|
106
|
-
- lib/anycable/rack
|
107
|
-
- lib/anycable/rack
|
108
|
-
- lib/anycable/rack
|
109
|
-
- lib/anycable/rack
|
110
|
-
- lib/anycable/rack
|
111
|
-
- lib/anycable/rack
|
112
|
-
- lib/anycable/rack
|
113
|
-
- lib/anycable/rack
|
114
|
-
- lib/anycable/rack
|
115
|
-
- lib/anycable/rack
|
116
|
-
- lib/anycable/rack
|
117
|
-
- lib/anycable/rack
|
118
|
-
- lib/anycable/rack
|
119
|
-
|
169
|
+
- lib/anycable/rack/broadcast_subscribers/base_subscriber.rb
|
170
|
+
- lib/anycable/rack/broadcast_subscribers/http_subscriber.rb
|
171
|
+
- lib/anycable/rack/broadcast_subscribers/redis_subscriber.rb
|
172
|
+
- lib/anycable/rack/coders/json.rb
|
173
|
+
- lib/anycable/rack/config.rb
|
174
|
+
- lib/anycable/rack/connection.rb
|
175
|
+
- lib/anycable/rack/errors.rb
|
176
|
+
- lib/anycable/rack/hub.rb
|
177
|
+
- lib/anycable/rack/logging.rb
|
178
|
+
- lib/anycable/rack/middleware.rb
|
179
|
+
- lib/anycable/rack/pinger.rb
|
180
|
+
- lib/anycable/rack/railtie.rb
|
181
|
+
- lib/anycable/rack/rpc/client.rb
|
182
|
+
- lib/anycable/rack/rpc/rpc.proto
|
183
|
+
- lib/anycable/rack/server.rb
|
184
|
+
- lib/anycable/rack/socket.rb
|
185
|
+
- lib/anycable/rack/version.rb
|
186
|
+
homepage:
|
120
187
|
licenses:
|
121
188
|
- MIT
|
122
189
|
metadata: {}
|
123
|
-
post_install_message:
|
190
|
+
post_install_message:
|
124
191
|
rdoc_options: []
|
125
192
|
require_paths:
|
126
193
|
- lib
|
@@ -135,9 +202,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
135
202
|
- !ruby/object:Gem::Version
|
136
203
|
version: '0'
|
137
204
|
requirements: []
|
138
|
-
|
139
|
-
|
140
|
-
signing_key:
|
205
|
+
rubygems_version: 3.2.15
|
206
|
+
signing_key:
|
141
207
|
specification_version: 4
|
142
|
-
summary:
|
208
|
+
summary: AnyCable Rack Server
|
143
209
|
test_files: []
|
data/lib/anycable/rack-server.rb
DELETED
@@ -1,107 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'set'
|
4
|
-
require 'json'
|
5
|
-
require 'anycable'
|
6
|
-
require 'websocket'
|
7
|
-
require 'securerandom'
|
8
|
-
require 'anycable/rack-server/hub'
|
9
|
-
require 'anycable/rack-server/pinger'
|
10
|
-
require 'anycable/rack-server/errors'
|
11
|
-
require 'anycable/rack-server/middleware'
|
12
|
-
require 'anycable/rack-server/broadcast_subscribers/redis_subscriber'
|
13
|
-
require 'anycable/rack-server/coders/json'
|
14
|
-
|
15
|
-
module AnyCable
|
16
|
-
module RackServer
|
17
|
-
DEFAULT_OPTIONS = {
|
18
|
-
headers: ['cookie', 'x-api-token']
|
19
|
-
}.freeze
|
20
|
-
|
21
|
-
class << self
|
22
|
-
attr_reader :broadcast_subscriber,
|
23
|
-
:coder,
|
24
|
-
:hub,
|
25
|
-
:middleware,
|
26
|
-
:pinger,
|
27
|
-
:server_id
|
28
|
-
|
29
|
-
def start(options = {})
|
30
|
-
options = DEFAULT_OPTIONS.merge(options)
|
31
|
-
@hub = Hub.new
|
32
|
-
@pinger = Pinger.new
|
33
|
-
@coder = Coders::JSON
|
34
|
-
|
35
|
-
rpc_host = unpack_host(AnyCable.config.rpc_host)
|
36
|
-
headers = parse_env_headers || options[:headers]
|
37
|
-
|
38
|
-
@server_id = "anycable-rack-server-#{SecureRandom.hex}"
|
39
|
-
@middleware = Middleware.new(
|
40
|
-
nil,
|
41
|
-
pinger: pinger,
|
42
|
-
hub: hub,
|
43
|
-
coder: coder,
|
44
|
-
rpc_host: rpc_host,
|
45
|
-
headers: headers,
|
46
|
-
server_id: server_id
|
47
|
-
)
|
48
|
-
|
49
|
-
broadcast_subscribe
|
50
|
-
|
51
|
-
@_started = true
|
52
|
-
end
|
53
|
-
|
54
|
-
def started?
|
55
|
-
@_started == true
|
56
|
-
end
|
57
|
-
|
58
|
-
def stop
|
59
|
-
return unless started?
|
60
|
-
|
61
|
-
@_started = false
|
62
|
-
broadcast_subscriber.unsubscribe(@_redis_channel)
|
63
|
-
pinger.stop
|
64
|
-
|
65
|
-
hub.sockets.each do |socket|
|
66
|
-
hub.remove_socket(socket)
|
67
|
-
socket.close
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
private
|
72
|
-
|
73
|
-
def broadcast_subscribe
|
74
|
-
@_redis_params = AnyCable.config.to_redis_params
|
75
|
-
@_redis_channel = AnyCable.config.redis_channel
|
76
|
-
|
77
|
-
@broadcast_subscriber = BroadcastSubscribers::RedisSubscriber.new(
|
78
|
-
hub: @hub,
|
79
|
-
coder: @coder,
|
80
|
-
options: @_redis_params
|
81
|
-
)
|
82
|
-
|
83
|
-
@broadcast_subscriber.subscribe(@_redis_channel)
|
84
|
-
end
|
85
|
-
|
86
|
-
def parse_env_headers
|
87
|
-
headers = ENV['ANYCABLE_HEADERS'].to_s.split(',')
|
88
|
-
return nil if headers.empty?
|
89
|
-
headers
|
90
|
-
end
|
91
|
-
|
92
|
-
def unpack_host(str)
|
93
|
-
str.gsub('[::]', '0.0.0.0')
|
94
|
-
end
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
class Rack
|
99
|
-
def initialize(_app = nil, options = {})
|
100
|
-
AnyCable::RackServer.start(options)
|
101
|
-
end
|
102
|
-
|
103
|
-
def call(env)
|
104
|
-
AnyCable::RackServer.middleware.call(env)
|
105
|
-
end
|
106
|
-
end
|
107
|
-
end
|