#!/usr/bin/env python from wxPython.wx import * import os, time, posix import regex, string, UserDict logdelay = 16000 # Seconds to wait before checking, updating GUI freenetdelay = 5000 # 1,000 = 1 sec os.system("rm -f /tmp/freenet_pid") """ Lars version 0.0.2 by Rob Cakebread Lars is a monitor, launcher and log watcher for the official Java Freenet server from http://freenet.sourceforge.net You'll need the wxPython GUI lib from http://www.wxpython.org/download.php Lars is Copyright 2001 by Rob Cakebread and released under the GNU Public License. NEW in 0.0.2: lars now parses the .freenetrc file to get the listening port and frpoxy port values. A future future version will have a Freenet configurator to write the .freenetrc file. Note: If a Server was previously started, this program won't attempt to stop it with the Stop Button. It's disabled. To Run: python lars.py TODO: Make it a little smarter as to how it updates the log file. As in, don't update it if the tail hasn't changed. Add checkbox for either just tail of freenet.log or a scrollbox for all output. (If you look down below, you can uncomment the proper line to change that -search for Append) Complete GUI for gonfiguring .freenetrc params """ global listenPort class FreenetRunning: def status(self, listenPort): out = os.popen("netstat -n -l|grep %s" % listenPort).read() if out: return 1 class FproxyRunning: def status(self, fproxyPort): out = os.popen("netstat -n -l|grep %s" % fproxyPort).read() if out: return 1 class StatusBar(wxStatusBar): def __init__(self, parent, listenPort, fproxyPort): wxStatusBar.__init__(self, parent, -1) self.listenPort = listenPort self.fproxyPort = fproxyPort self.SetFieldsCount(4) self.sizeChanged = false EVT_SIZE(self, self.OnSize) EVT_IDLE(self, self.OnIdle) self.but = wxButton(self, 1002, "", wxPoint(200,2)) self.Reposition() i = IniFile("freenet.ini") limit = i.data[DefaultSect]['bandwidthLimit'] self.SetStatusText("BndWdthLimit %s" % limit, 3) f = FreenetRunning() s = f.status(self.listenPort) if s: self.but.SetLabel("Freenet ALREADY Started") else: EVT_BUTTON(self, 1002, self.OnButton) self.timer = wxPyTimer(self.Notify) self.timer.Start(freenetdelay) self.Notify() def OnButton(self, event): r = FreenetRunning() running = r.status(self.listenPort) f = FproxyRunning() frunning = f.status(self.fproxyPort) if running: #Stop server f = open('/tmp/freenet_pid', 'r') pid = f.read() print pid os.system("kill %s" % pid) self.SetStatusText("Freenet is not running", 0) self.SetStatusText("Fproxy is not running", 2) self.but.SetLabel("Start Freenet") #Start server else: cmd = "java -cp './freenet.jar' Freenet.node.Node" self.process = wxProcess(self) self.process.Redirect(); pid = wxExecute(cmd, false, self.process) output = open('/tmp/freenet_pid', 'w') pidline = ("%s" % pid) output.write(pidline) output.close() self.but.SetLabel("Stop Freenet") self.SetStatusText("Freenet is running", 0) self.SetStatusText("Checking for Fproxy...", 2) def Notify(self): r = FreenetRunning() running = r.status(self.listenPort) f = FproxyRunning() frunning = f.status(self.fproxyPort) if running: self.SetStatusText("Freenet UP port %s" % self.listenPort, 0) self.but.SetLabel("Stop Freenet") else: self.SetStatusText("Freenet is not running", 0) self.but.SetLabel("Start Freenet") if frunning: self.SetStatusText("Fproxy is running", 2) else: self.SetStatusText("Fproxy is not running", 2) def OnToggleClock(self, event): if self.cb.GetValue(): self.timer.Start(1000) self.Notify() else: self.timer.Stop() def OnSize(self, evt): self.Reposition() # for normal size events # Set a flag so the idle time handler will also do the repositioning. # It is done this way to get around a buglet where GetFieldRect is not # accurate during the EVT_SIZE resulting from a frame maximize. self.sizeChanged = true def OnIdle(self, evt): if self.sizeChanged: self.Reposition() # reposition the checkbox def Reposition(self): rect = self.GetFieldRect(1) self.but.SetPosition(wxPoint(rect.x+2, rect.y+2)) self.but.SetSize(wxSize(rect.width-4, rect.height-4)) self.sizeChanged = false """ Class to parse Windoze-style ".INI" files. Instance creates a dictionary object of the form: [section][option] = value Options appearing before any section header are stored in the default section named DefaultSect. Any lines unbound to options are appended to a list in [section][DefaultOpt] Lines starting with leading tabs immediately following an assignment are assumed to be continuation lines. Null lines, or lines beginning with ';' or '#', are appended to a list in [section][Comments] """ # Special keys - leading space for sort to front DefaultSect = ' _global_' DefaultOpt = ' _values_' Comments = ' _comments_' class IniFile(UserDict.UserDict): """ Invoke with name of .ini file """ _section = regex.compile('^\[\(.+\)\]') _option = regex.compile('^\([^ \t]+\)[ \t]*=[ \t]*\(.*\)$') def __init__(self, fn): self.filename = fn self.data = {} # Parse the .ini file try: f = open(fn) lines = filter(None, f.readlines()) f.close() except: lines = [] sect = DefaultSect self.data[sect] = {} opt = None for line in lines: line = string.rstrip(line) if line == '': opt = None continue if line[0] == ';' or line[0] == '#': if not self.data[sect].has_key(Comments): self.data[sect][Comments] = [] self.data[sect][Comments].append(line) continue if self._section.match(line) >= 0: sect = self._section.group(1) if not self.data.has_key(sect): self.data[sect] = {} opt = None continue if self._option.match(line) >= 0: opt, val = self._option.group(1, 2) self.data[sect][opt] = val continue if opt and line[0] == '\t': self.data[sect][opt] = '%s %s' \ % (self.data[sect][opt], string.lstrip(line)) continue if not self.data[sect].has_key(DefaultOpt): self.data[sect][DefaultOpt] = [] self.data[sect][DefaultOpt].append(line) opt = None if not self.data[DefaultSect]: del self.data[DefaultSect] def change(self, name, value, section): """ Change value of old 'name', or add new """ # See if name already exists in default section data = self.data for sect in (section, DefaultSect): if data.has_key(sect) and data[sect].has_key(name): section = sect break else: if not data.has_key(section): data[section] = {} data[section][name] = value def write(self): """ Write the data back to the file """ f = open(self.filename, "w") sections = self.data.keys() sections.sort() for section in sections: if section is not DefaultSect: f.write('\n[%s]\n' % section) data = self.data[section] names = data.keys() names.sort() for name in names: value = data[name] if name in (Comments, DefaultOpt): f.write('%s\n' % string.join(value, '\n')) else: f.write('%s = %s\n' % (name, value)) f.close() class MyFrame(wxFrame): def __init__(self, parent): wxFrame.__init__(self, parent, -1, 'Lars - Freenet Server Monitor in wxPython', wxPoint(0,0), wxSize(540, 100)) i = IniFile(".freenetrc") self.listenPort = i.data[DefaultSect]['listenPort'] self.fproxyPort = i.data[DefaultSect]['services.fproxy.port'] services_fproxy_port = i.data[DefaultSect]['services.fproxy.port'] self.sb = StatusBar(self,self.listenPort, self.fproxyPort) self.SetStatusBar(self.sb) EVT_CLOSE(self, self.OnCloseWindow) self.log = wxTextCtrl(self, -1, '', style=wxTE_MULTILINE|wxTE_READONLY) self.timer = wxPyTimer(self.Notify) self.timer.Start(logdelay) self.Notify() def Notify(self): r = FreenetRunning() running = r.status(self.listenPort) if running: tail = os.popen("tail -10 /root/freenet/freenet.log").read() #self.log.AppendText(tail) self.log.SetValue(tail) # Use either one of the lines above to either show the tail only (default) # or have a scrollbox def OnCloseWindow(self, event): self.sb.timer.Stop() del self.sb.timer self.Destroy() class MyApp(wxApp): def OnInit(self): frame = MyFrame(NULL) frame.Show(true) self.SetTopWindow(frame) return true app = MyApp(0) app.MainLoop()