uv-rays 2.3.0 → 2.3.1
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/lib/uv-rays.rb +93 -94
- data/lib/uv-rays/abstract_tokenizer.rb +1 -1
- data/lib/uv-rays/buffered_tokenizer.rb +1 -1
- data/lib/uv-rays/connection.rb +188 -188
- data/lib/uv-rays/http_endpoint.rb +296 -296
- data/lib/uv-rays/scheduler.rb +409 -409
- data/lib/uv-rays/scheduler/time.rb +307 -308
- data/lib/uv-rays/tcp_server.rb +44 -44
- data/lib/uv-rays/version.rb +1 -1
- data/spec/scheduler_spec.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3e353fd7111af33397aa886f1ac63dd04f98c77a
|
4
|
+
data.tar.gz: 022c6fd79ee1e2c63126f320051b0eec490eca56
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 41d012acf5a07242274956c7807332e185a91a2173f33a5f7c508c0e01076e3d96a4d0517e0d822aeb81037ef2f797c4422afe4f02bebea4b9b47ccea0882fa2
|
7
|
+
data.tar.gz: 1b9f591075b747c840a7d47d75903459e49afef2c44f99cafad7c3a022552ffb49a1458e8756e71dd9f28301d4302050ceae65e95242b1fa8f0aa7244b186b77
|
data/lib/uv-rays.rb
CHANGED
@@ -1,94 +1,93 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'libuv'
|
4
|
-
|
5
|
-
|
6
|
-
# In-memory event scheduling
|
7
|
-
require 'set' # ruby std lib
|
8
|
-
require 'bisect' # insert into a sorted array
|
9
|
-
require 'tzinfo' # timezone information
|
10
|
-
require 'uv-rays/scheduler/time'
|
11
|
-
require 'uv-rays/scheduler'
|
12
|
-
|
13
|
-
# Intelligent stream buffering
|
14
|
-
require 'uv-rays/buffered_tokenizer'
|
15
|
-
require 'uv-rays/abstract_tokenizer'
|
16
|
-
|
17
|
-
# TCP Connections
|
18
|
-
require 'ipaddress' # IP Address parser
|
19
|
-
require 'uv-rays/tcp_server'
|
20
|
-
require 'uv-rays/connection'
|
21
|
-
|
22
|
-
# HTTP related methods
|
23
|
-
require 'cookiejar' # Manages cookies
|
24
|
-
require 'http-parser' # Parses HTTP request / responses
|
25
|
-
require 'addressable/uri' # URI parser
|
26
|
-
require 'uv-rays/http/encoding'
|
27
|
-
require 'uv-rays/http/request'
|
28
|
-
require 'uv-rays/http/parser'
|
29
|
-
require 'uv-rays/http_endpoint'
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
module UV
|
34
|
-
|
35
|
-
# @private
|
36
|
-
def self.klass_from_handler(klass, handler = nil, *args)
|
37
|
-
klass = if handler and handler.is_a?(Class)
|
38
|
-
raise ArgumentError, "must provide module or subclass of #{klass.name}" unless klass >= handler
|
39
|
-
handler
|
40
|
-
elsif handler
|
41
|
-
begin
|
42
|
-
handler::UR_CONNECTION_CLASS
|
43
|
-
rescue NameError
|
44
|
-
handler::const_set(:UR_CONNECTION_CLASS, Class.new(klass) {include handler})
|
45
|
-
end
|
46
|
-
else
|
47
|
-
klass
|
48
|
-
end
|
49
|
-
|
50
|
-
arity = klass.instance_method(:post_init).arity
|
51
|
-
expected = arity >= 0 ? arity : -(arity + 1)
|
52
|
-
if (arity >= 0 and args.size != expected) or (arity < 0 and args.size < expected)
|
53
|
-
raise ArgumentError, "wrong number of arguments for #{klass}#post_init (#{args.size} for #{expected})"
|
54
|
-
end
|
55
|
-
|
56
|
-
klass
|
57
|
-
end
|
58
|
-
|
59
|
-
|
60
|
-
def self.connect(server, port, handler, *args)
|
61
|
-
klass = klass_from_handler(OutboundConnection, handler, *args)
|
62
|
-
|
63
|
-
c = klass.new server, port
|
64
|
-
c.post_init *args
|
65
|
-
c
|
66
|
-
end
|
67
|
-
|
68
|
-
def self.start_server(server, port, handler, *args)
|
69
|
-
thread = reactor # Get the reactor running on this thread
|
70
|
-
raise ThreadError, "There is no Libuv reactor running on the current thread" if thread.nil?
|
71
|
-
|
72
|
-
klass = klass_from_handler(InboundConnection, handler, *args)
|
73
|
-
UV::TcpServer.new thread, server, port, klass, *args
|
74
|
-
end
|
75
|
-
|
76
|
-
def self.attach_server(sock, handler, *args)
|
77
|
-
thread = reactor # Get the reactor running on this thread
|
78
|
-
raise ThreadError, "There is no Libuv reactor running on the current thread" if thread.nil?
|
79
|
-
|
80
|
-
klass = klass_from_handler(InboundConnection, handler, *args)
|
81
|
-
sd = sock.respond_to?(:fileno) ? sock.fileno : sock
|
82
|
-
|
83
|
-
UV::TcpServer.new thread, sd, sd, klass, *args
|
84
|
-
end
|
85
|
-
|
86
|
-
def self.open_datagram_socket(handler, server = nil, port = nil, *args)
|
87
|
-
klass = klass_from_handler(DatagramConnection, handler, *args)
|
88
|
-
|
89
|
-
c = klass.new server, port
|
90
|
-
c.post_init *args
|
91
|
-
c
|
92
|
-
end
|
93
|
-
end
|
94
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'libuv'
|
4
|
+
|
5
|
+
|
6
|
+
# In-memory event scheduling
|
7
|
+
require 'set' # ruby std lib
|
8
|
+
require 'bisect' # insert into a sorted array
|
9
|
+
require 'tzinfo' # timezone information
|
10
|
+
require 'uv-rays/scheduler/time'
|
11
|
+
require 'uv-rays/scheduler'
|
12
|
+
|
13
|
+
# Intelligent stream buffering
|
14
|
+
require 'uv-rays/buffered_tokenizer'
|
15
|
+
require 'uv-rays/abstract_tokenizer'
|
16
|
+
|
17
|
+
# TCP Connections
|
18
|
+
require 'ipaddress' # IP Address parser
|
19
|
+
require 'uv-rays/tcp_server'
|
20
|
+
require 'uv-rays/connection'
|
21
|
+
|
22
|
+
# HTTP related methods
|
23
|
+
require 'cookiejar' # Manages cookies
|
24
|
+
require 'http-parser' # Parses HTTP request / responses
|
25
|
+
require 'addressable/uri' # URI parser
|
26
|
+
require 'uv-rays/http/encoding'
|
27
|
+
require 'uv-rays/http/request'
|
28
|
+
require 'uv-rays/http/parser'
|
29
|
+
require 'uv-rays/http_endpoint'
|
30
|
+
|
31
|
+
|
32
|
+
|
33
|
+
module UV
|
34
|
+
|
35
|
+
# @private
|
36
|
+
def self.klass_from_handler(klass, handler = nil, *args)
|
37
|
+
klass = if handler and handler.is_a?(Class)
|
38
|
+
raise ArgumentError, "must provide module or subclass of #{klass.name}" unless klass >= handler
|
39
|
+
handler
|
40
|
+
elsif handler
|
41
|
+
begin
|
42
|
+
handler::UR_CONNECTION_CLASS
|
43
|
+
rescue NameError
|
44
|
+
handler::const_set(:UR_CONNECTION_CLASS, Class.new(klass) {include handler})
|
45
|
+
end
|
46
|
+
else
|
47
|
+
klass
|
48
|
+
end
|
49
|
+
|
50
|
+
arity = klass.instance_method(:post_init).arity
|
51
|
+
expected = arity >= 0 ? arity : -(arity + 1)
|
52
|
+
if (arity >= 0 and args.size != expected) or (arity < 0 and args.size < expected)
|
53
|
+
raise ArgumentError, "wrong number of arguments for #{klass}#post_init (#{args.size} for #{expected})"
|
54
|
+
end
|
55
|
+
|
56
|
+
klass
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
def self.connect(server, port, handler, *args)
|
61
|
+
klass = klass_from_handler(OutboundConnection, handler, *args)
|
62
|
+
|
63
|
+
c = klass.new server, port
|
64
|
+
c.post_init *args
|
65
|
+
c
|
66
|
+
end
|
67
|
+
|
68
|
+
def self.start_server(server, port, handler, *args)
|
69
|
+
thread = reactor # Get the reactor running on this thread
|
70
|
+
raise ThreadError, "There is no Libuv reactor running on the current thread" if thread.nil?
|
71
|
+
|
72
|
+
klass = klass_from_handler(InboundConnection, handler, *args)
|
73
|
+
UV::TcpServer.new thread, server, port, klass, *args
|
74
|
+
end
|
75
|
+
|
76
|
+
def self.attach_server(sock, handler, *args)
|
77
|
+
thread = reactor # Get the reactor running on this thread
|
78
|
+
raise ThreadError, "There is no Libuv reactor running on the current thread" if thread.nil?
|
79
|
+
|
80
|
+
klass = klass_from_handler(InboundConnection, handler, *args)
|
81
|
+
sd = sock.respond_to?(:fileno) ? sock.fileno : sock
|
82
|
+
|
83
|
+
UV::TcpServer.new thread, sd, sd, klass, *args
|
84
|
+
end
|
85
|
+
|
86
|
+
def self.open_datagram_socket(handler, server = nil, port = nil, *args)
|
87
|
+
klass = klass_from_handler(DatagramConnection, handler, *args)
|
88
|
+
|
89
|
+
c = klass.new server, port
|
90
|
+
c.post_init *args
|
91
|
+
c
|
92
|
+
end
|
93
|
+
end
|
data/lib/uv-rays/connection.rb
CHANGED
@@ -1,188 +1,188 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module UV
|
4
|
-
def self.try_connect(tcp, handler, server, port)
|
5
|
-
if IPAddress.valid? server
|
6
|
-
tcp.finally handler.method(:on_close)
|
7
|
-
tcp.progress handler.method(:on_read)
|
8
|
-
tcp.connect server, port do
|
9
|
-
tcp.enable_nodelay
|
10
|
-
tcp.start_tls(handler.using_tls) if handler.using_tls
|
11
|
-
|
12
|
-
# on_connect could call use_tls so must come after start_tls
|
13
|
-
handler.on_connect(tcp)
|
14
|
-
tcp.start_read
|
15
|
-
end
|
16
|
-
else
|
17
|
-
tcp.reactor.lookup(server, wait: false).then(
|
18
|
-
proc { |result|
|
19
|
-
UV.try_connect(tcp, handler, result[0][0], port)
|
20
|
-
},
|
21
|
-
proc { |failure|
|
22
|
-
# TODO:: Log error on reactor
|
23
|
-
handler.on_close
|
24
|
-
}
|
25
|
-
)
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
|
30
|
-
# @abstract
|
31
|
-
class Connection
|
32
|
-
attr_reader :using_tls
|
33
|
-
|
34
|
-
def initialize
|
35
|
-
@send_queue = []
|
36
|
-
@paused = false
|
37
|
-
@using_tls = false
|
38
|
-
end
|
39
|
-
|
40
|
-
def pause
|
41
|
-
@paused = true
|
42
|
-
@transport.stop_read
|
43
|
-
end
|
44
|
-
|
45
|
-
def paused?
|
46
|
-
@paused
|
47
|
-
end
|
48
|
-
|
49
|
-
def resume
|
50
|
-
@paused = false
|
51
|
-
@transport.start_read
|
52
|
-
end
|
53
|
-
|
54
|
-
# Compatible with TCP
|
55
|
-
def close_connection(*args)
|
56
|
-
@transport.close
|
57
|
-
end
|
58
|
-
|
59
|
-
def on_read(data, *args) # user to define
|
60
|
-
end
|
61
|
-
|
62
|
-
def post_init(*args)
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
class TcpConnection < Connection
|
67
|
-
def write(data)
|
68
|
-
@transport.write(data, wait: :promise)
|
69
|
-
end
|
70
|
-
|
71
|
-
def close_connection(after_writing = false)
|
72
|
-
if after_writing
|
73
|
-
@transport.shutdown
|
74
|
-
else
|
75
|
-
@transport.close
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
def stream_file(filename, type = :raw)
|
80
|
-
file = @reactor.file(filename, File::RDONLY) do # File is open and available for reading
|
81
|
-
file.send_file(@transport, type, wait: :promise).finally do
|
82
|
-
file.close
|
83
|
-
end
|
84
|
-
end
|
85
|
-
return file
|
86
|
-
end
|
87
|
-
|
88
|
-
def keepalive(raw_time)
|
89
|
-
time = raw_time.to_i
|
90
|
-
if time.to_i <= 0
|
91
|
-
@transport.disable_keepalive
|
92
|
-
else
|
93
|
-
@transport.enable_keepalive(time)
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
|
-
def on_connect(transport) # user to define
|
98
|
-
end
|
99
|
-
|
100
|
-
def on_close # user to define
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
|
-
class InboundConnection < TcpConnection
|
105
|
-
def initialize(tcp)
|
106
|
-
super()
|
107
|
-
|
108
|
-
@reactor = tcp.reactor
|
109
|
-
@transport = tcp
|
110
|
-
@transport.finally method(:on_close)
|
111
|
-
@transport.progress method(:on_read)
|
112
|
-
end
|
113
|
-
|
114
|
-
def use_tls(args = {})
|
115
|
-
args[:server] = true
|
116
|
-
|
117
|
-
if @transport.connected
|
118
|
-
@transport.start_tls(args)
|
119
|
-
else
|
120
|
-
@using_tls = args
|
121
|
-
end
|
122
|
-
end
|
123
|
-
end
|
124
|
-
|
125
|
-
class OutboundConnection < TcpConnection
|
126
|
-
|
127
|
-
def initialize(server, port)
|
128
|
-
super()
|
129
|
-
|
130
|
-
@reactor = reactor
|
131
|
-
@server = server
|
132
|
-
@port = port
|
133
|
-
@transport = @reactor.tcp
|
134
|
-
|
135
|
-
::UV.try_connect(@transport, self, @server, @port)
|
136
|
-
end
|
137
|
-
|
138
|
-
def use_tls(args = {})
|
139
|
-
args.delete(:server)
|
140
|
-
|
141
|
-
if @transport.connected
|
142
|
-
@transport.start_tls(args)
|
143
|
-
else
|
144
|
-
@using_tls = args
|
145
|
-
end
|
146
|
-
end
|
147
|
-
|
148
|
-
def reconnect(server = nil, port = nil)
|
149
|
-
@reactor = reactor
|
150
|
-
|
151
|
-
@transport = @reactor.tcp
|
152
|
-
@server = server || @server
|
153
|
-
@port = port || @port
|
154
|
-
|
155
|
-
::UV.try_connect(@transport, self, @server, @port)
|
156
|
-
end
|
157
|
-
end
|
158
|
-
|
159
|
-
class DatagramConnection < Connection
|
160
|
-
def initialize(server = nil, port = nil)
|
161
|
-
super()
|
162
|
-
|
163
|
-
@reactor = reactor
|
164
|
-
@transport = @reactor.udp
|
165
|
-
@transport.progress method(:on_read)
|
166
|
-
|
167
|
-
if not server.nil?
|
168
|
-
server = '127.0.0.1' if server == 'localhost'
|
169
|
-
raise ArgumentError, "Invalid server address #{server}" unless IPAddress.valid?(server)
|
170
|
-
@transport.bind(server, port)
|
171
|
-
end
|
172
|
-
|
173
|
-
@transport.start_read
|
174
|
-
end
|
175
|
-
|
176
|
-
def send_datagram(data, recipient_address, recipient_port)
|
177
|
-
if IPAddress.valid? recipient_address
|
178
|
-
@transport.send recipient_address, recipient_port, data
|
179
|
-
else
|
180
|
-
# Async DNS resolution
|
181
|
-
# Note:: send here will chain the promise
|
182
|
-
@reactor.lookup(recipient_address).then do |result|
|
183
|
-
@transport.send result[0][0], recipient_port, data
|
184
|
-
end
|
185
|
-
end
|
186
|
-
end
|
187
|
-
end
|
188
|
-
end
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module UV
|
4
|
+
def self.try_connect(tcp, handler, server, port)
|
5
|
+
if IPAddress.valid? server
|
6
|
+
tcp.finally handler.method(:on_close)
|
7
|
+
tcp.progress handler.method(:on_read)
|
8
|
+
tcp.connect server, port do
|
9
|
+
tcp.enable_nodelay
|
10
|
+
tcp.start_tls(handler.using_tls) if handler.using_tls
|
11
|
+
|
12
|
+
# on_connect could call use_tls so must come after start_tls
|
13
|
+
handler.on_connect(tcp)
|
14
|
+
tcp.start_read
|
15
|
+
end
|
16
|
+
else
|
17
|
+
tcp.reactor.lookup(server, wait: false).then(
|
18
|
+
proc { |result|
|
19
|
+
UV.try_connect(tcp, handler, result[0][0], port)
|
20
|
+
},
|
21
|
+
proc { |failure|
|
22
|
+
# TODO:: Log error on reactor
|
23
|
+
handler.on_close
|
24
|
+
}
|
25
|
+
)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
# @abstract
|
31
|
+
class Connection
|
32
|
+
attr_reader :using_tls
|
33
|
+
|
34
|
+
def initialize
|
35
|
+
@send_queue = []
|
36
|
+
@paused = false
|
37
|
+
@using_tls = false
|
38
|
+
end
|
39
|
+
|
40
|
+
def pause
|
41
|
+
@paused = true
|
42
|
+
@transport.stop_read
|
43
|
+
end
|
44
|
+
|
45
|
+
def paused?
|
46
|
+
@paused
|
47
|
+
end
|
48
|
+
|
49
|
+
def resume
|
50
|
+
@paused = false
|
51
|
+
@transport.start_read
|
52
|
+
end
|
53
|
+
|
54
|
+
# Compatible with TCP
|
55
|
+
def close_connection(*args)
|
56
|
+
@transport.close
|
57
|
+
end
|
58
|
+
|
59
|
+
def on_read(data, *args) # user to define
|
60
|
+
end
|
61
|
+
|
62
|
+
def post_init(*args)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
class TcpConnection < Connection
|
67
|
+
def write(data)
|
68
|
+
@transport.write(data, wait: :promise)
|
69
|
+
end
|
70
|
+
|
71
|
+
def close_connection(after_writing = false)
|
72
|
+
if after_writing
|
73
|
+
@transport.shutdown
|
74
|
+
else
|
75
|
+
@transport.close
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def stream_file(filename, type = :raw)
|
80
|
+
file = @reactor.file(filename, File::RDONLY) do # File is open and available for reading
|
81
|
+
file.send_file(@transport, type, wait: :promise).finally do
|
82
|
+
file.close
|
83
|
+
end
|
84
|
+
end
|
85
|
+
return file
|
86
|
+
end
|
87
|
+
|
88
|
+
def keepalive(raw_time)
|
89
|
+
time = raw_time.to_i
|
90
|
+
if time.to_i <= 0
|
91
|
+
@transport.disable_keepalive
|
92
|
+
else
|
93
|
+
@transport.enable_keepalive(time)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def on_connect(transport) # user to define
|
98
|
+
end
|
99
|
+
|
100
|
+
def on_close # user to define
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
class InboundConnection < TcpConnection
|
105
|
+
def initialize(tcp)
|
106
|
+
super()
|
107
|
+
|
108
|
+
@reactor = tcp.reactor
|
109
|
+
@transport = tcp
|
110
|
+
@transport.finally method(:on_close)
|
111
|
+
@transport.progress method(:on_read)
|
112
|
+
end
|
113
|
+
|
114
|
+
def use_tls(args = {})
|
115
|
+
args[:server] = true
|
116
|
+
|
117
|
+
if @transport.connected
|
118
|
+
@transport.start_tls(args)
|
119
|
+
else
|
120
|
+
@using_tls = args
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
class OutboundConnection < TcpConnection
|
126
|
+
|
127
|
+
def initialize(server, port)
|
128
|
+
super()
|
129
|
+
|
130
|
+
@reactor = reactor
|
131
|
+
@server = server
|
132
|
+
@port = port
|
133
|
+
@transport = @reactor.tcp
|
134
|
+
|
135
|
+
::UV.try_connect(@transport, self, @server, @port)
|
136
|
+
end
|
137
|
+
|
138
|
+
def use_tls(args = {})
|
139
|
+
args.delete(:server)
|
140
|
+
|
141
|
+
if @transport.connected
|
142
|
+
@transport.start_tls(args)
|
143
|
+
else
|
144
|
+
@using_tls = args
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
def reconnect(server = nil, port = nil)
|
149
|
+
@reactor = reactor
|
150
|
+
|
151
|
+
@transport = @reactor.tcp
|
152
|
+
@server = server || @server
|
153
|
+
@port = port || @port
|
154
|
+
|
155
|
+
::UV.try_connect(@transport, self, @server, @port)
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
class DatagramConnection < Connection
|
160
|
+
def initialize(server = nil, port = nil)
|
161
|
+
super()
|
162
|
+
|
163
|
+
@reactor = reactor
|
164
|
+
@transport = @reactor.udp
|
165
|
+
@transport.progress method(:on_read)
|
166
|
+
|
167
|
+
if not server.nil?
|
168
|
+
server = '127.0.0.1' if server == 'localhost'
|
169
|
+
raise ArgumentError, "Invalid server address #{server}" unless IPAddress.valid?(server)
|
170
|
+
@transport.bind(server, port)
|
171
|
+
end
|
172
|
+
|
173
|
+
@transport.start_read
|
174
|
+
end
|
175
|
+
|
176
|
+
def send_datagram(data, recipient_address, recipient_port)
|
177
|
+
if IPAddress.valid? recipient_address
|
178
|
+
@transport.send recipient_address, recipient_port, data
|
179
|
+
else
|
180
|
+
# Async DNS resolution
|
181
|
+
# Note:: send here will chain the promise
|
182
|
+
@reactor.lookup(recipient_address).then do |result|
|
183
|
+
@transport.send result[0][0], recipient_port, data
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|