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,161 @@
|
|
1
|
+
module Vnstat
|
2
|
+
##
|
3
|
+
# A class encapsulating traffic information for a specific network interface.
|
4
|
+
#
|
5
|
+
# @attr_reader [String] id The network interface identifier.
|
6
|
+
class Interface < Document
|
7
|
+
attr_reader :id
|
8
|
+
|
9
|
+
##
|
10
|
+
# Initializes the {Interface}.
|
11
|
+
#
|
12
|
+
# @param [String] id The network interface identifier.
|
13
|
+
# @param [String] data The raw XML data.
|
14
|
+
def initialize(id, data)
|
15
|
+
super(data)
|
16
|
+
@id = id
|
17
|
+
end
|
18
|
+
|
19
|
+
##
|
20
|
+
# Retrieves the raw XML data for the given interface identifier.
|
21
|
+
#
|
22
|
+
# @param [String] id The network interface identifier.
|
23
|
+
# @return [String]
|
24
|
+
def self.load_data(id)
|
25
|
+
Utils.call_executable('-i', id, '--xml')
|
26
|
+
end
|
27
|
+
|
28
|
+
##
|
29
|
+
# Determines whether the interface is the same as another.
|
30
|
+
#
|
31
|
+
# @param [Interface] other The compared object.
|
32
|
+
# @return [true, false]
|
33
|
+
def ==(other)
|
34
|
+
return false unless other.respond_to?(:id)
|
35
|
+
id == other.id
|
36
|
+
end
|
37
|
+
|
38
|
+
##
|
39
|
+
# Refreshes data cached in the current instance.
|
40
|
+
#
|
41
|
+
# @return [Interface]
|
42
|
+
def reload
|
43
|
+
self.data = self.class.load_data(id)
|
44
|
+
@nick = nil
|
45
|
+
self
|
46
|
+
end
|
47
|
+
|
48
|
+
##
|
49
|
+
# Deletes the traffic database for the interface.
|
50
|
+
#
|
51
|
+
# @return [true, false]
|
52
|
+
def delete
|
53
|
+
Utils.call_executable_returning_status('--delete', '-i', id)
|
54
|
+
end
|
55
|
+
|
56
|
+
##
|
57
|
+
# Reset the internal counters in the database for the selected interface.
|
58
|
+
# Use this if the interface goes down and back up, otherwise that interface
|
59
|
+
# will get some extra traffic to its database. Not needed when the daemon is
|
60
|
+
# used.
|
61
|
+
#
|
62
|
+
# @return [Interface]
|
63
|
+
def reset
|
64
|
+
Utils.call_executable_returning_status('--reset', '-i', id)
|
65
|
+
reload
|
66
|
+
end
|
67
|
+
|
68
|
+
##
|
69
|
+
# Returns the alias name for the interface.
|
70
|
+
#
|
71
|
+
# @return [String]
|
72
|
+
def nick
|
73
|
+
@nick ||= interface_data.xpath('nick').text
|
74
|
+
end
|
75
|
+
|
76
|
+
#
|
77
|
+
# Sets the alias name for the interface.
|
78
|
+
#
|
79
|
+
# @param [String] nick The alias name for the interface.
|
80
|
+
def nick=(nick)
|
81
|
+
Utils.call_executable_returning_status(
|
82
|
+
'-i', id, '--nick', nick, '--update'
|
83
|
+
)
|
84
|
+
@nick = nick
|
85
|
+
end
|
86
|
+
|
87
|
+
alias_method :name, :nick
|
88
|
+
alias_method :name=, :nick=
|
89
|
+
|
90
|
+
##
|
91
|
+
# The date on which tracking of the interface began.
|
92
|
+
# @return [Date]
|
93
|
+
#
|
94
|
+
def created_on
|
95
|
+
Parser.extract_date_from_xml_element(interface_data.xpath('created'))
|
96
|
+
end
|
97
|
+
|
98
|
+
##
|
99
|
+
# The date and time on which the tracking information for the interface
|
100
|
+
# were updated.
|
101
|
+
#
|
102
|
+
# @return [DateTime]
|
103
|
+
def updated_at
|
104
|
+
Parser.extract_datetime_from_xml_element(interface_data.xpath('updated'))
|
105
|
+
end
|
106
|
+
|
107
|
+
##
|
108
|
+
# Returns information about the total traffic.
|
109
|
+
#
|
110
|
+
# @return [Result]
|
111
|
+
def total
|
112
|
+
Result.extract_from_xml_element(interface_data.xpath('traffic/total'))
|
113
|
+
end
|
114
|
+
|
115
|
+
##
|
116
|
+
# Returns information about the hourly traffic.
|
117
|
+
#
|
118
|
+
# @return [Traffic::Hourly]
|
119
|
+
def hours
|
120
|
+
@hours ||= Traffic::Hourly.new(self)
|
121
|
+
end
|
122
|
+
|
123
|
+
##
|
124
|
+
# Returns information about the daily traffic.
|
125
|
+
#
|
126
|
+
# @return [Traffic::Daily]
|
127
|
+
def days
|
128
|
+
@days ||= Traffic::Daily.new(self)
|
129
|
+
end
|
130
|
+
|
131
|
+
##
|
132
|
+
# Returns information about the monthly traffic.
|
133
|
+
#
|
134
|
+
# @return [Traffic::Monthly]
|
135
|
+
def months
|
136
|
+
@months ||= Traffic::Monthly.new(self)
|
137
|
+
end
|
138
|
+
|
139
|
+
##
|
140
|
+
# Returns information about the traffic tops.
|
141
|
+
#
|
142
|
+
# @return [Traffic::Tops]
|
143
|
+
def tops
|
144
|
+
@tops ||= Traffic::Tops.new(self)
|
145
|
+
end
|
146
|
+
|
147
|
+
##
|
148
|
+
# A human readable representation of the {Interface}.
|
149
|
+
#
|
150
|
+
# @return [String]
|
151
|
+
def inspect
|
152
|
+
"#<#{self.class.name} id: #{id.inspect}>"
|
153
|
+
end
|
154
|
+
|
155
|
+
private
|
156
|
+
|
157
|
+
def interface_data
|
158
|
+
data.xpath("//interface[@id='#{id}']")
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
module Vnstat
|
2
|
+
##
|
3
|
+
# A class encapsulating traffic information for all known network interfaces.
|
4
|
+
class InterfaceCollection < Document
|
5
|
+
include Enumerable
|
6
|
+
|
7
|
+
##
|
8
|
+
# Retrieves the raw XML data for all interfaces.
|
9
|
+
#
|
10
|
+
# @return [String]
|
11
|
+
def self.load_data
|
12
|
+
Utils.call_executable('--xml')
|
13
|
+
end
|
14
|
+
|
15
|
+
##
|
16
|
+
# Sets the raw XML data for the {InterfaceCollection}.
|
17
|
+
#
|
18
|
+
# @param [String] data A string representing the document.
|
19
|
+
def data=(data)
|
20
|
+
super
|
21
|
+
each { |interface| interface.data = data }
|
22
|
+
end
|
23
|
+
|
24
|
+
##
|
25
|
+
# Refreshes data cached in the current instance.
|
26
|
+
#
|
27
|
+
# @return [InterfaceCollection]
|
28
|
+
def reload
|
29
|
+
self.data = self.class.load_data
|
30
|
+
self
|
31
|
+
end
|
32
|
+
|
33
|
+
##
|
34
|
+
# Returns the names of known interfaces.
|
35
|
+
#
|
36
|
+
# @return [Array<String>]
|
37
|
+
def ids
|
38
|
+
interfaces_hash.keys
|
39
|
+
end
|
40
|
+
|
41
|
+
##
|
42
|
+
# Returns traffic information for a certain interface.
|
43
|
+
#
|
44
|
+
# @param [String] id The name of the interface.
|
45
|
+
# @raise [UnknownInterface] An error that is raised if the
|
46
|
+
# specified interface is not tracked.
|
47
|
+
# @return [Interface]
|
48
|
+
def [](id)
|
49
|
+
interfaces_hash.fetch(id.to_s) do
|
50
|
+
fail UnknownInterface.new(id.to_s),
|
51
|
+
"Unknown interface: #{id}"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
##
|
56
|
+
# Iterates over each interface.
|
57
|
+
#
|
58
|
+
# @yieldparam [Interface] interface
|
59
|
+
def each(&block)
|
60
|
+
interfaces_hash.each_value(&block)
|
61
|
+
end
|
62
|
+
|
63
|
+
##
|
64
|
+
# Creates the traffic database for the given interface.
|
65
|
+
#
|
66
|
+
# @param [String] id The network interface identifier
|
67
|
+
# @return [Interface, nil] The interface that has justed been added to
|
68
|
+
# tracking.
|
69
|
+
def create(id)
|
70
|
+
success = Utils.call_executable_returning_status('--create', '-i', id)
|
71
|
+
return nil unless success
|
72
|
+
reload
|
73
|
+
self[id]
|
74
|
+
end
|
75
|
+
|
76
|
+
##
|
77
|
+
# Reset the total traffic counters and recount those using recorded months.
|
78
|
+
#
|
79
|
+
# @return [InterfaceCollection]
|
80
|
+
def rebuild
|
81
|
+
success = Utils.call_executable_returning_status('--rebuildtotal')
|
82
|
+
reload if success
|
83
|
+
self
|
84
|
+
end
|
85
|
+
|
86
|
+
##
|
87
|
+
# A human readable representation of the {InterfaceCollection}.
|
88
|
+
#
|
89
|
+
# @return [String]
|
90
|
+
def inspect
|
91
|
+
"#<#{self.class.name} ids: #{ids.inspect}>"
|
92
|
+
end
|
93
|
+
|
94
|
+
private
|
95
|
+
|
96
|
+
def interfaces_hash
|
97
|
+
@interfaces_hash ||= begin
|
98
|
+
elements = data.xpath('//interface')
|
99
|
+
elements.each_with_object({}) do |node, hash|
|
100
|
+
id = node[:id]
|
101
|
+
hash[id] = Interface.new(id, data)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module Vnstat
|
2
|
+
##
|
3
|
+
# A module containing several utility methods responsible for document
|
4
|
+
# parsing.
|
5
|
+
module Parser
|
6
|
+
module_function
|
7
|
+
|
8
|
+
##
|
9
|
+
# Extracts the year and month from the given XML element.
|
10
|
+
#
|
11
|
+
# @param [Nokogiri::XML::Element] element The XML element.
|
12
|
+
# @return [Array<Integer, Integer>] An Array consisting of year and month.
|
13
|
+
def extract_month_from_xml_element(element)
|
14
|
+
month = element.xpath('date/month').text.to_i
|
15
|
+
year = element.xpath('date/year').text.to_i
|
16
|
+
[year, month]
|
17
|
+
end
|
18
|
+
|
19
|
+
##
|
20
|
+
# Extracts the date from the given XML element.
|
21
|
+
#
|
22
|
+
# @param [Nokogiri::XML::Element] element The XML element.
|
23
|
+
# @return [Date]
|
24
|
+
def extract_date_from_xml_element(element)
|
25
|
+
day = element.xpath('date/day').text.to_i
|
26
|
+
year, month = extract_month_from_xml_element(element)
|
27
|
+
Date.new(year, month, day)
|
28
|
+
end
|
29
|
+
|
30
|
+
##
|
31
|
+
# Extracts the date and time from the given XML element.
|
32
|
+
#
|
33
|
+
# @param [Nokogiri::XML::Element] element The XML element.
|
34
|
+
# @return [DateTime]
|
35
|
+
def extract_datetime_from_xml_element(element)
|
36
|
+
date = extract_date_from_xml_element(element)
|
37
|
+
hour = element.xpath('time/hour').text.to_i
|
38
|
+
minute = element.xpath('time/minute').text.to_i
|
39
|
+
DateTime.new(date.year, date.month, date.day, hour, minute)
|
40
|
+
end
|
41
|
+
|
42
|
+
##
|
43
|
+
# Extracts the bytes received and sent from the given XML element.
|
44
|
+
#
|
45
|
+
# @param [Nokogiri::XML::Element] element The XML element.
|
46
|
+
# @return [Array<Integer, Integer>] An Array consisting of bytes received
|
47
|
+
# and bytes sent.
|
48
|
+
def extract_transmitted_bytes_from_xml_element(element)
|
49
|
+
bytes_received = element.xpath('rx').text.to_i * 1024
|
50
|
+
bytes_sent = element.xpath('tx').text.to_i * 1024
|
51
|
+
[bytes_received, bytes_sent]
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module Vnstat
|
2
|
+
##
|
3
|
+
# A class representing a tracking result.
|
4
|
+
#
|
5
|
+
# @attr_reader [Integer] bytes_received The received bytes.
|
6
|
+
# @attr_reader [Integer] bytes_sent The sent bytes.
|
7
|
+
class Result
|
8
|
+
autoload :Minute, 'vnstat/result/minute'
|
9
|
+
autoload :Day, 'vnstat/result/day'
|
10
|
+
autoload :Hour, 'vnstat/result/hour'
|
11
|
+
autoload :Month, 'vnstat/result/month'
|
12
|
+
|
13
|
+
autoload :DateDelegation, 'vnstat/result/date_delegation'
|
14
|
+
autoload :TimeComparable, 'vnstat/result/time_comparable'
|
15
|
+
|
16
|
+
include Comparable
|
17
|
+
|
18
|
+
attr_reader :bytes_received, :bytes_sent
|
19
|
+
|
20
|
+
##
|
21
|
+
# Initializes the {Result}.
|
22
|
+
#
|
23
|
+
# @param [Integer] bytes_received The received bytes.
|
24
|
+
# @param [Integer] bytes_sent The sent bytes.
|
25
|
+
def initialize(bytes_received, bytes_sent)
|
26
|
+
@bytes_received = bytes_received
|
27
|
+
@bytes_sent = bytes_sent
|
28
|
+
end
|
29
|
+
|
30
|
+
##
|
31
|
+
# Initializes a {Result} using the the data contained in the given XML
|
32
|
+
# element.
|
33
|
+
#
|
34
|
+
# @param [Nokogiri::XML::Element] element The XML element.
|
35
|
+
# @return [Result]
|
36
|
+
def self.extract_from_xml_element(element)
|
37
|
+
new(*Parser.extract_transmitted_bytes_from_xml_element(element))
|
38
|
+
end
|
39
|
+
|
40
|
+
##
|
41
|
+
# The transmitted bytes (both sent and received).
|
42
|
+
#
|
43
|
+
# @return [Integer]
|
44
|
+
def bytes_transmitted
|
45
|
+
bytes_received + bytes_sent
|
46
|
+
end
|
47
|
+
|
48
|
+
##
|
49
|
+
# @return [Integer, nil]
|
50
|
+
def <=>(other)
|
51
|
+
return nil unless other.respond_to?(:bytes_transmitted)
|
52
|
+
bytes_transmitted <=> other.bytes_transmitted
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Vnstat
|
2
|
+
class Result
|
3
|
+
##
|
4
|
+
# A module that is included by result types that contain date information.
|
5
|
+
module DateDelegation
|
6
|
+
##
|
7
|
+
# The year the result was captured in.
|
8
|
+
#
|
9
|
+
# @return [Integer]
|
10
|
+
def year
|
11
|
+
date.year
|
12
|
+
end
|
13
|
+
|
14
|
+
##
|
15
|
+
# The month the result was captured in.
|
16
|
+
#
|
17
|
+
# @return [Integer]
|
18
|
+
def month
|
19
|
+
date.month
|
20
|
+
end
|
21
|
+
|
22
|
+
##
|
23
|
+
# The day the result was captured on.
|
24
|
+
#
|
25
|
+
# @return [Integer]
|
26
|
+
def day
|
27
|
+
date.day
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Vnstat
|
2
|
+
class Result
|
3
|
+
##
|
4
|
+
# A class representing a tracking result for a specific day.
|
5
|
+
#
|
6
|
+
# @attr_reader [Date] date The date the result was captured on.
|
7
|
+
class Day < Result
|
8
|
+
include DateDelegation
|
9
|
+
|
10
|
+
attr_reader :date
|
11
|
+
|
12
|
+
##
|
13
|
+
# Initializes the {Day}.
|
14
|
+
#
|
15
|
+
# @param [Date] date The date the result was captured on.
|
16
|
+
# @param [Integer] bytes_received The received bytes.
|
17
|
+
# @param [Integer] bytes_sent The sent bytes.
|
18
|
+
def initialize(date, bytes_received, bytes_sent)
|
19
|
+
@date = date
|
20
|
+
super(bytes_received, bytes_sent)
|
21
|
+
end
|
22
|
+
|
23
|
+
##
|
24
|
+
# Initializes a {Day} using the the data contained in the given XML
|
25
|
+
# element.
|
26
|
+
#
|
27
|
+
# @param [Nokogiri::XML::Element] element The XML element.
|
28
|
+
# @return [Day]
|
29
|
+
def self.extract_from_xml_element(element)
|
30
|
+
new(
|
31
|
+
Parser.extract_date_from_xml_element(element),
|
32
|
+
*Parser.extract_transmitted_bytes_from_xml_element(element)
|
33
|
+
)
|
34
|
+
end
|
35
|
+
|
36
|
+
##
|
37
|
+
# @return [Integer, nil]
|
38
|
+
def <=>(other)
|
39
|
+
return nil unless other.respond_to?(:bytes_transmitted)
|
40
|
+
return nil unless other.respond_to?(:date)
|
41
|
+
[date, bytes_transmitted] <=> [other.date, other.bytes_transmitted]
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|