Onlooker 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README +46 -0
- data/lib/net/ping.rb +11 -0
- data/lib/net/ping/external.rb +107 -0
- data/lib/net/ping/http.rb +88 -0
- data/lib/net/ping/icmp.rb +165 -0
- data/lib/net/ping/ping.rb +81 -0
- data/lib/net/ping/tcp.rb +86 -0
- data/lib/net/ping/udp.rb +119 -0
- data/lib/onlooker.rb +48 -0
- data/test/onlooker_test.rb +8 -0
- metadata +66 -0
data/README
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
Onlooker v0.1
|
2
|
+
=============
|
3
|
+
|
4
|
+
OnLooker is a simple rails plugin that lets a user check the status of his or her website or server. OnLooker uses Ping's to check via TCP or HTTP whether the site, sites or servers that you specify are online and accessible. OnLooker also supports custom images to distinguish status.
|
5
|
+
|
6
|
+
|
7
|
+
Example
|
8
|
+
=======
|
9
|
+
|
10
|
+
To use this plugin, simply call the check function in your controller such as:
|
11
|
+
|
12
|
+
For a Website: @status = OnLooker.check('www.rubyonrails.com', 'web')
|
13
|
+
|
14
|
+
For an IP: @status = OnLooker.check('207.179.66.134', 'ip')
|
15
|
+
|
16
|
+
Then in your views:
|
17
|
+
|
18
|
+
<%= @status %>
|
19
|
+
|
20
|
+
This will report the text "Online" or "Offline" depending on the result of the check.
|
21
|
+
|
22
|
+
The available options for OnLooker.check are:
|
23
|
+
|
24
|
+
- OnLooker.check(host, type, debug)
|
25
|
+
- Host can be a URL (without the http://) or IP
|
26
|
+
- Type can be set to web or ip
|
27
|
+
- Debug can be true or false in which OnLooker will attempt to give an explanation if your site is down
|
28
|
+
|
29
|
+
|
30
|
+
Using images to distinguish statuses:
|
31
|
+
|
32
|
+
OnLooker includes a basic helper to allow you to set an image for displaying online or offline status.
|
33
|
+
|
34
|
+
For example, If you call the OnLooker.check function from the @status variable in your controller, your views can look something like this:
|
35
|
+
|
36
|
+
<%= onlooker_format @status, :online_img => "/images/online.gif", :offline_img => "/images/offline.gif" %>
|
37
|
+
|
38
|
+
That way an image is displayed in-place of the default "Online" or "Offline" text.
|
39
|
+
|
40
|
+
|
41
|
+
Credits
|
42
|
+
=======
|
43
|
+
|
44
|
+
Copyright (c) 2008 Eric A. released under the MIT license
|
45
|
+
http://from.two2twelve.com
|
46
|
+
http://plugins.two2twelve.com
|
data/lib/net/ping.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
# By doing a "require 'net/ping'" you are requiring every subclass. If you
|
2
|
+
# want to require a specific ping type only, do "require 'net/ping/tcp'",
|
3
|
+
# for example.
|
4
|
+
#
|
5
|
+
$LOAD_PATH.unshift File.dirname(__FILE__)
|
6
|
+
|
7
|
+
require 'ping/tcp'
|
8
|
+
require 'ping/udp'
|
9
|
+
require 'ping/icmp'
|
10
|
+
require 'ping/external'
|
11
|
+
require 'ping/http'
|
@@ -0,0 +1,107 @@
|
|
1
|
+
$LOAD_PATH.unshift File.dirname(__FILE__)
|
2
|
+
require 'ping'
|
3
|
+
|
4
|
+
if RUBY_PLATFORM.match('mswin')
|
5
|
+
require 'win32/open3'
|
6
|
+
require 'windows/console'
|
7
|
+
include Windows::Console
|
8
|
+
else
|
9
|
+
require 'open3'
|
10
|
+
end
|
11
|
+
|
12
|
+
module Net
|
13
|
+
class Ping::External < Ping
|
14
|
+
|
15
|
+
# Pings the host using your system's ping utility and checks for any
|
16
|
+
# errors or warnings. Returns true if boolful, or false if not.
|
17
|
+
#
|
18
|
+
# If false, then the Ping::External#exception method should contain a
|
19
|
+
# string indicating what went wrong. If true, the Ping::External#warning
|
20
|
+
# method may or may not contain a value.
|
21
|
+
#
|
22
|
+
def ping(host = @host)
|
23
|
+
super(host)
|
24
|
+
|
25
|
+
input, output, error = ""
|
26
|
+
pstring = "ping "
|
27
|
+
bool = false
|
28
|
+
orig_cp = nil
|
29
|
+
|
30
|
+
case RUBY_PLATFORM
|
31
|
+
when /linux|bsd|osx|mach|darwin/i
|
32
|
+
pstring += "-c 1 #{host}"
|
33
|
+
when /solaris|sunos/i
|
34
|
+
pstring += "#{host} 1"
|
35
|
+
when /hpux/i
|
36
|
+
pstring += "#{host} -n 1"
|
37
|
+
when /win32|windows|mswin/i
|
38
|
+
orig_cp = GetConsoleCP()
|
39
|
+
SetConsoleCP(437) if orig_cp != 437 # United States
|
40
|
+
pstring += "-n 1 #{host}"
|
41
|
+
else
|
42
|
+
pstring += "#{host}"
|
43
|
+
end
|
44
|
+
|
45
|
+
start_time = Time.now
|
46
|
+
|
47
|
+
begin
|
48
|
+
e = nil
|
49
|
+
Timeout.timeout(@timeout){
|
50
|
+
input, output, error = Open3.popen3(pstring)
|
51
|
+
e = error.gets # Can't chomp yet, might be nil
|
52
|
+
}
|
53
|
+
|
54
|
+
input.close
|
55
|
+
error.close
|
56
|
+
|
57
|
+
if RUBY_PLATFORM.match('mswin') && GetConsoleCP() != orig_cp
|
58
|
+
SetConsoleCP(orig_cp)
|
59
|
+
end
|
60
|
+
|
61
|
+
unless e.nil?
|
62
|
+
if e =~ /warning/i
|
63
|
+
@warning = e.chomp
|
64
|
+
bool = true
|
65
|
+
else
|
66
|
+
@exception = e.chomp
|
67
|
+
end
|
68
|
+
# The "no answer" response goes to stdout, not stderr, so check it
|
69
|
+
else
|
70
|
+
lines = output.readlines
|
71
|
+
output.close
|
72
|
+
if lines.nil? || lines.empty?
|
73
|
+
bool = true
|
74
|
+
else
|
75
|
+
regexp = /
|
76
|
+
no\ answer|
|
77
|
+
host\ unreachable|
|
78
|
+
could\ not\ find\ host|
|
79
|
+
request\ timed\ out|
|
80
|
+
100%\ packet\ loss
|
81
|
+
/ix
|
82
|
+
lines.each{ |e|
|
83
|
+
if regexp.match(e)
|
84
|
+
@exception = e.chomp
|
85
|
+
break
|
86
|
+
end
|
87
|
+
}
|
88
|
+
bool = true unless @exception
|
89
|
+
end
|
90
|
+
end
|
91
|
+
rescue Exception => err
|
92
|
+
@exception = err.message
|
93
|
+
end
|
94
|
+
|
95
|
+
# There is no duration if the ping failed
|
96
|
+
@duration = Time.now - start_time if bool
|
97
|
+
|
98
|
+
bool
|
99
|
+
end
|
100
|
+
|
101
|
+
alias ping? ping
|
102
|
+
alias pingecho ping
|
103
|
+
end
|
104
|
+
|
105
|
+
# Class alias for backwards compatibility.
|
106
|
+
PingExternal = Ping::External
|
107
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
$LOAD_PATH.unshift File.dirname(__FILE__)
|
2
|
+
require 'ping'
|
3
|
+
require 'net/http'
|
4
|
+
require 'uri'
|
5
|
+
|
6
|
+
# Force non-blocking Socket.getaddrinfo on Unix systems. Do not use on
|
7
|
+
# Windows because it causes problems.
|
8
|
+
unless RUBY_PLATFORM.match('mswin')
|
9
|
+
require 'resolv-replace'
|
10
|
+
end
|
11
|
+
|
12
|
+
module Net
|
13
|
+
class Ping::HTTP < Ping
|
14
|
+
|
15
|
+
# By default an http ping will follow a redirect and give you the result
|
16
|
+
# of the final URI. If this value is set to false, then it will not
|
17
|
+
# follow a redirect and will return false immediately on a redirect.
|
18
|
+
#
|
19
|
+
attr_accessor :follow_redirect
|
20
|
+
|
21
|
+
# Creates and returns a new Ping::HTTP object. Note that the default
|
22
|
+
# port for Ping::HTTP is 80.
|
23
|
+
#
|
24
|
+
def initialize(uri=nil, port=80, timeout=5)
|
25
|
+
@follow_redirect = true
|
26
|
+
super(uri, port, timeout)
|
27
|
+
end
|
28
|
+
|
29
|
+
# Looks for an HTTP response from the URI passed to the constructor.
|
30
|
+
# If the result is a kind of Net::HTTPSuccess then the ping was
|
31
|
+
# boolful and true is returned. Otherwise, false is returned
|
32
|
+
# and the Ping::HTTP#exception method should contain a string
|
33
|
+
# indicating what went wrong.
|
34
|
+
#
|
35
|
+
# If the HTTP#follow_redirect accessor is set to true (which it is
|
36
|
+
# by default) and a redirect occurs during the ping, then the
|
37
|
+
# HTTP#warning attribute is set to the redirect message, but the
|
38
|
+
# return result is still true. If it's set to false then a false
|
39
|
+
# value is returned if a redirect occurs.
|
40
|
+
#
|
41
|
+
def ping(host = @host)
|
42
|
+
super(host)
|
43
|
+
bool = false
|
44
|
+
uri = URI.parse(host)
|
45
|
+
|
46
|
+
start_time = Time.now
|
47
|
+
|
48
|
+
begin
|
49
|
+
response = nil
|
50
|
+
Timeout.timeout(@timeout){
|
51
|
+
response = Net::HTTP.get_response(uri.host, uri.path, @port)
|
52
|
+
}
|
53
|
+
rescue Exception => err
|
54
|
+
@exception = err.message
|
55
|
+
else
|
56
|
+
if response.is_a?(Net::HTTPSuccess)
|
57
|
+
bool = true
|
58
|
+
else
|
59
|
+
if @follow_redirect
|
60
|
+
@warning = response.message
|
61
|
+
while response.is_a?(Net::HTTPRedirection)
|
62
|
+
redirect = URI.parse(response['location'])
|
63
|
+
redirect = uri + redirect if redirect.relative?
|
64
|
+
response = Net::HTTP.get_response(redirect.host, redirect.path, @port)
|
65
|
+
end
|
66
|
+
bool = true if response.is_a?(Net::HTTPSuccess)
|
67
|
+
else
|
68
|
+
@exception = response.message
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# There is no duration if the ping failed
|
74
|
+
@duration = Time.now - start_time if bool
|
75
|
+
|
76
|
+
bool
|
77
|
+
end
|
78
|
+
|
79
|
+
alias ping? ping
|
80
|
+
alias pingecho ping
|
81
|
+
alias follow_redirect? follow_redirect
|
82
|
+
alias uri host
|
83
|
+
alias uri= host=
|
84
|
+
end
|
85
|
+
|
86
|
+
# Class alias for backwards compatibility
|
87
|
+
PingHTTP = Ping::HTTP
|
88
|
+
end
|
@@ -0,0 +1,165 @@
|
|
1
|
+
$LOAD_PATH.unshift File.dirname(__FILE__)
|
2
|
+
require 'ping'
|
3
|
+
|
4
|
+
module Net
|
5
|
+
class Ping::ICMP < Ping
|
6
|
+
ICMP_ECHOREPLY = 0
|
7
|
+
ICMP_ECHO = 8
|
8
|
+
ICMP_SUBCODE = 0
|
9
|
+
|
10
|
+
# You cannot set or change the port value. A value of 0 is always
|
11
|
+
# used internally for ICMP pings.
|
12
|
+
#
|
13
|
+
undef_method :port=
|
14
|
+
|
15
|
+
# Returns the data size, i.e. number of bytes sent on the ping. The
|
16
|
+
# default size is 56.
|
17
|
+
#
|
18
|
+
attr_reader :data_size
|
19
|
+
|
20
|
+
# Creates and returns a new Ping::ICMP object. This is similar to its
|
21
|
+
# superclass constructor, but must be created with root privileges (on
|
22
|
+
# UNIX systems), and the port value is ignored.
|
23
|
+
#
|
24
|
+
def initialize(host=nil, port=nil, timeout=5)
|
25
|
+
raise 'requires root privileges' if Process.euid > 0
|
26
|
+
|
27
|
+
@seq = 0
|
28
|
+
@bind_port = 0
|
29
|
+
@bind_host = nil
|
30
|
+
@data_size = 56
|
31
|
+
@data = ''
|
32
|
+
|
33
|
+
0.upto(@data_size){ |n| @data << (n % 256).chr }
|
34
|
+
|
35
|
+
@pid = Process.pid & 0xffff
|
36
|
+
|
37
|
+
super(host, port, timeout)
|
38
|
+
@port = nil # This value is not used in ICMP pings.
|
39
|
+
end
|
40
|
+
|
41
|
+
# Sets the number of bytes sent in the ping method.
|
42
|
+
#
|
43
|
+
def data_size=(size)
|
44
|
+
@data_size = size
|
45
|
+
@data = ''
|
46
|
+
0.upto(size){ |n| @data << (n % 256).chr }
|
47
|
+
end
|
48
|
+
|
49
|
+
# Associates the local end of the socket connection with the given
|
50
|
+
# +host+ and +port+. The default port is 0.
|
51
|
+
#
|
52
|
+
def bind(host, port = 0)
|
53
|
+
@bind_host = host
|
54
|
+
@bind_port = port
|
55
|
+
end
|
56
|
+
|
57
|
+
# Pings the +host+ specified in this method or in the constructor. If a
|
58
|
+
# host was not specified either here or in the constructor, an
|
59
|
+
# ArgumentError is raised.
|
60
|
+
#
|
61
|
+
def ping(host = @host)
|
62
|
+
super(host)
|
63
|
+
bool = false
|
64
|
+
|
65
|
+
socket = Socket.new(
|
66
|
+
Socket::PF_INET,
|
67
|
+
Socket::SOCK_RAW,
|
68
|
+
Socket::IPPROTO_ICMP
|
69
|
+
)
|
70
|
+
|
71
|
+
if @bind_host
|
72
|
+
saddr = Socket.pack_sockaddr_in(@bind_port, @bind_host)
|
73
|
+
socket.bind(saddr)
|
74
|
+
end
|
75
|
+
|
76
|
+
@seq = (@seq + 1) % 65536
|
77
|
+
pstring = 'C2 n3 A' << @data_size.to_s
|
78
|
+
timeout = @timeout
|
79
|
+
|
80
|
+
checksum = 0
|
81
|
+
msg = [ICMP_ECHO, ICMP_SUBCODE, checksum, @pid, @seq, @data].pack(pstring)
|
82
|
+
checksum = checksum(msg)
|
83
|
+
msg = [ICMP_ECHO, ICMP_SUBCODE, checksum, @pid, @seq, @data].pack(pstring)
|
84
|
+
|
85
|
+
start_time = Time.now
|
86
|
+
|
87
|
+
begin
|
88
|
+
saddr = Socket.pack_sockaddr_in(0, host)
|
89
|
+
rescue Exception
|
90
|
+
return bool
|
91
|
+
end
|
92
|
+
|
93
|
+
socket.send(msg, 0, saddr) # Send the message
|
94
|
+
|
95
|
+
begin
|
96
|
+
Timeout.timeout(@timeout){
|
97
|
+
io_array = select([socket], nil, nil, timeout)
|
98
|
+
|
99
|
+
if io_array.nil? || io_array[0].empty?
|
100
|
+
return false
|
101
|
+
end
|
102
|
+
|
103
|
+
pid = nil
|
104
|
+
seq = nil
|
105
|
+
|
106
|
+
data, sender = socket.recvfrom(1500)
|
107
|
+
port, host = Socket.unpack_sockaddr_in(sender)
|
108
|
+
type, subcode = data[20, 2].unpack('C2')
|
109
|
+
|
110
|
+
case type
|
111
|
+
when ICMP_ECHOREPLY
|
112
|
+
if data.length >= 28
|
113
|
+
pid, seq = data[24, 4].unpack('n3')
|
114
|
+
end
|
115
|
+
else
|
116
|
+
if data.length > 56
|
117
|
+
pid, seq = data[52, 4].unpack('n3')
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
if pid == @pid && seq == @seq && type == ICMP_ECHOREPLY
|
122
|
+
bool = true
|
123
|
+
end
|
124
|
+
}
|
125
|
+
rescue Exception => err
|
126
|
+
@exception = err
|
127
|
+
ensure
|
128
|
+
socket.close if socket
|
129
|
+
end
|
130
|
+
|
131
|
+
# There is no duration if the ping failed
|
132
|
+
@duration = Time.now - start_time if bool
|
133
|
+
|
134
|
+
return bool
|
135
|
+
end
|
136
|
+
|
137
|
+
alias ping? ping
|
138
|
+
alias pingecho ping
|
139
|
+
|
140
|
+
private
|
141
|
+
|
142
|
+
# Perform a checksum on the message. This is the sum of all the short
|
143
|
+
# words and it folds the high order bits into the low order bits.
|
144
|
+
#
|
145
|
+
def checksum(msg)
|
146
|
+
length = msg.length
|
147
|
+
num_short = length / 2
|
148
|
+
check = 0
|
149
|
+
|
150
|
+
msg.unpack("n#{num_short}").each do |short|
|
151
|
+
check += short
|
152
|
+
end
|
153
|
+
|
154
|
+
if length % 2 > 0
|
155
|
+
check += msg[length-1, 1].unpack('C') << 8
|
156
|
+
end
|
157
|
+
|
158
|
+
check = (check >> 16) + (check & 0xffff)
|
159
|
+
return (~((check >> 16) + check) & 0xffff)
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
# Alias for consistency with other ping related classes
|
164
|
+
PingICMP = Ping::ICMP
|
165
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'socket'
|
2
|
+
require 'timeout'
|
3
|
+
|
4
|
+
module Net
|
5
|
+
class Ping
|
6
|
+
VERSION = '1.2.2'
|
7
|
+
|
8
|
+
# The host to ping. In the case of Ping::HTTP, this is the URI.
|
9
|
+
attr_accessor :host
|
10
|
+
|
11
|
+
# The port to ping. This is set to the echo port (7) by default. The
|
12
|
+
# Ping::HTTP class defaults to port 80.
|
13
|
+
#
|
14
|
+
attr_accessor :port
|
15
|
+
|
16
|
+
# The maximum time a ping attempt is made.
|
17
|
+
attr_accessor :timeout
|
18
|
+
|
19
|
+
# If a ping fails, this value is set to the error that occurred which
|
20
|
+
# caused it to fail.
|
21
|
+
#
|
22
|
+
attr_reader :exception
|
23
|
+
|
24
|
+
# This value is set if a ping succeeds, but some other condition arose
|
25
|
+
# during the ping attempt which merits warning, e.g a redirect in the
|
26
|
+
# case of Ping::HTTP#ping.
|
27
|
+
#
|
28
|
+
attr_reader :warning
|
29
|
+
|
30
|
+
# The number of seconds (returned as a Float) that it took to ping
|
31
|
+
# the host. This is not a precise value, but rather a good estimate
|
32
|
+
# since there is a small amount of internal calculation that is added
|
33
|
+
# to the overall time.
|
34
|
+
#
|
35
|
+
attr_reader :duration
|
36
|
+
|
37
|
+
# The default constructor for the Net::Ping class. Accepts an optional
|
38
|
+
# +host+, +port+ and +timeout+. The port defaults to your echo port, or
|
39
|
+
# 7 if that happens to be undefined. The default timeout is 5 seconds.
|
40
|
+
#
|
41
|
+
# The host, although optional in the constructor, must be specified at
|
42
|
+
# some point before the Net::Ping#ping method is called, or else an
|
43
|
+
# ArgumentError will be raised.
|
44
|
+
#
|
45
|
+
# Yields +self+ in block context.
|
46
|
+
#
|
47
|
+
# This class is not meant to be instantiated directly. It is strictly
|
48
|
+
# meant as an interface for subclasses.
|
49
|
+
#
|
50
|
+
def initialize(host=nil, port=nil, timeout=5)
|
51
|
+
@host = host
|
52
|
+
@port = port || Socket.getservbyname('echo') || 7
|
53
|
+
@timeout = timeout
|
54
|
+
@exception = nil
|
55
|
+
@warning = nil
|
56
|
+
@duration = nil
|
57
|
+
|
58
|
+
yield self if block_given?
|
59
|
+
end
|
60
|
+
|
61
|
+
# The default interface for the Net::Ping#ping method. Each subclass
|
62
|
+
# should call super() before continuing with their own implementation in
|
63
|
+
# order to ensure that the @exception and @warning instance variables
|
64
|
+
# are reset.
|
65
|
+
#
|
66
|
+
# If +host+ is nil here, then it will use the host specified in the
|
67
|
+
# constructor. If the +host+ is nil and there was no host specified
|
68
|
+
# in the constructor then an ArgumentError is raised.
|
69
|
+
#--
|
70
|
+
# The @duration should be set in the subclass' ping method.
|
71
|
+
#
|
72
|
+
def ping(host = @host)
|
73
|
+
raise ArgumentError, 'no host specified' unless host
|
74
|
+
@exception = nil
|
75
|
+
@warning = nil
|
76
|
+
end
|
77
|
+
|
78
|
+
alias ping? ping
|
79
|
+
alias pingecho ping
|
80
|
+
end
|
81
|
+
end
|
data/lib/net/ping/tcp.rb
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
$LOAD_PATH.unshift File.dirname(__FILE__)
|
2
|
+
require 'ping'
|
3
|
+
|
4
|
+
module Net
|
5
|
+
|
6
|
+
# With a TCP ping, simply try to open a connection. If we are successful,
|
7
|
+
# assume bool. In either case, close the connection to be polite.
|
8
|
+
#
|
9
|
+
class Ping::TCP < Ping
|
10
|
+
@@service_check = false
|
11
|
+
|
12
|
+
# Returns whether or not Errno::ECONNREFUSED is considered a successful
|
13
|
+
# ping. The default is false.
|
14
|
+
#
|
15
|
+
def self.service_check
|
16
|
+
@@service_check
|
17
|
+
end
|
18
|
+
|
19
|
+
# Sets whether or not an Errno::ECONNREFUSED should be considered a
|
20
|
+
# successful ping.
|
21
|
+
#
|
22
|
+
def self.service_check=(bool)
|
23
|
+
unless bool.kind_of?(TrueClass) || bool.kind_of?(FalseClass)
|
24
|
+
raise ArgumentError, 'argument must be true or false'
|
25
|
+
end
|
26
|
+
@@service_check = bool
|
27
|
+
end
|
28
|
+
|
29
|
+
# This method attempts to ping a host and port using a TCPSocket with
|
30
|
+
# the host, port and timeout values passed in the constructor. Returns
|
31
|
+
# true if successful, or false otherwise.
|
32
|
+
#
|
33
|
+
# Note that, by default, an Errno::ECONNREFUSED return result will be
|
34
|
+
# considered a failed ping. See the documentation for the
|
35
|
+
# Ping::TCP.service_check= method if you wish to change this behavior.
|
36
|
+
#
|
37
|
+
def ping(host=@host)
|
38
|
+
super(host)
|
39
|
+
|
40
|
+
bool = false
|
41
|
+
tcp = nil
|
42
|
+
start_time = Time.now
|
43
|
+
|
44
|
+
begin
|
45
|
+
Timeout.timeout(@timeout){
|
46
|
+
begin
|
47
|
+
tcp = TCPSocket.new(host, @port)
|
48
|
+
rescue Errno::ECONNREFUSED => err
|
49
|
+
if @@service_check
|
50
|
+
bool = true
|
51
|
+
else
|
52
|
+
@exception = err
|
53
|
+
end
|
54
|
+
rescue Exception => err
|
55
|
+
@exception = err
|
56
|
+
else
|
57
|
+
bool = true
|
58
|
+
end
|
59
|
+
}
|
60
|
+
rescue Timeout::Error => err
|
61
|
+
@exception = err
|
62
|
+
ensure
|
63
|
+
tcp.close if tcp
|
64
|
+
end
|
65
|
+
|
66
|
+
# There is no duration if the ping failed
|
67
|
+
@duration = Time.now - start_time if bool
|
68
|
+
|
69
|
+
bool
|
70
|
+
end
|
71
|
+
|
72
|
+
alias ping? ping
|
73
|
+
alias pingecho ping
|
74
|
+
|
75
|
+
# Class method aliases. DEPRECATED.
|
76
|
+
class << self
|
77
|
+
alias econnrefused service_check
|
78
|
+
alias econnrefused= service_check=
|
79
|
+
alias ecr service_check
|
80
|
+
alias ecr= service_check=
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
# Class alias for backwards compatibility
|
85
|
+
PingTCP = Ping::TCP
|
86
|
+
end
|
data/lib/net/ping/udp.rb
ADDED
@@ -0,0 +1,119 @@
|
|
1
|
+
$LOAD_PATH.unshift File.dirname(__FILE__)
|
2
|
+
require 'ping'
|
3
|
+
|
4
|
+
module Net
|
5
|
+
class Ping::UDP < Ping
|
6
|
+
@@service_check = true
|
7
|
+
|
8
|
+
# Returns whether or not the connect behavior should enforce remote
|
9
|
+
# service availability as well as reachability. The default is true.
|
10
|
+
#
|
11
|
+
def self.service_check
|
12
|
+
@@service_check
|
13
|
+
end
|
14
|
+
|
15
|
+
# Set whether or not the connect behavior should enforce remote
|
16
|
+
# service availability as well as reachability. If set to false
|
17
|
+
# then Errno::ECONNREFUSED or Errno::ECONNRESET will be considered
|
18
|
+
# a successful ping, meaning no actual data handshaking is required.
|
19
|
+
# By default, if either of those errors occurs it is considered a failed
|
20
|
+
# ping.
|
21
|
+
#
|
22
|
+
def self.service_check=(bool)
|
23
|
+
unless bool.kind_of?(TrueClass) || bool.kind_of?(FalseClass)
|
24
|
+
raise ArgumentError, 'argument must be true or false'
|
25
|
+
end
|
26
|
+
@@service_check = bool
|
27
|
+
end
|
28
|
+
|
29
|
+
MAX_DATA = 64
|
30
|
+
|
31
|
+
# The data to send to the remote host. By default this is 'ping'.
|
32
|
+
# This should be MAX_DATA size characters or less.
|
33
|
+
#
|
34
|
+
attr_reader :data
|
35
|
+
|
36
|
+
# Creates and returns a new Ping::UDP object. This is effectively
|
37
|
+
# identical to its superclass constructor.
|
38
|
+
#
|
39
|
+
def initialize(host=nil, port=nil, timeout=5)
|
40
|
+
@data = 'ping'
|
41
|
+
|
42
|
+
super(host, port, timeout)
|
43
|
+
|
44
|
+
@bind_host = nil
|
45
|
+
@bind_port = nil
|
46
|
+
end
|
47
|
+
|
48
|
+
# Sets the data string sent to the remote host. This value cannot have
|
49
|
+
# a size greater than MAX_DATA.
|
50
|
+
#
|
51
|
+
def data=(string)
|
52
|
+
if string.size > MAX_DATA
|
53
|
+
err = "cannot set data string larger than #{MAX_DATA} characters"
|
54
|
+
raise ArgumentError, err
|
55
|
+
end
|
56
|
+
|
57
|
+
@data = string
|
58
|
+
end
|
59
|
+
|
60
|
+
# Associates the local end of the UDP connection with the given +host+
|
61
|
+
# and +port+. This is essentially a wrapper for UDPSocket#bind.
|
62
|
+
#
|
63
|
+
def bind(host, port)
|
64
|
+
@bind_host = host
|
65
|
+
@bind_port = port
|
66
|
+
end
|
67
|
+
|
68
|
+
# Sends a simple text string to the host and checks the return string. If
|
69
|
+
# the string sent and the string returned are a match then the ping was
|
70
|
+
# successful and true is returned. Otherwise, false is returned.
|
71
|
+
#
|
72
|
+
def ping(host = @host)
|
73
|
+
super(host)
|
74
|
+
|
75
|
+
bool = false
|
76
|
+
udp = UDPSocket.open
|
77
|
+
array = []
|
78
|
+
|
79
|
+
if @bind_host
|
80
|
+
udp.bind(@bind_host, @bind_port)
|
81
|
+
end
|
82
|
+
|
83
|
+
start_time = Time.now
|
84
|
+
|
85
|
+
begin
|
86
|
+
Timeout.timeout(@timeout){
|
87
|
+
udp.connect(host, @port)
|
88
|
+
udp.send(@data, 0)
|
89
|
+
array = udp.recvfrom(MAX_DATA)
|
90
|
+
}
|
91
|
+
rescue Errno::ECONNREFUSED, Errno::ECONNRESET => err
|
92
|
+
if @@service_check
|
93
|
+
@exception = err
|
94
|
+
else
|
95
|
+
bool = true
|
96
|
+
end
|
97
|
+
rescue Exception => err
|
98
|
+
@exception = err
|
99
|
+
else
|
100
|
+
if array[0] == @data
|
101
|
+
bool = true
|
102
|
+
end
|
103
|
+
ensure
|
104
|
+
udp.close if udp
|
105
|
+
end
|
106
|
+
|
107
|
+
# There is no duration if the ping failed
|
108
|
+
@duration = Time.now - start_time if bool
|
109
|
+
|
110
|
+
bool
|
111
|
+
end
|
112
|
+
|
113
|
+
alias ping? ping
|
114
|
+
alias pingecho ping
|
115
|
+
end
|
116
|
+
|
117
|
+
# Class alias for backwards compatibility
|
118
|
+
PingUDP = Ping::UDP
|
119
|
+
end
|
data/lib/onlooker.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
require "net/ping"
|
2
|
+
include Net
|
3
|
+
class OnLooker
|
4
|
+
|
5
|
+
def self.check(host, ping_type, debug=false, timeout=2)
|
6
|
+
type = ping_type.downcase
|
7
|
+
if type == "ip"
|
8
|
+
request = Net::PingExternal.new(host, timeout)
|
9
|
+
get_result(request, debug)
|
10
|
+
elsif type == "web"
|
11
|
+
request = PingTCP.new(host, "http", 2)
|
12
|
+
get_result(request, debug)
|
13
|
+
else
|
14
|
+
"Type invalid. Try 'web' or 'ip'."
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.get_result(request, debug)
|
19
|
+
if request.ping?
|
20
|
+
"Online"
|
21
|
+
else
|
22
|
+
status = "Offline "
|
23
|
+
if debug == true
|
24
|
+
return status + request.exception
|
25
|
+
else
|
26
|
+
return status
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
module OnLookerHelper
|
34
|
+
|
35
|
+
def onlooker_format(status, *params)
|
36
|
+
options = params.extract_options!.symbolize_keys
|
37
|
+
|
38
|
+
options[:online_img] ||= options.include?(:online_img)
|
39
|
+
options[:offline_img] ||= options.include?(:offline_img)
|
40
|
+
|
41
|
+
if status == "Online"
|
42
|
+
"<img src='#{options[:online_img]}' alt='Online' />"
|
43
|
+
else
|
44
|
+
"<img src='#{options[:offline_img]}' alt='Offline' />"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
metadata
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: Onlooker
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jonathan Towell
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2010-01-24 00:00:00 -06:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: |-
|
17
|
+
OnLooker is a simple rails plugin that lets a user check the status of his or her website or server. OnLooker uses
|
18
|
+
Ping's to check via TCP or HTTP whether the site, sites or servers that you specify are online and accessible. OnLooker
|
19
|
+
also supports custom images to distinguish status.
|
20
|
+
email: jrtowell@gmail.com
|
21
|
+
executables: []
|
22
|
+
|
23
|
+
extensions: []
|
24
|
+
|
25
|
+
extra_rdoc_files:
|
26
|
+
- README
|
27
|
+
files:
|
28
|
+
- lib/net/ping/external.rb
|
29
|
+
- lib/net/ping/http.rb
|
30
|
+
- lib/net/ping/icmp.rb
|
31
|
+
- lib/net/ping/ping.rb
|
32
|
+
- lib/net/ping/tcp.rb
|
33
|
+
- lib/net/ping/udp.rb
|
34
|
+
- lib/net/ping.rb
|
35
|
+
- lib/onlooker.rb
|
36
|
+
- README
|
37
|
+
has_rdoc: true
|
38
|
+
homepage: http://github.com
|
39
|
+
licenses: []
|
40
|
+
|
41
|
+
post_install_message:
|
42
|
+
rdoc_options: []
|
43
|
+
|
44
|
+
require_paths:
|
45
|
+
- lib
|
46
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
47
|
+
requirements:
|
48
|
+
- - ">="
|
49
|
+
- !ruby/object:Gem::Version
|
50
|
+
version: "0"
|
51
|
+
version:
|
52
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: "0"
|
57
|
+
version:
|
58
|
+
requirements: []
|
59
|
+
|
60
|
+
rubyforge_project:
|
61
|
+
rubygems_version: 1.3.5
|
62
|
+
signing_key:
|
63
|
+
specification_version: 3
|
64
|
+
summary: OnLooker is a simple rails plugin that lets a user check the status of his or her website or server. OnLooker uses Ping's to check via TCP or HTTP whether the site, sites or servers that you specify are online and accessible. OnLooker also supports custom images to distinguish status.
|
65
|
+
test_files:
|
66
|
+
- test/onlooker_test.rb
|