mt-uv-rays 2.4.7

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.
@@ -0,0 +1,189 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'ipaddress' # IP Address parser
4
+ require 'ipaddr'
5
+
6
+ # Based on code from https://github.com/chernesk/net-ping/blob/master/lib/net/ping/external.rb
7
+
8
+ module MTUV; end
9
+ class MTUV::Ping
10
+
11
+ def initialize(host, count: 1, interval: 1, timeout: 5)
12
+ @host = host
13
+ @count = count
14
+ @timeout = timeout
15
+ end
16
+
17
+ attr_reader :host, :ip, :count, :timeout, :exception, :warning, :duration, :pingable
18
+
19
+ def ping
20
+ @ip = if IPAddress.valid?(@host)
21
+ @host
22
+ else
23
+ nslookup(@host)
24
+ end
25
+
26
+ if @ip.nil?
27
+ @pingable = false
28
+ @exception = 'DNS lookup failed for both IPv4 and IPv6'
29
+ return false
30
+ end
31
+
32
+ ipaddr = IPAddr.new @ip
33
+ if ipaddr.ipv4?
34
+ ping4(@ip, @count, @timeout)
35
+ else
36
+ ping6(@ip, @count, @timeout)
37
+ end
38
+ end
39
+
40
+
41
+ protected
42
+
43
+
44
+ def nslookup(domain)
45
+ value = nil
46
+ reactor = MTLibuv::Reactor.current
47
+ begin
48
+ value = reactor.lookup(domain)[0][0]
49
+ rescue => e
50
+ begin
51
+ value = reactor.lookup(domain, :IPv6)[0][0]
52
+ rescue; end
53
+ end
54
+ value
55
+ end
56
+
57
+ def ping4(host, count, timeout)
58
+ pargs = nil
59
+ bool = false
60
+
61
+ case ::RbConfig::CONFIG['host_os']
62
+ when /linux/i
63
+ pargs = ['-c', count.to_s, '-W', timeout.to_s, host]
64
+ when /aix/i
65
+ pargs = ['-c', count.to_s, '-w', timeout.to_s, host]
66
+ when /bsd|osx|mach|darwin/i
67
+ pargs = ['-c', count.to_s, '-t', timeout.to_s, host]
68
+ when /solaris|sunos/i
69
+ pargs = [host, timeout.to_s]
70
+ when /hpux/i
71
+ pargs = [host, "-n#{count.to_s}", '-m', timeout.to_s]
72
+ when /win32|windows|msdos|mswin|cygwin|mingw/i
73
+ pargs = ['-n', count.to_s, '-w', (timeout * 1000).to_s, host]
74
+ else
75
+ pargs = [host]
76
+ end
77
+
78
+ start_time = Time.now
79
+ exitstatus, info, err = spawn_ping('ping', pargs)
80
+
81
+ case exitstatus
82
+ when 0
83
+ if info =~ /unreachable/ix # Windows
84
+ bool = false
85
+ @exception = "host unreachable"
86
+ else
87
+ bool = true # Success, at least one response.
88
+ end
89
+
90
+ if err =~ /warning/i
91
+ @warning = err.chomp
92
+ end
93
+ when 2
94
+ bool = false # Transmission successful, no response.
95
+ @exception = err.chomp if err
96
+ else
97
+ bool = false # An error occurred
98
+ if err
99
+ @exception = err.chomp
100
+ else
101
+ info.each_line do |line|
102
+ if line =~ /(timed out|could not find host|bad address|packet loss)/i
103
+ @exception = line.chomp
104
+ break
105
+ end
106
+ end
107
+ end
108
+ end
109
+
110
+ @duration = Time.now - start_time if bool
111
+ @pingable = bool
112
+ bool
113
+ end
114
+
115
+ def ping6(host, count, timeout)
116
+ pargs = nil
117
+ bool = false
118
+
119
+ case RbConfig::CONFIG['host_os']
120
+ when /linux/i
121
+ pargs =['-c', count.to_s, '-W', timeout.to_s, host]
122
+ when /aix/i
123
+ pargs =['-c', count.to_s, '-w', timeout.to_s, host]
124
+ when /bsd|osx|mach|darwin/i
125
+ pargs =['-c', count.to_s, host]
126
+ when /solaris|sunos/i
127
+ pargs =[host, timeout.to_s]
128
+ when /hpux/i
129
+ pargs =[host, "-n#{count.to_s}", '-m', timeout.to_s]
130
+ when /win32|windows|msdos|mswin|cygwin|mingw/i
131
+ pargs =['-n', count.to_s, '-w', (timeout * 1000).to_s, host]
132
+ else
133
+ pargs =[host]
134
+ end
135
+
136
+ start_time = Time.now
137
+ exitstatus, info, err = spawn_ping('ping6', pargs)
138
+
139
+ case exitstatus
140
+ when 0
141
+ if info =~ /unreachable/ix # Windows
142
+ bool = false
143
+ @exception = "host unreachable"
144
+ else
145
+ bool = true # Success, at least one response.
146
+ end
147
+
148
+ if err =~ /warning/i
149
+ @warning = err.chomp
150
+ end
151
+ when 2
152
+ bool = false # Transmission successful, no response.
153
+ @exception = err.chomp if err
154
+ else
155
+ bool = false # An error occurred
156
+ if err
157
+ @exception = err.chomp
158
+ else
159
+ info.each_line do |line|
160
+ if line =~ /(timed out|could not find host|bad address|packet loss)/i
161
+ @exception = line.chomp
162
+ break
163
+ end
164
+ end
165
+ end
166
+ end
167
+
168
+ @duration = Time.now - start_time if bool
169
+ @pingable = bool
170
+ bool
171
+ end
172
+
173
+ def spawn_ping(cmd, args)
174
+ stdout = String.new
175
+ stderr = String.new
176
+
177
+ process = MTLibuv::Reactor.current.spawn(cmd, args: args)
178
+ process.stdout.progress { |data| stdout << data }
179
+ process.stderr.progress { |data| stderr << data }
180
+ process.stdout.start_read
181
+ process.stderr.start_read
182
+ begin
183
+ process.value
184
+ [0, stdout, stderr]
185
+ rescue => e
186
+ [e.exit_status, stdout, stderr]
187
+ end
188
+ end
189
+ end
@@ -0,0 +1,307 @@
1
+ # frozen_string_literal: true
2
+
3
+ #--
4
+ # Copyright (c) 2006-2013, John Mettraux, jmettraux@gmail.com
5
+ #
6
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ # of this software and associated documentation files (the "Software"), to deal
8
+ # in the Software without restriction, including without limitation the rights
9
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ # copies of the Software, and to permit persons to whom the Software is
11
+ # furnished to do so, subject to the following conditions:
12
+ #
13
+ # The above copyright notice and this permission notice shall be included in
14
+ # all copies or substantial portions of the Software.
15
+ #
16
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
+ # THE SOFTWARE.
23
+ #
24
+ # Made in Japan.
25
+ #++
26
+
27
+ require 'parse-cron'
28
+
29
+
30
+ module MTUV
31
+ class Scheduler
32
+
33
+ # Thread safe timezone time class for use with parse-cron
34
+ class TimeInZone
35
+ def initialize(timezone)
36
+ @timezone = timezone
37
+ end
38
+
39
+ def now
40
+ time = nil
41
+ Time.use_zone(@timezone) do
42
+ time = Time.now
43
+ end
44
+ time
45
+ end
46
+
47
+ def local(*args)
48
+ result = nil
49
+ Time.use_zone(@timezone) do
50
+ result = Time.local(*args)
51
+ end
52
+ result
53
+ end
54
+ end
55
+
56
+
57
+ def self.parse_in(o, quiet = false)
58
+ # if o is an integer we are looking at ms
59
+ o.is_a?(String) ? parse_duration(o, quiet) : o
60
+ end
61
+
62
+ TZ_REGEX = /\b((?:[a-zA-Z][a-zA-z0-9\-+]+)(?:\/[a-zA-Z0-9\-+]+)?)\b/
63
+
64
+ def self.parse_at(o, quiet = false)
65
+ return (o.to_f * 1000).to_i if o.is_a?(Time)
66
+
67
+ tz = nil
68
+ s = o.to_s.gsub(TZ_REGEX) { |m|
69
+ t = TZInfo::Timezone.get(m) rescue nil
70
+ tz ||= t
71
+ t ? '' : m
72
+ }
73
+
74
+ begin
75
+ DateTime.parse(o)
76
+ rescue
77
+ raise ArgumentError, "no time information in #{o.inspect}"
78
+ end if RUBY_VERSION < '1.9.0'
79
+
80
+ t = Time.parse(s)
81
+ t = tz.local_to_utc(t) if tz
82
+ (t.to_f * 1000).to_i # Convert to milliseconds
83
+
84
+ rescue StandardError => se
85
+ return nil if quiet
86
+ raise se
87
+ end
88
+
89
+ def self.parse_cron(o, quiet = false, timezone: nil)
90
+ if timezone
91
+ tz = TimeInZone.new(timezone)
92
+ CronParser.new(o, tz)
93
+ else
94
+ CronParser.new(o)
95
+ end
96
+
97
+ rescue ArgumentError => ae
98
+ return nil if quiet
99
+ raise ae
100
+ end
101
+
102
+ def self.parse_to_time(o)
103
+ t = o
104
+ t = parse(t) if t.is_a?(String)
105
+ t = Time.now + t if t.is_a?(Numeric)
106
+
107
+ raise ArgumentError.new(
108
+ "cannot turn #{o.inspect} to a point in time, doesn't make sense"
109
+ ) unless t.is_a?(Time)
110
+
111
+ t
112
+ end
113
+
114
+ DURATIONS2M = [
115
+ [ 'y', 365 * 24 * 3600 * 1000 ],
116
+ [ 'M', 30 * 24 * 3600 * 1000 ],
117
+ [ 'w', 7 * 24 * 3600 * 1000 ],
118
+ [ 'd', 24 * 3600 * 1000 ],
119
+ [ 'h', 3600 * 1000 ],
120
+ [ 'm', 60 * 1000 ],
121
+ [ 's', 1000 ]
122
+ ]
123
+ DURATIONS2 = DURATIONS2M.dup
124
+ DURATIONS2.delete_at(1)
125
+
126
+ DURATIONS = DURATIONS2M.inject({}) { |r, (k, v)| r[k] = v; r }
127
+ DURATION_LETTERS = DURATIONS.keys.join
128
+
129
+ DU_KEYS = DURATIONS2M.collect { |k, v| k.to_sym }
130
+
131
+ # Turns a string like '1m10s' into a float like '70.0', more formally,
132
+ # turns a time duration expressed as a string into a Float instance
133
+ # (millisecond count).
134
+ #
135
+ # w -> week
136
+ # d -> day
137
+ # h -> hour
138
+ # m -> minute
139
+ # s -> second
140
+ # M -> month
141
+ # y -> year
142
+ # 'nada' -> millisecond
143
+ #
144
+ # Some examples:
145
+ #
146
+ # Rufus::Scheduler.parse_duration "0.5" # => 0.5
147
+ # Rufus::Scheduler.parse_duration "500" # => 0.5
148
+ # Rufus::Scheduler.parse_duration "1000" # => 1.0
149
+ # Rufus::Scheduler.parse_duration "1h" # => 3600.0
150
+ # Rufus::Scheduler.parse_duration "1h10s" # => 3610.0
151
+ # Rufus::Scheduler.parse_duration "1w2d" # => 777600.0
152
+ #
153
+ # Negative time strings are OK (Thanks Danny Fullerton):
154
+ #
155
+ # Rufus::Scheduler.parse_duration "-0.5" # => -0.5
156
+ # Rufus::Scheduler.parse_duration "-1h" # => -3600.0
157
+ #
158
+ def self.parse_duration(string, quiet = false)
159
+ string = string.to_s
160
+
161
+ return 0 if string == ''
162
+
163
+ m = string.match(/^(-?)([\d\.#{DURATION_LETTERS}]+)$/)
164
+
165
+ return nil if m.nil? && quiet
166
+ raise ArgumentError.new("cannot parse '#{string}'") if m.nil?
167
+
168
+ mod = m[1] == '-' ? -1.0 : 1.0
169
+ val = 0.0
170
+
171
+ s = m[2]
172
+
173
+ while s.length > 0
174
+ m = nil
175
+ if m = s.match(/^(\d+|\d+\.\d*|\d*\.\d+)([#{DURATION_LETTERS}])(.*)$/)
176
+ val += m[1].to_f * DURATIONS[m[2]]
177
+ elsif s.match(/^\d+$/)
178
+ val += s.to_i
179
+ elsif s.match(/^\d*\.\d*$/)
180
+ val += s.to_f
181
+ elsif quiet
182
+ return nil
183
+ else
184
+ raise ArgumentError.new(
185
+ "cannot parse '#{string}' (unexpected '#{s}')"
186
+ )
187
+ end
188
+ break unless m && m[3]
189
+ s = m[3]
190
+ end
191
+
192
+ res = mod * val
193
+ res.to_i
194
+ end
195
+
196
+
197
+ # Turns a number of seconds into a a time string
198
+ #
199
+ # Rufus.to_duration 0 # => '0s'
200
+ # Rufus.to_duration 60 # => '1m'
201
+ # Rufus.to_duration 3661 # => '1h1m1s'
202
+ # Rufus.to_duration 7 * 24 * 3600 # => '1w'
203
+ # Rufus.to_duration 30 * 24 * 3600 + 1 # => "4w2d1s"
204
+ #
205
+ # It goes from seconds to the year. Months are not counted (as they
206
+ # are of variable length). Weeks are counted.
207
+ #
208
+ # For 30 days months to be counted, the second parameter of this
209
+ # method can be set to true.
210
+ #
211
+ # Rufus.to_duration 30 * 24 * 3600 + 1, true # => "1M1s"
212
+ #
213
+ # If a Float value is passed, milliseconds will be displayed without
214
+ # 'marker'
215
+ #
216
+ # Rufus.to_duration 0.051 # => "51"
217
+ # Rufus.to_duration 7.051 # => "7s51"
218
+ # Rufus.to_duration 0.120 + 30 * 24 * 3600 + 1 # => "4w2d1s120"
219
+ #
220
+ # (this behaviour mirrors the one found for parse_time_string()).
221
+ #
222
+ # Options are :
223
+ #
224
+ # * :months, if set to true, months (M) of 30 days will be taken into
225
+ # account when building up the result
226
+ # * :drop_seconds, if set to true, seconds and milliseconds will be trimmed
227
+ # from the result
228
+ #
229
+ def self.to_duration(seconds, options = {})
230
+ h = to_duration_hash(seconds, options)
231
+
232
+ return (options[:drop_seconds] ? '0m' : '0s') if h.empty?
233
+
234
+ s = DU_KEYS.inject(String.new) { |r, key|
235
+ count = h[key]
236
+ count = nil if count == 0
237
+ r << "#{count}#{key}" if count
238
+ r
239
+ }
240
+
241
+ ms = h[:ms]
242
+ s << ms.to_s if ms
243
+ s
244
+ end
245
+
246
+ # Turns a number of seconds (integer or Float) into a hash like in :
247
+ #
248
+ # Rufus.to_duration_hash 0.051
249
+ # # => { :ms => "51" }
250
+ # Rufus.to_duration_hash 7.051
251
+ # # => { :s => 7, :ms => "51" }
252
+ # Rufus.to_duration_hash 0.120 + 30 * 24 * 3600 + 1
253
+ # # => { :w => 4, :d => 2, :s => 1, :ms => "120" }
254
+ #
255
+ # This method is used by to_duration behind the scenes.
256
+ #
257
+ # Options are :
258
+ #
259
+ # * :months, if set to true, months (M) of 30 days will be taken into
260
+ # account when building up the result
261
+ # * :drop_seconds, if set to true, seconds and milliseconds will be trimmed
262
+ # from the result
263
+ #
264
+ def self.to_duration_hash(seconds, options = {})
265
+ h = {}
266
+
267
+ if (seconds % 1000) > 0
268
+ h[:ms] = (seconds % 1000).to_i
269
+ seconds = (seconds / 1000).to_i * 1000
270
+ end
271
+
272
+ if options[:drop_seconds]
273
+ h.delete(:ms)
274
+ seconds = (seconds - seconds % 60000)
275
+ end
276
+
277
+ durations = options[:months] ? DURATIONS2M : DURATIONS2
278
+
279
+ durations.each do |key, duration|
280
+ count = seconds / duration
281
+ seconds = seconds % duration
282
+
283
+ h[key.to_sym] = count if count > 0
284
+ end
285
+
286
+ h
287
+ end
288
+
289
+ #--
290
+ # misc
291
+ #++
292
+
293
+ # Produces the UTC string representation of a Time instance
294
+ #
295
+ # like "2009/11/23 11:11:50.947109 UTC"
296
+ #
297
+ def self.utc_to_s(t=Time.now)
298
+ "#{t.utc.strftime('%Y-%m-%d %H:%M:%S')}.#{sprintf('%06d', t.usec)} UTC"
299
+ end
300
+
301
+ # Produces a hour/min/sec/milli string representation of Time instance
302
+ #
303
+ def self.h_to_s(t=Time.now)
304
+ "#{t.strftime('%H:%M:%S')}.#{sprintf('%06d', t.usec)}"
305
+ end
306
+ end
307
+ end