]> git.immae.eu Git - perso/Immae/Projets/Ruby/Monitor.git/blob - monitor.rb
initial
[perso/Immae/Projets/Ruby/Monitor.git] / monitor.rb
1 #!/usr/bin/env ruby
2
3 require "time"
4 require "ncurses"
5 require "inifile"
6 require "open3"
7
8 class IO
9 def readline_nonblock
10 buffer = ""
11 buffer << read_nonblock(1) while buffer[-1] != "\n"
12 buffer
13 rescue IO::WaitReadable => blocking
14 if (not buffer.empty?)
15 ungetc(buffer)
16 end
17 raise blocking
18 end
19 end
20
21 class List_Win
22 def initialize(inifile)
23 @params = inifile
24 @win = Ncurses::WINDOW.new(0, Ncurses.COLS()/4, 0, 0)
25 @win.border(*([0]*8))
26 @win.keypad(true)
27 @win.timeout(1000)
28 @win.refresh()
29 @entry = 0
30 end
31
32 def getch()
33 @win.getch()
34 end
35 def clear()
36 @win.clear()
37 end
38 def resize(x,y)
39 @win.resize(x,y)
40 end
41 def move(x,y)
42 @win.move(x,y)
43 end
44 def refresh()
45 @win.refresh()
46 end
47
48 def print_list(entry=nil)
49 if(not entry.nil?)
50 @entry = entry
51 end
52 i = 0
53 @params.each_section do |section|
54 if(@entry == i)
55 @win.attron(Ncurses::A_REVERSE)
56 end
57 @win.move(i+1,1)
58 print_line(@win,@params[section]['Name'])
59 if(@entry == i)
60 @win.attroff(Ncurses::A_REVERSE)
61 end
62 i = i+1
63 end
64 @win.border(*([0]*8))
65 @win.move(0,3)
66 @win.addstr("Menu")
67 @win.refresh()
68 end
69 end
70
71 class Buff_Win
72 def initialize(winsize,winpos,params)
73 @params = params
74 @win = Ncurses::WINDOW.new(0, winsize, 0, winpos)
75 @panel = Ncurses::Panel::PANEL.new(@win)
76 if(@params['Type'] == 'oneshot')
77 @buffer = Buffer.new(0)
78 else
79 @buffer = Buffer.new(@params['Buffer'].to_i)
80 end
81 @proc = nil
82 @curr_offset = 0
83 @hscroll = 0
84 update_date()
85
86 spawn_proc()
87 print_buffer()
88 end
89
90 def move_resize(winsize,winpos)
91 newwin = Ncurses::WINDOW.new(0, winsize, 0, winpos)
92 Ncurses::Panel.replace_panel(@panel, newwin)
93 Ncurses.delwin(@win)
94 @win = newwin
95 print_buffer()
96 end
97 def update_date()
98 @last_update = Time.now
99 @date = @last_update.strftime("%F %R:%S")
100 end
101
102 def win_border()
103 @win.border(*([0]*8))
104 win_header()
105 end
106 def win_header()
107 @win.move(0,3)
108 @win.addnstr(@params['Name'],@win.getmaxx-@date.length-10)
109 @win.move(0,@win.getmaxx-@date.length-2)
110 @win.addstr(@date)
111 end
112 def refresh()
113 @win.refresh()
114 end
115 def clear()
116 @win.clear()
117 end
118
119 def show_win()
120 Ncurses::Panel.top_panel(@panel)
121 Ncurses::Panel.update_panels
122 end
123
124 def hscroll(scroll=0)
125 @hscroll += scroll
126 if(@hscroll < 0)
127 @hscroll = 0
128 end
129 if(@hscroll > @buffer.maxlen()-@win.getmaxx+3)
130 @hscroll = @buffer.maxlen()-@win.getmaxx+3
131 end
132 print_buffer()
133 refresh()
134 end
135 def scroll(scroll=0,goto=nil,fact=nil)
136 if (not fact.nil?)
137 scroll = (fact * @win.getmaxy.to_f).to_i
138 elsif (not goto.nil?)
139 @curr_offset = (goto * @buffer.size()).to_i
140 scroll = 0
141 end
142 #@curr_offset -= @win.getmaxy/2
143 @curr_offset += scroll
144 if(@curr_offset < 0)
145 @curr_offset = 0
146 end
147 if(@curr_offset > @buffer.size()-@win.getmaxy+2)
148 @curr_offset = @buffer.size()-@win.getmaxy+2
149 end
150 print_buffer()
151 refresh()
152 end
153
154 def print_buffer()
155 win_border()
156 j = 1
157 @buffer.yield(@win.getmaxy-2,@curr_offset) { |l,type|
158 @win.move(j,1)
159 if(type == 1) then @win.attron(Ncurses.COLOR_PAIR(1)) end
160 print_line(@win,l,hscroll=@hscroll)
161 if(type == 1) then @win.attroff(Ncurses.COLOR_PAIR(1)) end
162 j = j+1
163 }
164 if(@buffer.has_before?)
165 @win.move(2,@win.getmaxx-1)
166 @win.attron(Ncurses::A_REVERSE)
167 @win.addstr("↑")
168 @win.attroff(Ncurses::A_REVERSE)
169 end
170 if(@buffer.has_after?)
171 @win.move(@win.getmaxy-2,@win.getmaxx-1)
172 @win.attron(Ncurses::A_REVERSE)
173 @win.addstr("↓")
174 @win.attroff(Ncurses::A_REVERSE)
175 end
176 end
177
178 def proc_readlines()
179 begin
180 while true
181 @buffer.push(@proc.readline_nonblock)
182 update_date()
183 end
184 rescue IO::WaitReadable
185 end
186 end
187
188 def update()
189 if(@params['Type'] == 'continuous')
190 proc_readlines()
191 end
192 if(@params['Type'] == 'oneshot')
193 if(Time.now - @last_update > @params['Periodic'].to_i)
194 @buffer.clear()
195 spawn_proc()
196 end
197 end
198 print_buffer()
199 end
200
201 def spawn_proc()
202 if(@params['Type'] == 'oneshot')
203 update_date()
204 Open3.popen3(@params["Command"]) { |i,o,e,t|
205 while ((not o.eof?) or (not e.eof?))
206 rs = IO.select([o,e],nil)[0]
207 r = (rs[0].eof?)? rs[1] : rs[0]
208
209 if r.fileno == o.fileno
210 @buffer.push(r.readline)
211 elsif r.fileno == e.fileno
212 @buffer.push(r.readline,type=1)
213 end
214 end
215 }
216 elsif(@params['Type'] == 'continuous')
217 @proc = IO.popen(@params["Command"])
218 proc_readlines()
219 end
220 end
221 end
222
223 class Buffer
224 def initialize(size)
225 @size = size
226 @buff = []
227 @buff_type = []
228 @current = 0
229 @wrap = false
230 @before = false
231 @after = false
232 end
233 def size()
234 return @buff.length
235 end
236 def maxlen()
237 maxlen = 0
238 @buff.each do |string|
239 if string.length > maxlen
240 maxlen = string.length
241 end
242 end
243 return maxlen
244 end
245
246 def push(string,type=0)
247 if(string.chomp.empty?) then string = " " end
248 string.split( /\r?\n/ ).each do |line|
249 @buff[@current] = line
250 @buff_type[@current] = type
251 if(@size > 0)
252 @current = (1+@current) % @size
253 else
254 @current = 1+@current
255 end
256 if(@current == 0) then @wrap = true end
257 end
258 end
259 def yield(size,offset=0,&block)
260 range = Range.new(0,@current-1).to_a
261 if(@wrap)
262 range = Range.new(@current,@size-1).to_a + range
263 end
264 range = range.last(size+offset)[0,size]
265 @before = (size+offset < @buff.length)
266 @after = (offset != 0 and size < @buff.length)
267 if(block)
268 range.each do |i|
269 yield [@buff[i],@buff_type[i]]
270 end
271 else
272 return range.collect{|r| [@buff[r],@buff_type[r]]}
273 end
274 end
275 def has_after?()
276 return @after
277 end
278 def has_before?()
279 return @before
280 end
281 def clear()
282 @current = 0
283 @buff = []
284 @buff_type = []
285 end
286 end
287
288 def read_ini()
289 inifile = IniFile.load('monitorrc')
290 return inifile
291 end
292
293 def print_line(win, str, hscroll=0)
294 if(hscroll > 0)
295 strcut = str[hscroll,str.length]
296 if(strcut.nil? or strcut.empty?)
297 str = ""
298 else
299 str = "…"+strcut
300 end
301 end
302 strlen = str.length
303 winlen = win.getmaxx-win.getcurx-1
304 if(strlen <= winlen)
305 win.addstr(str + " "*(winlen-strlen))
306 else
307 win.addstr(str[0,winlen-1]+"…")
308 end
309 end
310
311 def make_bufwins(inifile)
312 bufwins = []
313 inifile.each_section do |section|
314 bufwin = Buff_Win.new(Ncurses.COLS()-Ncurses.COLS()/4,
315 Ncurses.COLS()/4,
316 inifile[section])
317 bufwins.push(bufwin)
318 end
319 return bufwins
320 end
321
322 def update_buffers(bufwins)
323 bufwins.each do |bufwin|
324 bufwin.update()
325 end
326 end
327
328 def redraw_all(list,bufwins,curr_bufwin)
329 bufwins.each do |bufwin|
330 bufwin.move_resize(Ncurses.COLS()-Ncurses.COLS()/4,Ncurses.COLS()/4)
331 end
332 list.resize(Ncurses.LINES(), Ncurses.COLS()/4)
333 list.clear()
334 list.print_list()
335 list.refresh()
336 curr_bufwin.refresh()
337 end
338 begin
339 # initialize ncurses
340 Ncurses.initscr
341 Ncurses.start_color
342 Ncurses.cbreak # provide unbuffered input
343 Ncurses.noecho # turn off input echoing
344 #Ncurses.nonl # turn off newline translation
345 #Ncurses.stdscr.intrflush(false) # turn off flush-on-interrupt
346 Ncurses.stdscr.keypad(true) # turn on keypad mode
347 Ncurses.init_pair(1, Ncurses::COLOR_RED, Ncurses::COLOR_BLACK)
348
349
350 inifile = read_ini()
351
352 list = List_Win.new(inifile)
353 bufwins = make_bufwins(inifile)
354 entry = 0
355 cur_bufwin = bufwins[entry]
356 cur_bufwin.show_win()
357 list.print_list()
358 while(ch = list.getch()) do
359 case(ch)
360 when "n".ord
361 entry = (entry +1) % bufwins.length
362 cur_bufwin = bufwins[entry]
363 cur_bufwin.show_win()
364 list.print_list(entry=entry)
365 when "p".ord
366 entry = (entry -1) % bufwins.length
367 cur_bufwin = bufwins[entry]
368 cur_bufwin.show_win()
369 list.print_list(entry=entry)
370 when 12 #ctrl+L
371 redraw_all(list,bufwins,cur_bufwin)
372 when Ncurses::KEY_RESIZE
373 redraw_all(list,bufwins,cur_bufwin)
374 when Ncurses::KEY_LEFT
375 cur_bufwin.hscroll(scroll=-1)
376 when Ncurses::KEY_RIGHT
377 cur_bufwin.hscroll(scroll=1)
378 when Ncurses::KEY_DOWN
379 cur_bufwin.scroll(scroll=-1)
380 when Ncurses::KEY_UP
381 cur_bufwin.scroll(scroll=1)
382 when Ncurses::KEY_NPAGE
383 cur_bufwin.scroll(scroll=0,goto=nil,fact=-0.75)
384 when Ncurses::KEY_PPAGE
385 cur_bufwin.scroll(scroll=0,goto=nil,fact=0.75)
386 when Ncurses::KEY_HOME
387 cur_bufwin.scroll(scroll=0,goto=1.0)
388 when Ncurses::KEY_END
389 cur_bufwin.scroll(scroll=0,goto=0.0)
390 when Ncurses::ERR
391 update_buffers(bufwins)
392 cur_bufwin.show_win()
393 when "q".ord
394 break
395 else
396 next
397 end
398 end
399
400 ensure
401 Ncurses.echo
402 Ncurses.nocbreak
403 Ncurses.nl
404 Ncurses.endwin
405 end