cztop 1.1.1 → 1.1.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 066d9600730db24e49b9b83fee30840882432df13dde7372f9e7f969b3774b33
4
- data.tar.gz: 67ee0941443c6a9eadf7d27b4bc084e00d20c2dc7ca4448fc6459edc93a88efb
3
+ metadata.gz: 3f398a80bc75445bfd115544ca7f3e4c9f894cd1b9d58a9f0e2a90f6c0841275
4
+ data.tar.gz: 4d6b4c393b573c8bd64f4a65317bd6bbf258c5c2a7137ecabc681be6713c6f6a
5
5
  SHA512:
6
- metadata.gz: c8852f4b214935ef5b0302a7a6481a2f51148dfc6fac939ca9d9b5f665ab06d8242418bdbe996edb9ad6fe010a84a540fd9b24e379cdd5b3197fd3c7a80f0478
7
- data.tar.gz: 506f6e6b9a927e8c68d60c410d3ed84abfae1edef435c43baae8855eb2f02409815692eb4cf18501298ab5c8f9c988cdd48d308a93eb20d1ae136bf51c8283fe
6
+ metadata.gz: 12567ad2f7cadeb6067edcf61fb3ba975635d236edd4a5dd5465b6dcb931cf7c8b4f5852892c5bd4c0c5f0aaa87488f21b7ccb81a73a5d4134928b55f276ce4a
7
+ data.tar.gz: 99d6274e17d86865e80328184825f525f2959dbe926e052c9af88423f40e0fbf6f53531ef5de8eb22225315f2629e3580fd34f094031c21bbb37a665946d58b7
data/CHANGES.md CHANGED
@@ -1,3 +1,8 @@
1
+ 1.1.2 (1/5/2024)
2
+ -----
3
+ * refactor to make code Fiber Scheduler agnostic
4
+ * remove Async::IO::CZTopSocket
5
+
1
6
  1.1.1 (1/4/2024)
2
7
  -----
3
8
  * speed up Async::IO#wait_readable and #wait_writable
data/README.md CHANGED
@@ -13,22 +13,22 @@ mechanisms (like CURVE).
13
13
 
14
14
  ## Example with Async
15
15
 
