vnstat-ruby 1.0.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 +7 -0
- data/.codeclimate.yml +14 -0
- data/.document +5 -0
- data/.rspec +3 -0
- data/.rubocop.yml +1171 -0
- data/.travis.yml +14 -0
- data/Gemfile +11 -0
- data/Gemfile.lock +84 -0
- data/LICENSE.txt +20 -0
- data/README.md +81 -0
- data/Rakefile +28 -0
- data/VERSION +1 -0
- data/lib/vnstat-ruby.rb +1 -0
- data/lib/vnstat.rb +65 -0
- data/lib/vnstat/configuration.rb +35 -0
- data/lib/vnstat/document.rb +56 -0
- data/lib/vnstat/error.rb +6 -0
- data/lib/vnstat/errors/executable_not_found.rb +7 -0
- data/lib/vnstat/errors/unknown_interface.rb +12 -0
- data/lib/vnstat/interface.rb +161 -0
- data/lib/vnstat/interface_collection.rb +106 -0
- data/lib/vnstat/parser.rb +54 -0
- data/lib/vnstat/result.rb +55 -0
- data/lib/vnstat/result/date_delegation.rb +31 -0
- data/lib/vnstat/result/day.rb +45 -0
- data/lib/vnstat/result/hour.rb +56 -0
- data/lib/vnstat/result/minute.rb +62 -0
- data/lib/vnstat/result/month.rb +47 -0
- data/lib/vnstat/result/time_comparable.rb +16 -0
- data/lib/vnstat/system_call.rb +90 -0
- data/lib/vnstat/traffic.rb +11 -0
- data/lib/vnstat/traffic/base.rb +46 -0
- data/lib/vnstat/traffic/daily.rb +40 -0
- data/lib/vnstat/traffic/hourly.rb +44 -0
- data/lib/vnstat/traffic/monthly.rb +27 -0
- data/lib/vnstat/traffic/tops.rb +39 -0
- data/lib/vnstat/utils.rb +68 -0
- data/spec/lib/vnstat/configuration_spec.rb +72 -0
- data/spec/lib/vnstat/document_spec.rb +54 -0
- data/spec/lib/vnstat/errors/executable_not_found_spec.rb +5 -0
- data/spec/lib/vnstat/errors/unknown_interface_spec.rb +5 -0
- data/spec/lib/vnstat/interface_collection_spec.rb +124 -0
- data/spec/lib/vnstat/interface_spec.rb +213 -0
- data/spec/lib/vnstat/result/day_spec.rb +39 -0
- data/spec/lib/vnstat/result/hour_spec.rb +43 -0
- data/spec/lib/vnstat/result/minute_spec.rb +52 -0
- data/spec/lib/vnstat/result/month_spec.rb +39 -0
- data/spec/lib/vnstat/result_spec.rb +86 -0
- data/spec/lib/vnstat/system_call_spec.rb +209 -0
- data/spec/lib/vnstat/traffic/daily_spec.rb +109 -0
- data/spec/lib/vnstat/traffic/hourly_spec.rb +153 -0
- data/spec/lib/vnstat/traffic/monthly_spec.rb +46 -0
- data/spec/lib/vnstat/traffic/tops_spec.rb +48 -0
- data/spec/lib/vnstat/utils_spec.rb +128 -0
- data/spec/lib/vnstat_spec.rb +61 -0
- data/spec/spec_helper.rb +98 -0
- data/spec/support/shared_examples/shared_examples_for_date_delegation.rb +19 -0
- data/spec/support/shared_examples/shared_examples_for_traffic_collection.rb +19 -0
- data/vnstat-ruby.gemspec +113 -0
- metadata +187 -0
@@ -0,0 +1,56 @@
|
|
1
|
+
module Vnstat
|
2
|
+
class Result
|
3
|
+
##
|
4
|
+
# A class representing a tracking result for a specific hour.
|
5
|
+
#
|
6
|
+
# @attr_reader [Date] date The date the result was captured on.
|
7
|
+
# @attr_reader [Integer] hour The hour the result was captured at.
|
8
|
+
class Hour < Result
|
9
|
+
include DateDelegation
|
10
|
+
include TimeComparable
|
11
|
+
|
12
|
+
attr_reader :date, :hour
|
13
|
+
|
14
|
+
##
|
15
|
+
# Initializes the {Hour}.
|
16
|
+
#
|
17
|
+
# @param [Date] date The date the result was captured on.
|
18
|
+
# @param [Integer] hour The hour the result was captured at.
|
19
|
+
# @param [Integer] bytes_received The received bytes.
|
20
|
+
# @param [Integer] bytes_sent The sent bytes.
|
21
|
+
def initialize(date, hour, bytes_received, bytes_sent)
|
22
|
+
@date = date
|
23
|
+
@hour = hour
|
24
|
+
super(bytes_received, bytes_sent)
|
25
|
+
end
|
26
|
+
|
27
|
+
##
|
28
|
+
# Initializes a {Hour} using the the data contained in the given XML
|
29
|
+
# element.
|
30
|
+
#
|
31
|
+
# @param [Nokogiri::XML::Element] element The XML element.
|
32
|
+
# @return [Hour]
|
33
|
+
def self.extract_from_xml_element(element)
|
34
|
+
date = Parser.extract_date_from_xml_element(element)
|
35
|
+
hour = Integer(element.attr('id').to_s)
|
36
|
+
new(date, hour, *Parser.extract_transmitted_bytes_from_xml_element(element))
|
37
|
+
end
|
38
|
+
|
39
|
+
##
|
40
|
+
# @return [Integer, nil]
|
41
|
+
def <=>(other)
|
42
|
+
return nil unless other.respond_to?(:bytes_transmitted)
|
43
|
+
return nil unless other.respond_to?(:time)
|
44
|
+
[time, bytes_transmitted] <=> [other.time, other.bytes_transmitted]
|
45
|
+
end
|
46
|
+
|
47
|
+
##
|
48
|
+
# The time the result was captured.
|
49
|
+
#
|
50
|
+
# @return [DateTime]
|
51
|
+
def time
|
52
|
+
DateTime.new(year, month, day, hour)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module Vnstat
|
2
|
+
class Result
|
3
|
+
##
|
4
|
+
# A class representing a tracking result for a specific minute.
|
5
|
+
#
|
6
|
+
# @attr_reader [DateTime] time The time the result was captured at.
|
7
|
+
class Minute < Result
|
8
|
+
include DateDelegation
|
9
|
+
include TimeComparable
|
10
|
+
|
11
|
+
attr_reader :time
|
12
|
+
|
13
|
+
##
|
14
|
+
# Initializes the {Minute}.
|
15
|
+
#
|
16
|
+
# @param [DateTime] time The time the result was captured at.
|
17
|
+
# @param [Integer] bytes_received The received bytes.
|
18
|
+
# @param [Integer] bytes_sent The sent bytes.
|
19
|
+
def initialize(time, bytes_received, bytes_sent)
|
20
|
+
@time = time
|
21
|
+
super(bytes_received, bytes_sent)
|
22
|
+
end
|
23
|
+
|
24
|
+
##
|
25
|
+
# Initializes a {Minute} using the the data contained in the given XML
|
26
|
+
# element.
|
27
|
+
#
|
28
|
+
# @param [Nokogiri::XML::Element] element The XML element.
|
29
|
+
# @return [Minute]
|
30
|
+
def self.extract_from_xml_element(element)
|
31
|
+
new(
|
32
|
+
Parser.extract_datetime_from_xml_element(element),
|
33
|
+
*Parser.extract_transmitted_bytes_from_xml_element(element)
|
34
|
+
)
|
35
|
+
end
|
36
|
+
|
37
|
+
##
|
38
|
+
# The date the result was captured.
|
39
|
+
#
|
40
|
+
# @return [Date]
|
41
|
+
def date
|
42
|
+
time.to_date
|
43
|
+
end
|
44
|
+
|
45
|
+
##
|
46
|
+
# The hour the result was captured.
|
47
|
+
#
|
48
|
+
# @return [Integer]
|
49
|
+
def hour
|
50
|
+
time.hour
|
51
|
+
end
|
52
|
+
|
53
|
+
##
|
54
|
+
# The minute the result was captured.
|
55
|
+
#
|
56
|
+
# @return [Integer]
|
57
|
+
def minute
|
58
|
+
time.minute
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Vnstat
|
2
|
+
class Result
|
3
|
+
##
|
4
|
+
# A class representing a tracking result for a specific month.
|
5
|
+
#
|
6
|
+
# @attr_reader [Integer] year The year the result was captured in.
|
7
|
+
# @attr_reader [Integer] month The month the result was captured in.
|
8
|
+
class Month < Result
|
9
|
+
attr_reader :year, :month
|
10
|
+
|
11
|
+
##
|
12
|
+
# Initializes the {Month}.
|
13
|
+
#
|
14
|
+
# @param [Integer] year The year the result was captured in.
|
15
|
+
# @param [Integer] month The month the result was captured in.
|
16
|
+
# @param [Integer] bytes_received The received bytes.
|
17
|
+
# @param [Integer] bytes_sent The sent bytes.
|
18
|
+
def initialize(year, month, bytes_received, bytes_sent)
|
19
|
+
@year = year
|
20
|
+
@month = month
|
21
|
+
super(bytes_received, bytes_sent)
|
22
|
+
end
|
23
|
+
|
24
|
+
##
|
25
|
+
# Initializes a {Month} using the the data contained in the given XML
|
26
|
+
# element.
|
27
|
+
#
|
28
|
+
# @param [Nokogiri::XML::Element] element The XML element.
|
29
|
+
# @return [Month]
|
30
|
+
def self.extract_from_xml_element(element)
|
31
|
+
new(
|
32
|
+
*Parser.extract_month_from_xml_element(element),
|
33
|
+
*Parser.extract_transmitted_bytes_from_xml_element(element)
|
34
|
+
)
|
35
|
+
end
|
36
|
+
|
37
|
+
##
|
38
|
+
# @return [Integer, nil]
|
39
|
+
def <=>(other)
|
40
|
+
return nil unless other.respond_to?(:bytes_transmitted)
|
41
|
+
return nil if !other.respond_to?(:year) || !other.respond_to?(:month)
|
42
|
+
[year, month, bytes_transmitted] <=>
|
43
|
+
[other.year, other.month, other.bytes_transmitted]
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Vnstat
|
2
|
+
class Result
|
3
|
+
##
|
4
|
+
# A module that is included by result types that can be compared based
|
5
|
+
# on their particular time information.
|
6
|
+
module TimeComparable
|
7
|
+
##
|
8
|
+
# @return [Integer, nil]
|
9
|
+
def <=>(other)
|
10
|
+
return nil unless other.respond_to?(:bytes_transmitted)
|
11
|
+
return nil unless other.respond_to?(:time)
|
12
|
+
[time, bytes_transmitted] <=> [other.time, other.bytes_transmitted]
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'open3'
|
2
|
+
|
3
|
+
module Vnstat
|
4
|
+
##
|
5
|
+
# A class responsible for communication with command line interfaces.
|
6
|
+
#
|
7
|
+
# @attr_reader [Array] args
|
8
|
+
# @attr_reader [String, nil] success_result The STDOUT output of the called
|
9
|
+
# command.
|
10
|
+
# @attr_reader [String, nil] error_result The STDERR output of the called
|
11
|
+
# command.
|
12
|
+
# @attr_reader [Process::Status, nil] exit_status The exit status of the
|
13
|
+
# called command.
|
14
|
+
class SystemCall
|
15
|
+
attr_reader :args, :success_result, :error_result, :exit_status
|
16
|
+
|
17
|
+
##
|
18
|
+
# Initializes the {SystemCall}.
|
19
|
+
#
|
20
|
+
# @param [Array] args The command line arguments.
|
21
|
+
def initialize(*args)
|
22
|
+
@args = args.flatten
|
23
|
+
end
|
24
|
+
|
25
|
+
##
|
26
|
+
# Initializes and calls the {SystemCall}.
|
27
|
+
#
|
28
|
+
# @param [Array] args The command line arguments.
|
29
|
+
# @return [SystemCall]
|
30
|
+
def self.call(*args)
|
31
|
+
new(*args).call
|
32
|
+
end
|
33
|
+
|
34
|
+
##
|
35
|
+
# Calls the command.
|
36
|
+
#
|
37
|
+
# @return [SystemCall]
|
38
|
+
def call
|
39
|
+
Open3.popen3(*args) do |_, stdout, stderr, wait_thr|
|
40
|
+
@success_result = readlines(stdout)
|
41
|
+
@error_result = readlines(stderr)
|
42
|
+
@exit_status = wait_thr.value
|
43
|
+
end
|
44
|
+
self
|
45
|
+
end
|
46
|
+
|
47
|
+
##
|
48
|
+
# Determines whether the command has been called.
|
49
|
+
#
|
50
|
+
# @return [true, false]
|
51
|
+
def called?
|
52
|
+
!exit_status.nil?
|
53
|
+
end
|
54
|
+
|
55
|
+
##
|
56
|
+
# Returns the command result.
|
57
|
+
#
|
58
|
+
# @return [String] Returns result from {#success_result} when command exited
|
59
|
+
# successfully. Otherwise returns result from {#error_result}.
|
60
|
+
# @raise [RuntimeError] Raises when the command has not yet been called.
|
61
|
+
def result
|
62
|
+
success? ? success_result : error_result
|
63
|
+
end
|
64
|
+
|
65
|
+
##
|
66
|
+
# Indicates whether the command has been executed successfully.
|
67
|
+
#
|
68
|
+
# @raise [RuntimeError] Raises when the command has not yet been called.
|
69
|
+
# @return [true, false]
|
70
|
+
def success?
|
71
|
+
fail 'Command not invoked' unless called?
|
72
|
+
exit_status.success?
|
73
|
+
end
|
74
|
+
|
75
|
+
##
|
76
|
+
# Indicates whether the command has not been executed successfully.
|
77
|
+
#
|
78
|
+
# @raise [RuntimeError] Raises when the command has not yet been called.
|
79
|
+
# @return [true, false]
|
80
|
+
def error?
|
81
|
+
!success?
|
82
|
+
end
|
83
|
+
|
84
|
+
private
|
85
|
+
|
86
|
+
def readlines(io)
|
87
|
+
io.readlines.join.chomp
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module Vnstat
|
2
|
+
##
|
3
|
+
# A namespace incorporating all kinds of traffic collections.
|
4
|
+
module Traffic
|
5
|
+
autoload :Base, 'vnstat/traffic/base'
|
6
|
+
autoload :Daily, 'vnstat/traffic/daily'
|
7
|
+
autoload :Hourly, 'vnstat/traffic/hourly'
|
8
|
+
autoload :Monthly, 'vnstat/traffic/monthly'
|
9
|
+
autoload :Tops, 'vnstat/traffic/tops'
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Vnstat
|
2
|
+
module Traffic
|
3
|
+
##
|
4
|
+
# An abstract implementation for a traffic collection.
|
5
|
+
#
|
6
|
+
# @attr_reader [Interface] interface The tracked interface.
|
7
|
+
class Base
|
8
|
+
include Enumerable
|
9
|
+
|
10
|
+
attr_reader :interface
|
11
|
+
|
12
|
+
##
|
13
|
+
# Initializes the traffic collection.
|
14
|
+
#
|
15
|
+
# @param [Interface] interface The tracked interface.
|
16
|
+
def initialize(interface)
|
17
|
+
@interface = interface
|
18
|
+
end
|
19
|
+
|
20
|
+
##
|
21
|
+
# Iterates over all results in the collection.
|
22
|
+
#
|
23
|
+
# @overload each
|
24
|
+
# @return [Enumerator]
|
25
|
+
#
|
26
|
+
# @overload each(&block)
|
27
|
+
# @yield [result]
|
28
|
+
# @yieldparam [Result] result
|
29
|
+
# @return [Base]
|
30
|
+
def each(&block)
|
31
|
+
entries_hash.values.each(&block)
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def traffic_data
|
37
|
+
interface.data.xpath('//traffic')
|
38
|
+
end
|
39
|
+
|
40
|
+
def entries_hash
|
41
|
+
fail NotImplementedError,
|
42
|
+
"Please override #{self.class.name}##{__method__}"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Vnstat
|
2
|
+
module Traffic
|
3
|
+
##
|
4
|
+
# A class encapsulating daily tracking information.
|
5
|
+
class Daily < Base
|
6
|
+
##
|
7
|
+
# Fetches a single {Result::Day} from the collection.
|
8
|
+
#
|
9
|
+
# @return [Result::Day]
|
10
|
+
#
|
11
|
+
# @overload [](date)
|
12
|
+
# @param [Date] date
|
13
|
+
#
|
14
|
+
# @overload [](year, month, day)
|
15
|
+
# @param [Integer] year
|
16
|
+
# @param [Integer] month
|
17
|
+
# @param [Integer] day
|
18
|
+
def [](*args)
|
19
|
+
date = case args.count
|
20
|
+
when 1 then args.first
|
21
|
+
when 3 then Date.new(*args)
|
22
|
+
else
|
23
|
+
fail ArgumentError, 'wrong number of arguments ' \
|
24
|
+
"(#{args.count} for 1 or 3)"
|
25
|
+
end
|
26
|
+
entries_hash[date]
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def entries_hash
|
32
|
+
elements = traffic_data.xpath('days/day')
|
33
|
+
elements.each_with_object({}) do |element, hash|
|
34
|
+
result = Result::Day.extract_from_xml_element(element)
|
35
|
+
hash[result.date] = result
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Vnstat
|
2
|
+
module Traffic
|
3
|
+
##
|
4
|
+
# A class encapsulating hourly tracking information.
|
5
|
+
class Hourly < Base
|
6
|
+
##
|
7
|
+
# Fetches a single {Result::Hour} from the collection.
|
8
|
+
#
|
9
|
+
# @return [Result::Hour]
|
10
|
+
#
|
11
|
+
# @overload [](date, hour)
|
12
|
+
# @param [Date] date
|
13
|
+
# @param [Integer] hour
|
14
|
+
#
|
15
|
+
# @overload [](year, month, day, hour)
|
16
|
+
# @param [Integer] year
|
17
|
+
# @param [Integer] month
|
18
|
+
# @param [Integer] day
|
19
|
+
# @param [Integer] hour
|
20
|
+
def [](*args)
|
21
|
+
args_count = args.count
|
22
|
+
hour = args.pop
|
23
|
+
date = case args_count
|
24
|
+
when 2 then args.first
|
25
|
+
when 4 then Date.new(*args)
|
26
|
+
else
|
27
|
+
fail ArgumentError, 'wrong number of arguments ' \
|
28
|
+
"(#{args_count} for 2 or 4)"
|
29
|
+
end
|
30
|
+
entries_hash[[date, hour]]
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def entries_hash
|
36
|
+
elements = traffic_data.xpath('hours/hour')
|
37
|
+
elements.each_with_object({}) do |element, hash|
|
38
|
+
result = Result::Hour.extract_from_xml_element(element)
|
39
|
+
hash[[result.date, result.hour]] = result
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Vnstat
|
2
|
+
module Traffic
|
3
|
+
##
|
4
|
+
# A class encapsulating monthly tracking information.
|
5
|
+
class Monthly < Base
|
6
|
+
##
|
7
|
+
# Fetches a single {Result::Month} from the collection.
|
8
|
+
#
|
9
|
+
# @param [Integer] year
|
10
|
+
# @param [Integer] month
|
11
|
+
# @return [Result::Month]
|
12
|
+
def [](year, month)
|
13
|
+
entries_hash[[year, month]]
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def entries_hash
|
19
|
+
elements = traffic_data.xpath('months/month')
|
20
|
+
elements.each_with_object({}) do |element, hash|
|
21
|
+
result = Result::Month.extract_from_xml_element(element)
|
22
|
+
hash[[result.year, result.month]] = result
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|