arbi 1.0.7 → 1.0.8

Sign up to get free protection for your applications and to get access to all the features.
@@ -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