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.
Files changed (60) hide show
  1. checksums.yaml +7 -0
  2. data/.codeclimate.yml +14 -0
  3. data/.document +5 -0
  4. data/.rspec +3 -0
  5. data/.rubocop.yml +1171 -0
  6. data/.travis.yml +14 -0
  7. data/Gemfile +11 -0
  8. data/Gemfile.lock +84 -0
  9. data/LICENSE.txt +20 -0
  10. data/README.md +81 -0
  11. data/Rakefile +28 -0
  12. data/VERSION +1 -0
  13. data/lib/vnstat-ruby.rb +1 -0
  14. data/lib/vnstat.rb +65 -0
  15. data/lib/vnstat/configuration.rb +35 -0
  16. data/lib/vnstat/document.rb +56 -0
  17. data/lib/vnstat/error.rb +6 -0
  18. data/lib/vnstat/errors/executable_not_found.rb +7 -0
  19. data/lib/vnstat/errors/unknown_interface.rb +12 -0
  20. data/lib/vnstat/interface.rb +161 -0
  21. data/lib/vnstat/interface_collection.rb +106 -0
  22. data/lib/vnstat/parser.rb +54 -0
  23. data/lib/vnstat/result.rb +55 -0
  24. data/lib/vnstat/result/date_delegation.rb +31 -0
  25. data/lib/vnstat/result/day.rb +45 -0
  26. data/lib/vnstat/result/hour.rb +56 -0
  27. data/lib/vnstat/result/minute.rb +62 -0
  28. data/lib/vnstat/result/month.rb +47 -0
  29. data/lib/vnstat/result/time_comparable.rb +16 -0
  30. data/lib/vnstat/system_call.rb +90 -0
  31. data/lib/vnstat/traffic.rb +11 -0
  32. data/lib/vnstat/traffic/base.rb +46 -0
  33. data/lib/vnstat/traffic/daily.rb +40 -0
  34. data/lib/vnstat/traffic/hourly.rb +44 -0
  35. data/lib/vnstat/traffic/monthly.rb +27 -0
  36. data/lib/vnstat/traffic/tops.rb +39 -0
  37. data/lib/vnstat/utils.rb +68 -0
  38. data/spec/lib/vnstat/configuration_spec.rb +72 -0
  39. data/spec/lib/vnstat/document_spec.rb +54 -0
  40. data/spec/lib/vnstat/errors/executable_not_found_spec.rb +5 -0
  41. data/spec/lib/vnstat/errors/unknown_interface_spec.rb +5 -0
  42. data/spec/lib/vnstat/interface_collection_spec.rb +124 -0
  43. data/spec/lib/vnstat/interface_spec.rb +213 -0
  44. data/spec/lib/vnstat/result/day_spec.rb +39 -0
  45. data/spec/lib/vnstat/result/hour_spec.rb +43 -0
  46. data/spec/lib/vnstat/result/minute_spec.rb +52 -0
  47. data/spec/lib/vnstat/result/month_spec.rb +39 -0
  48. data/spec/lib/vnstat/result_spec.rb +86 -0
  49. data/spec/lib/vnstat/system_call_spec.rb +209 -0
  50. data/spec/lib/vnstat/traffic/daily_spec.rb +109 -0
  51. data/spec/lib/vnstat/traffic/hourly_spec.rb +153 -0
  52. data/spec/lib/vnstat/traffic/monthly_spec.rb +46 -0
  53. data/spec/lib/vnstat/traffic/tops_spec.rb +48 -0
  54. data/spec/lib/vnstat/utils_spec.rb +128 -0
  55. data/spec/lib/vnstat_spec.rb +61 -0
  56. data/spec/spec_helper.rb +98 -0
  57. data/spec/support/shared_examples/shared_examples_for_date_delegation.rb +19 -0
  58. data/spec/support/shared_examples/shared_examples_for_traffic_collection.rb +19 -0
  59. data/vnstat-ruby.gemspec +113 -0
  60. 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