16
+ See [this example](https://github.com/paddor/cztop/blob/master/examples/async.rb):
17
+
16
18
  ```ruby
17
19
  #! /usr/bin/env ruby
18
20
 
19
- require 'cztop/async'
21
+ require 'cztop'
20
22
 
21
23
  Async do |task|
22
24
  task.async do |t|
23
25
  socket = CZTop::Socket::REP.new("inproc://req_rep_example")
24
- io = Async::IO.try_convert socket
25
-
26
26
  socket.options.rcvtimeo = 50 # ms
27
27
 
28
28
  loop do
29
- msg = io.receive
29
+ msg = socket.receive
30
30
  puts "<<< #{msg.to_a.inspect}"
31
- io << msg.to_a.map(&:upcase)
31
+ socket << msg.to_a.map(&:upcase)
32
32
  rescue IO::TimeoutError
33
33
  break
34
34
  end
@@ -38,11 +38,10 @@ Async do |task|
38
38
 
39
39
  task.async do
40
40
  socket = CZTop::Socket::REQ.new("inproc://req_rep_example")
41
- io = Async::IO.try_convert socket
42
41
 
43
42
  10.times do |i|
44
- io << "foobar ##{i}"
45
- msg = io.receive
43
+ socket << "foobar ##{i}"
44
+ msg = socket.receive
46
45
  puts ">>> #{msg.to_a.inspect}"
47
46
  end
48
47
 
@@ -54,6 +53,8 @@ end
54
53
 
55
54
  Output:
56
55
  ```
56
+ $ cd examples
57
+ $ time ./async.rb
57
58
  <<< ["foobar #0"]
58
59
  >>> ["FOOBAR #0"]
59
60
  <<< ["foobar #1"]
@@ -76,61 +77,20 @@ Output:
76
77
  >>> ["FOOBAR #9"]
77
78
  REQ done.
78
79
  REP done.
79
- 0.46user 0.09system 0:00.60elapsed 90%CPU (0avgtext+0avgdata 47296maxresident)k
80
- 0inputs+0outputs (0major+13669minor)pagefaults 0swaps
81
- ```
82
-
83
- ## Overview
84
-
85
- ### Class Hierarchy
86
80
 
87
- Here's an overview of the core classes:
81
+ ________________________________________________________
82
+ Executed in 401.51 millis fish external
83
+ usr time 308.44 millis 605.00 micros 307.83 millis
84
+ sys time 40.08 millis 278.00 micros 39.81 millis
88
85
 
89
- * [CZTop](http://www.rubydoc.info/gems/cztop/CZTop)
90
- * [Actor](http://www.rubydoc.info/gems/cztop/CZTop)
91
- * [Authenticator](http://www.rubydoc.info/gems/cztop/CZTop/Authenticator)
92
- * [Beacon](http://www.rubydoc.info/gems/cztop/CZTop/Beacon)
93
- * [Certificate](http://www.rubydoc.info/gems/cztop/CZTop/Certificate)
94
- * [CertStore](http://www.rubydoc.info/gems/cztop/CZTop/CertStore)
95
- * [Config](http://www.rubydoc.info/gems/cztop/CZTop/Config)
96
- * [Frame](http://www.rubydoc.info/gems/cztop/CZTop/Frame)
97
- * [Message](http://www.rubydoc.info/gems/cztop/CZTop/Message)
98
- * [Monitor](http://www.rubydoc.info/gems/cztop/CZTop/Monitor)
99
- * [Metadata](http://www.rubydoc.info/gems/cztop/CZTop/Metadata)
100
- * [Proxy](http://www.rubydoc.info/gems/cztop/CZTop/Proxy)
101
- * [Poller](http://www.rubydoc.info/gems/cztop/CZTop/Poller) (based on `zmq_poller_*()` functions)
102
- * [Aggregated](http://www.rubydoc.info/gems/cztop/CZTop/Poller/Aggregated)
103
- * [ZPoller](http://www.rubydoc.info/gems/cztop/CZTop/Poller/ZPoller)
104
- * [Socket](http://www.rubydoc.info/gems/cztop/CZTop/Socket)
105
- * [REQ](http://www.rubydoc.info/gems/cztop/CZTop/Socket/REQ) < Socket
106
- * [REP](http://www.rubydoc.info/gems/cztop/CZTop/Socket/REP) < Socket
107
- * [ROUTER](http://www.rubydoc.info/gems/cztop/CZTop/Socket/ROUTER) < Socket
108
- * [DEALER](http://www.rubydoc.info/gems/cztop/CZTop/Socket/DEALER) < Socket
109
- * [PUSH](http://www.rubydoc.info/gems/cztop/CZTop/Socket/PUSH) < Socket
110
- * [PULL](http://www.rubydoc.info/gems/cztop/CZTop/Socket/PULL) < Socket
111
- * [PUB](http://www.rubydoc.info/gems/cztop/CZTop/Socket/PUB) < Socket
112
- * [SUB](http://www.rubydoc.info/gems/cztop/CZTop/Socket/SUB) < Socket
113
- * [XPUB](http://www.rubydoc.info/gems/cztop/CZTop/Socket/XPUB) < Socket
114
- * [XSUB](http://www.rubydoc.info/gems/cztop/CZTop/Socket/XSUB) < Socket
115
- * [PAIR](http://www.rubydoc.info/gems/cztop/CZTop/Socket/PAIR) < Socket
116
- * [STREAM](http://www.rubydoc.info/gems/cztop/CZTop/Socket/STREAM) < Socket
117
- * [CLIENT](http://www.rubydoc.info/gems/cztop/CZTop/Socket/CLIENT) < Socket
118
- * [SERVER](http://www.rubydoc.info/gems/cztop/CZTop/Socket/SERVER) < Socket
119
- * [RADIO](http://www.rubydoc.info/gems/cztop/CZTop/Socket/RADIO) < Socket
120
- * [DISH](http://www.rubydoc.info/gems/cztop/CZTop/Socket/DISH) < Socket
121
- * [SCATTER](http://www.rubydoc.info/gems/cztop/CZTop/Socket/SCATTER) < Socket
122
- * [GATHER](http://www.rubydoc.info/gems/cztop/CZTop/Socket/GATHER) < Socket
123
- * [Z85](http://www.rubydoc.info/gems/cztop/CZTop/Z85)
124
- * [Padded](http://www.rubydoc.info/gems/cztop/CZTop/Z85/Padded) < Z85
125
- * [Pipe](http://www.rubydoc.info/gems/cztop/CZTop/Z85/Pipe)
126
- * [ZAP](http://www.rubydoc.info/gems/cztop/CZTop/ZAP)
86
+ ```
127
87
 
128
- More information in the [API documentation](http://www.rubydoc.info/github/paddor/cztop).
88
+ ## Overview
129
89
 
130
90
  ### Features
131
91
 
132
92
  * Ruby idiomatic API
133
- * compatible with [Async](https://github.com/socketry/async) / [Async::IO](https://github.com/socketry/async-io)
93
+ * Fiber Scheduler aware
134
94
  * errors as exceptions
135
95
  * CURVE security
136
96
  * supports CZMQ DRAFT API
@@ -175,6 +135,51 @@ Or install it yourself as:
175
135
 
176
136
  $ gem install cztop
177
137
 
138
+ ### Class Hierarchy
139
+
140
+ Here's an overview of the core classes:
141
+
142
+ * [CZTop](http://www.rubydoc.info/gems/cztop/CZTop)
143
+ * [Actor](http://www.rubydoc.info/gems/cztop/CZTop)
144
+ * [Authenticator](http://www.rubydoc.info/gems/cztop/CZTop/Authenticator)
145
+ * [Beacon](http://www.rubydoc.info/gems/cztop/CZTop/Beacon)
146
+ * [Certificate](http://www.rubydoc.info/gems/cztop/CZTop/Certificate)
147
+ * [CertStore](http://www.rubydoc.info/gems/cztop/CZTop/CertStore)
148
+ * [Config](http://www.rubydoc.info/gems/cztop/CZTop/Config)
149
+ * [Frame](http://www.rubydoc.info/gems/cztop/CZTop/Frame)
150
+ * [Message](http://www.rubydoc.info/gems/cztop/CZTop/Message)
151
+ * [Monitor](http://www.rubydoc.info/gems/cztop/CZTop/Monitor)
152
+ * [Metadata](http://www.rubydoc.info/gems/cztop/CZTop/Metadata)
153
+ * [Proxy](http://www.rubydoc.info/gems/cztop/CZTop/Proxy)
154
+ * [Poller](http://www.rubydoc.info/gems/cztop/CZTop/Poller) (based on `zmq_poller_*()` functions)
155
+ * [Aggregated](http://www.rubydoc.info/gems/cztop/CZTop/Poller/Aggregated)
156
+ * [ZPoller](http://www.rubydoc.info/gems/cztop/CZTop/Poller/ZPoller)
157
+ * [Socket](http://www.rubydoc.info/gems/cztop/CZTop/Socket)
158
+ * [REQ](http://www.rubydoc.info/gems/cztop/CZTop/Socket/REQ) < Socket
159
+ * [REP](http://www.rubydoc.info/gems/cztop/CZTop/Socket/REP) < Socket
160
+ * [ROUTER](http://www.rubydoc.info/gems/cztop/CZTop/Socket/ROUTER) < Socket
161
+ * [DEALER](http://www.rubydoc.info/gems/cztop/CZTop/Socket/DEALER) < Socket
162
+ * [PUSH](http://www.rubydoc.info/gems/cztop/CZTop/Socket/PUSH) < Socket
163
+ * [PULL](http://www.rubydoc.info/gems/cztop/CZTop/Socket/PULL) < Socket
164
+ * [PUB](http://www.rubydoc.info/gems/cztop/CZTop/Socket/PUB) < Socket
165
+ * [SUB](http://www.rubydoc.info/gems/cztop/CZTop/Socket/SUB) < Socket
166
+ * [XPUB](http://www.rubydoc.info/gems/cztop/CZTop/Socket/XPUB) < Socket
167
+ * [XSUB](http://www.rubydoc.info/gems/cztop/CZTop/Socket/XSUB) < Socket
168
+ * [PAIR](http://www.rubydoc.info/gems/cztop/CZTop/Socket/PAIR) < Socket
169
+ * [STREAM](http://www.rubydoc.info/gems/cztop/CZTop/Socket/STREAM) < Socket
170
+ * [CLIENT](http://www.rubydoc.info/gems/cztop/CZTop/Socket/CLIENT) < Socket
171
+ * [SERVER](http://www.rubydoc.info/gems/cztop/CZTop/Socket/SERVER) < Socket
172
+ * [RADIO](http://www.rubydoc.info/gems/cztop/CZTop/Socket/RADIO) < Socket
173
+ * [DISH](http://www.rubydoc.info/gems/cztop/CZTop/Socket/DISH) < Socket
174
+ * [SCATTER](http://www.rubydoc.info/gems/cztop/CZTop/Socket/SCATTER) < Socket
175
+ * [GATHER](http://www.rubydoc.info/gems/cztop/CZTop/Socket/GATHER) < Socket
176
+ * [Z85](http://www.rubydoc.info/gems/cztop/CZTop/Z85)
177
+ * [Padded](http://www.rubydoc.info/gems/cztop/CZTop/Z85/Padded) < Z85
178
+ * [Pipe](http://www.rubydoc.info/gems/cztop/CZTop/Z85/Pipe)
179
+ * [ZAP](http://www.rubydoc.info/gems/cztop/CZTop/ZAP)
180
+
181
+ More information in the [API documentation](http://www.rubydoc.info/github/paddor/cztop).
182
+
178
183
  ## Documentation
179
184
 
180
185
  The API should be fairly straight-forward to anyone who is familiar with CZMQ
data/cztop.gemspec CHANGED
@@ -36,6 +36,5 @@ Gem::Specification.new do |spec|
36
36
 
37
37
  if RUBY_VERSION >= '3.1'
38
38
  spec.add_development_dependency "async", ">= 2.0.1"
39
- spec.add_development_dependency "async-io"
40
39
  end
41
40
  end
data/lib/cztop/message.rb CHANGED
@@ -61,6 +61,8 @@ module CZTop
61
61
  # returns with failure. Please report as bug.
62
62
  #
63
63
  def send_to(destination)
64
+ destination.wait_writable if Fiber.scheduler
65
+
64
66
  rc = Zmsg.send(ffi_delegate, destination)
65
67
  return if rc.zero?
66
68
 
@@ -79,6 +81,8 @@ module CZTop
79
81
  # @raise [SystemCallError] for any other error code set after +zmsg_recv+
80
82
  # returns with failure. Please report as bug.
81
83
  def self.receive_from(source)
84
+ source.wait_readable if Fiber.scheduler
85
+
82
86
  delegate = Zmsg.recv(source)
83
87
  return from_ffi_delegate(delegate) unless delegate.null?
84
88
 
@@ -35,5 +35,80 @@ module CZTop
35
35
  Message.receive_from(self)
36
36
  end
37
37
 
38
+
39
+ # Waits for socket to become readable.
40
+ def wait_readable(timeout = read_timeout)
41
+ return true if readable?
42
+
43
+ @fd_io ||= to_io
44
+
45
+ if timeout
46
+ timeout_at = now + timeout
47
+
48
+ while true
49
+ @fd_io.wait_readable(timeout)
50
+ break if readable? # NOTE: ZMQ FD can't be trusted 100%
51
+ raise ::IO::TimeoutError if now >= timeout_at
52
+ end
53
+ else
54
+ @fd_io.wait_readable until readable?
55
+ end
56
+ end
57
+
58
+
59
+ # Waits for socket to become writable.
60
+ def wait_writable(timeout = write_timeout)
61
+ return true if writable?
62
+
63
+ @fd_io ||= to_io
64
+
65
+ if timeout
66
+ timeout_at = now + timeout
67
+
68
+ while true
69
+ @fd_io.wait_writable(timeout)
70
+ break if writable? # NOTE: ZMQ FD can't be trusted 100%
71
+ raise ::IO::TimeoutError if now >= timeout_at
72
+ end
73
+ else
74
+ @fd_io.wait_writable until writable?
75
+ end
76
+ end
77
+
78
+
79
+ # @return [Float, nil] the timeout in seconds used by {IO#wait_readable}
80
+ def read_timeout
81
+ timeout = options.rcvtimeo
82
+
83
+ if timeout <= 0
84
+ timeout = nil
85
+ else
86
+ timeout = timeout.to_f / 1000
87
+ end
88
+
89
+ timeout
90
+ end
91
+
92
+
93
+ # @return [Float, nil] the timeout in seconds used by {IO#wait_writable}
94
+ def write_timeout
95
+ timeout = options.sndtimeo
96
+
97
+ if timeout <= 0
98
+ timeout = nil
99
+ else
100
+ timeout = timeout.to_f / 1000
101
+ end
102
+
103
+ timeout
104
+ end
105
+
106
+
107
+ private
108
+
109
+
110
+ def now
111
+ Process.clock_gettime(Process::CLOCK_MONOTONIC)
112
+ end
38
113
  end
39
114
  end
data/lib/cztop/version.rb CHANGED
@@ -2,6 +2,6 @@
2
2
 
3
3
  module CZTop
4
4
 
5
- VERSION = '1.1.1'
5
+ VERSION = '1.1.2'
6
6
 
7
7
  end
@@ -43,6 +43,12 @@ module CZTop
43
43
  end
44
44
 
45
45
 
46
+ # @return [IO] IO for FD
47
+ def to_io
48
+ IO.for_fd fd, autoclose: false
49
+ end
50
+
51
+
46
52
  # Used to access the options of a {Socket} or {Actor}.
47
53
  class OptionsAccessor
48
54
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cztop
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.1
4
+ version: 1.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Patrik Wenger
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-01-04 00:00:00.000000000 Z
11
+ date: 2024-01-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: czmq-ffi-gen
@@ -150,20 +150,6 @@ dependencies:
150
150
  - - ">="
151
151
  - !ruby/object:Gem::Version
152
152
  version: 2.0.1
153
- - !ruby/object:Gem::Dependency
154
- name: async-io
155
- requirement: !ruby/object:Gem::Requirement
156
- requirements:
157
- - - ">="
158
- - !ruby/object:Gem::Version
159
- version: '0'
160
- type: :development
161
- prerelease: false
162
- version_requirements: !ruby/object:Gem::Requirement
163
- requirements:
164
- - - ">="
165
- - !ruby/object:Gem::Version
166
- version: '0'
167
153
  description: CZMQ binding based on the generated low-level FFI bindings of CZMQ
168
154
  email:
169
155
  - paddor@gmail.com
@@ -192,10 +178,6 @@ files:
192
178
  - ci/install-libczmq
193
179
  - ci/install-libzmq
194
180
  - cztop.gemspec
195
- - examples/async/.gitignore
196
- - examples/async/Gemfile
197
- - examples/async/README.md
198
- - examples/async/async.rb
199
181
  - examples/ruby_actor/actor.rb
200
182
  - examples/simple_req_rep/rep.rb
201
183
  - examples/simple_req_rep/req.rb
@@ -214,7 +196,6 @@ files:
214
196
  - exe/z85encode
215
197
  - lib/cztop.rb
216
198
  - lib/cztop/actor.rb
217
- - lib/cztop/async.rb
218
199
  - lib/cztop/authenticator.rb
219
200
  - lib/cztop/beacon.rb
220
201
  - lib/cztop/cert_store.rb
@@ -1 +0,0 @@
1
- /Gemfile.lock
@@ -1,5 +0,0 @@
1
- source 'https://rubygems.org'
2
-
3
- gem 'async'
4
- gem 'cztop', path: '../../'
5
- gem 'async-io'
@@ -1 +0,0 @@
1
- Run: `bundle exec ./async.rb`
@@ -1,35 +0,0 @@
1
- #! /usr/bin/env ruby
2
-
3
- require 'cztop/async'
4
-
5
- Async do |task|
6
- task.async do |t|
7
- socket = CZTop::Socket::REP.new("inproc://req_rep_example")
8
- io = Async::IO.try_convert socket
9
-
10
- socket.options.rcvtimeo = 50 # ms
11
-
12
- loop do
13
- msg = io.receive
14
- puts "<<< #{msg.to_a.inspect}"
15
- io << msg.to_a.map(&:upcase)
16
- rescue IO::TimeoutError
17
- break
18
- end
19
-
20
- puts "REP done."
21
- end
22
-
23
- task.async do
24
- socket = CZTop::Socket::REQ.new("inproc://req_rep_example")
25
- io = Async::IO.try_convert socket
26
-
27
- 10.times do |i|
28
- io << "foobar ##{i}"
29
- msg = io.receive
30
- puts ">>> #{msg.to_a.inspect}"
31
- end
32
-
33
- puts "REQ done."
34
- end
35
- end
data/lib/cztop/async.rb DELETED
@@ -1,124 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'cztop'
4
- require 'async/io'
5
-
6
- module Async
7
- module IO
8
-
9
- # Wrapper for CZTop sockets.
10
- #
11
- # @example
12
- # Async do |task|
13
- # socket = CZTop::Socket::REP.new("ipc:///tmp/req_rep_example")
14
- # socket.options.rcvtimeo = 3
15
- # io = Async::IO.try_convert socket
16
- # msg = io.receive
17
- # io << msg.to_a.map(&:upcase)
18
- # end
19
-
20
- class CZTopSocket < Generic
21
- wraps ::CZTop::Socket::REQ
22
- wraps ::CZTop::Socket::REP
23
- wraps ::CZTop::Socket::PAIR
24
- wraps ::CZTop::Socket::ROUTER
25
- wraps ::CZTop::Socket::DEALER
26
- wraps ::CZTop::Socket::PUSH
27
- wraps ::CZTop::Socket::PULL
28
- wraps ::CZTop::Socket::PUB
29
- wraps ::CZTop::Socket::SUB
30
- wraps ::CZTop::Socket::XPUB
31
- wraps ::CZTop::Socket::XSUB
32
-
33
-
34
- # @see {CZTop::SendReceiveMethods#receive}
35
- def receive
36
- wait_readable
37
- @io.receive
38
- end
39
-
40
-
41
- # @see {CZTop::SendReceiveMethods#<<}
42
- def <<(...)
43
- wait_writable
44
- @io.<<(...)
45
- end
46
-
47
-
48
- # Waits for socket to become readable.
49
- def wait_readable(timeout = read_timeout)
50
- @io_fd ||= ::IO.for_fd @io.fd, autoclose: false
51
-
52
- return true if @io.readable?
53
-
54
- if timeout
55
- timeout_at = now + timeout
56
-
57
- while true
58
- @io_fd.wait_readable(timeout)
59
- break if @io.readable?
60
- raise ::IO::TimeoutError if now >= timeout_at
61
- end
62
- else
63
- @io_fd.wait_readable until @io.readable?
64
- end
65
- end
66
-
67
-
68
- # Waits for socket to become writable.
69
- def wait_writable(timeout = write_timeout)
70
- @io_fd ||= ::IO.for_fd @io.fd, autoclose: false
71
-
72
- return true if @io.writable?
73
-
74
- if timeout
75
- timeout_at = now + timeout
76
-
77
- while true
78
- @io_fd.wait_writable(timeout)
79
- break if @io.writable?
80
- raise ::IO::TimeoutError if now >= timeout_at
81
- end
82
- else
83
- @io_fd.wait_writable until @io.writable?
84
- end
85
- end
86
-
87
-
88
- # @return [Float, nil] the timeout in seconds used by {IO#wait_readable}
89
- def read_timeout
90
- timeout = @io.options.rcvtimeo
91
-
92
- if timeout <= 0
93
- timeout = nil
94
- else
95
- timeout = timeout.to_f / 1000
96
- end
97
-
98
- timeout
99
- end
100
-
101
-
102
- # @return [Float, nil] the timeout in seconds used by {IO#wait_writable}
103
- def write_timeout
104
- timeout = @io.options.sndtimeo
105
-
106
- if timeout <= 0
107
- timeout = nil
108
- else
109
- timeout = timeout.to_f / 1000
110
- end
111
-
112
- timeout
113
- end
114
-
115
-
116
- private
117
-
118
-
119
- def now
120
- Process.clock_gettime(Process::CLOCK_MONOTONIC)
121
- end
122
- end
123
- end
124
- end