arbi 1.0.7 → 1.0.8

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,52 @@
1
+ #--
2
+ # Copyleft shura. [ shura1991@gmail.com ]
3
+ #
4
+ # This file is part of arbi.
5
+ #
6
+ # arbi is free software: you can redistribute it and/or modify
7
+ # it under the terms of the GNU Affero General Public License as published
8
+ # by the Free Software Foundation, either version 3 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ # arbi is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU Affero General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU Affero General Public License
17
+ # along with arbi. If not, see <http://www.gnu.org/licenses/>.
18
+ #++
19
+
20
+ require 'socket'
21
+ require 'arbi/modules'
22
+
23
+ module Arbi
24
+
25
+ class Client
26
+ attr_reader :sock
27
+
28
+ def initialize(address = '127.0.0.1', port = 6969)
29
+ @address = address || '127.0.0.1'
30
+ @port = port || 6969
31
+
32
+ self.connect
33
+ end
34
+
35
+ def connect
36
+ @sock = TCPSocket.new(@address, @port)
37
+ @sock.gets
38
+ end
39
+
40
+ def get(what = 'help')
41
+ @sock.print "#{what.strip}\r\n"
42
+ @sock.flush
43
+ JSON.parse(@sock.gets.strip)
44
+ rescue Errno::EPIPE
45
+ self.connect
46
+ retry
47
+ rescue NoMethodError
48
+ nil
49
+ end
50
+ end
51
+
52
+ end
@@ -0,0 +1,70 @@
1
+ #--
2
+ # Copyleft shura. [ shura1991@gmail.com ]
3
+ #
4
+ # This file is part of arbi.
5
+ #
6
+ # arbi is free software: you can redistribute it and/or modify
7
+ # it under the terms of the GNU Affero General Public License as published
8
+ # by the Free Software Foundation, either version 3 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ # arbi is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU Affero General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU Affero General Public License
17
+ # along with arbi. If not, see <http://www.gnu.org/licenses/>.
18
+ #++
19
+
20
+ require 'yaml'
21
+ require 'singleton'
22
+
23
+ module Arbi
24
+
25
+ class Config < Hash
26
+ include Singleton
27
+
28
+ def initialize
29
+ super()
30
+ self.parse
31
+ end
32
+
33
+ def parse(file = '/etc/arbi.conf')
34
+ config = YAML.load_file(file)
35
+ rescue
36
+ Arbi.debug "Config: Error in parsing"
37
+ ensure
38
+ config ||= {}
39
+ config[:server] ||= {}
40
+ config[:server][:address] ||= '127.0.0.1'
41
+ config[:server][:port] ||= 6969
42
+ config[:client] ||= {}
43
+ config[:client][:address] ||= '127.0.0.1'
44
+ config[:client][:port] ||= 6969
45
+ config[:client][:default_cmd] ||= ['help', 'quit']
46
+ config[:modules] ||= {}
47
+ config[:modules][:path] ||= []
48
+ config[:modules][:modules] ||= []
49
+
50
+ config[:client][:default_cmd].map!(&:to_s).uniq!
51
+ config[:client][:default_cmd].delete('quit')
52
+ config[:client][:default_cmd] << 'quit'
53
+ config[:modules][:path] << File.join(File.dirname(__FILE__), 'modules')
54
+ config[:modules][:path].uniq!
55
+
56
+ self.replace(config)
57
+ end
58
+
59
+ class << self
60
+ def [](*args)
61
+ self.instance.[](*args)
62
+ end
63
+
64
+ def parse(*args)
65
+ self.instance.parse(*args)
66
+ end
67
+ end
68
+ end
69
+
70
+ end
@@ -0,0 +1,183 @@
1
+ #--
2
+ # Copyleft shura. [ shura1991@gmail.com ]
3
+ #
4
+ # This file is part of arbi.
5
+ #
6
+ # arbi is free software: you can redistribute it and/or modify
7
+ # it under the terms of the GNU Affero General Public License as published
8
+ # by the Free Software Foundation, either version 3 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ # arbi is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU Affero General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU Affero General Public License
17
+ # along with arbi. If not, see <http://www.gnu.org/licenses/>.
18
+ #++
19
+
20
+ require 'json'
21
+ require 'singleton'
22
+ require 'arbi/config'
23
+ require 'arbi/timeline'
24
+ require 'arbi/utils/table'
25
+ require 'arbi/utils/numeric'
26
+
27
+ module Arbi
28
+
29
+ module Modules
30
+ PATH = [File.join(File.dirname(__FILE__), 'modules')]
31
+
32
+ @@logger = STDERR
33
+
34
+ class Error
35
+ def initialize(data = "")
36
+ @data = data
37
+ end
38
+
39
+ def to_json(*a)
40
+ ({
41
+ 'json_class' => self.class.name,
42
+ 'data' => @data
43
+ }.to_json(*a)) + "\n"
44
+ end
45
+
46
+ def format
47
+ @data
48
+ end
49
+
50
+ def self.json_create(o)
51
+ self.new(o['data'])
52
+ end
53
+ end
54
+
55
+ class Module
56
+ attr_reader :data
57
+
58
+ def initialize(data = [])
59
+ @data = data
60
+ end
61
+
62
+ def every(ev = 2, args = {}, &blk)
63
+ args[:timeout] ||= 5
64
+ TimeLine::Job.new(ev, args[:timeout], &blk)
65
+ end
66
+
67
+ def to_json(*a)
68
+ self.refresh if self.respond_to?(:refresh)
69
+
70
+ {
71
+ 'json_class' => self.class.to_s,
72
+ 'data' => @data
73
+ }.to_json(*a) + "\n"
74
+ end
75
+
76
+ def format
77
+ "#{self.class.name} has no format specified, writing raw:\n#{data.to_json}"
78
+ end
79
+
80
+ def valid?
81
+ false
82
+ end
83
+
84
+ class << self
85
+ def json_create(o)
86
+ self.new(o['data'])
87
+ end
88
+
89
+ def inherited(obj)
90
+ @@modules ||= {}
91
+ Singleton.__init__(obj)
92
+ Arbi::Modules.uninit
93
+ @@modules[obj.name] = obj
94
+ end
95
+
96
+ def modules
97
+ @@modules
98
+ end
99
+
100
+ def name
101
+ self.to_s.downcase.split('::').last
102
+ end
103
+
104
+ alias __method_missing__ method_missing
105
+ def method_missing(sym, *args, &blk)
106
+ if self.instance.respond_to?(sym)
107
+ self.instance.send(sym, *args, &blk)
108
+ else
109
+ self.__method_missing__(sym, *args, &blk)
110
+ end
111
+ end
112
+
113
+ undef_method :to_json
114
+ end
115
+ end
116
+
117
+ class << self
118
+ @@init = false
119
+
120
+ def modules
121
+ Arbi::Modules::Module.modules.dup
122
+ end
123
+
124
+ def init
125
+ return if self.initialized?
126
+ Arbi::Modules::Module.modules.replace(
127
+ Hash[Arbi::Modules::Module.modules.to_a.select {|(key, value)|
128
+ value.valid?
129
+ }])
130
+ @@init = true
131
+ end
132
+
133
+ def uninit
134
+ @@init = false
135
+ end
136
+
137
+ def initialized?
138
+ @@init
139
+ end
140
+ end
141
+ end
142
+
143
+ def self.debug(str)
144
+ @@logger.puts(str.to_s)
145
+ rescue
146
+ STDERR.puts(str.to_s)
147
+ end
148
+
149
+ def self.init
150
+ Arbi::Modules.init
151
+ end
152
+
153
+ def self.modules
154
+ Arbi.init
155
+ Arbi::Modules.modules
156
+ end
157
+
158
+ end
159
+
160
+ def load_module(file)
161
+ lp = $:.dup
162
+ $:.replace(Arbi::Config[:modules][:path] + $:)
163
+ require file
164
+ rescue Exception => e
165
+ Arbi.debug("Error loading module: #{e}")
166
+ ensure
167
+ $:.replace(lp)
168
+ end
169
+
170
+ load_module('help')
171
+ load_module('version')
172
+ load_module('cpu')
173
+ load_module('ram')
174
+ load_module('net')
175
+ load_module('adapter')
176
+ load_module('battery')
177
+ load_module('diskstat')
178
+
179
+ Arbi::Config[:modules][:modules].each {|mod|
180
+ load_module(mod)
181
+ }
182
+
183
+ Arbi.init
@@ -0,0 +1,62 @@
1
+ #--
2
+ # Copyleft shura. [ shura1991@gmail.com ]
3
+ #
4
+ # This file is part of arbi.
5
+ #
6
+ # arbi is free software: you can redistribute it and/or modify
7
+ # it under the terms of the GNU Affero General Public License as published
8
+ # by the Free Software Foundation, either version 3 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ # arbi is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU Affero General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU Affero General Public License
17
+ # along with arbi. If not, see <http://www.gnu.org/licenses/>.
18
+ #++
19
+
20
+ require 'arbi/modules/acpi/utils'
21
+
22
+ module Arbi
23
+
24
+ module Modules
25
+
26
+ module Acpi
27
+
28
+ class Adapter < Arbi::Modules::Module
29
+ include Arbi::Modules::Acpi::Utils
30
+
31
+ def initialize(data = [])
32
+ super(data)
33
+ @adapters = Dir.glob('/proc/acpi/ac_adapter/*')
34
+ end
35
+
36
+ def valid?
37
+ !@adapters.empty?
38
+ end
39
+
40
+ def refresh
41
+ @data = []
42
+
43
+ @adapters.each {|adapter|
44
+ @data << {
45
+ name: File.basename(adapter),
46
+ state: (hashize("#{adapter}/state")[:state] == 'on-line' ? true : false)
47
+ }
48
+ }
49
+ end
50
+
51
+ def format
52
+ tablize([['NAME', 'STATE']] + @data.map {|adapter|
53
+ [adapter[:name] || adapter['name'], (adapter[:state] || adapter['state']) ? 'on' : 'off']
54
+ })
55
+ end
56
+ end
57
+
58
+ end
59
+
60
+ end
61
+
62
+ end
@@ -0,0 +1,99 @@
1
+ #--
2
+ # Copyleft shura. [ shura1991@gmail.com ]
3
+ #
4
+ # This file is part of arbi.
5
+ #
6
+ # arbi is free software: you can redistribute it and/or modify
7
+ # it under the terms of the GNU Affero General Public License as published
8
+ # by the Free Software Foundation, either version 3 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ # arbi is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU Affero General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU Affero General Public License
17
+ # along with arbi. If not, see <http://www.gnu.org/licenses/>.
18
+ #++
19
+
20
+ require 'arbi/modules/acpi/utils'
21
+
22
+ module Arbi
23
+
24
+ module Modules
25
+
26
+ module Acpi
27
+
28
+ class Battery < Arbi::Modules::Module
29
+ include Arbi::Modules::Acpi::Utils
30
+
31
+ def initialize(data = [])
32
+ super(data)
33
+ @batteries = Dir.glob("/proc/acpi/battery/*")
34
+ end
35
+
36
+ def valid?
37
+ File.exist?('/proc/acpi/battery') and !@batteries.empty?
38
+ end
39
+
40
+ def refresh
41
+ @data = []
42
+
43
+ @batteries.each {|battery|
44
+ @data << self.battery_info(battery)
45
+ }
46
+ @data << self.average(@data)
47
+ end
48
+
49
+ def format
50
+ tablize([['NAME', 'PERCENT', 'STATE', 'SANITY']] + @data.map {|x|
51
+ [x[:name] || x['name'], x[:percent] || x['percent'], x[:state] || x['state'], x[:sanity] || x['sanity']]
52
+ })
53
+ end
54
+
55
+ protected
56
+ def battery_info(dir)
57
+ raw = self.hashize(dir + '/info').merge(self.hashize(dir + '/state'))
58
+ # Return if battery isn't present
59
+ return not_present(File.basename(dir)) unless {yes: true, no: false}[(raw[:present].to_sym rescue nil)]
60
+
61
+ {
62
+ name: File.basename(dir),
63
+ sanity: ("%.1f%%" % [100.0 / raw[:design_capacity] * raw[:last_full_capacity]]),
64
+ state: raw[:charging_state],
65
+ percent: ("%.1f%%" % [100.0 / raw[:last_full_capacity] * raw[:remaining_capacity]])
66
+ }
67
+ end
68
+
69
+ def average(batteries)
70
+ avg, n = 0, 0
71
+
72
+ batteries.each {|battery|
73
+ avg += battery[:percent].gsub(/%$/, '').to_f and n += 1 if battery[:percent]
74
+ }
75
+ avg = "%.1f%%" % [avg / n] rescue false
76
+
77
+ {
78
+ name: 'AVERAGE',
79
+ sanity: false,
80
+ state: false,
81
+ percent: avg
82
+ }
83
+ end
84
+
85
+ def not_present(name)
86
+ {
87
+ name: name,
88
+ sanity: false,
89
+ state: false,
90
+ percent: false
91
+ }
92
+ end
93
+ end
94
+
95
+ end
96
+
97
+ end
98
+
99
+ end