macapp: report failure of node startup to the user

in certain cases (e.g. the node.pem changed but old .furls are in private/)
the node will abort upon startup. previously it used os.abort() which in these
cases caused the mac gui app to crash on startup with no explanation.

this changes that behaviour from calling os.abort() to calling 
node._abort_process(failure) which by default calls os.abort().  this allows 
that method to be overridden in subclasses.

the mac app now provides and uses such a subclass of Client, so that failures
are reported to the user in a message dialog before the process exits.
this uses wx.PostEvent() with a custom event type to signal from the reactor
thread into the gui thread.
This commit is contained in:
robk-tahoe 2008-03-06 13:53:21 -07:00
parent d5886bed2f
commit ee67d788cd
2 changed files with 38 additions and 8 deletions

View File

@ -43,6 +43,23 @@ def run_macapp():
app = App(basedir)
return app.run()
ABORT_EVENT_ID = wx.NewId()
class AbortEvent(wx.PyEvent):
def __init__(self, failure):
wx.PyEvent.__init__(self)
self.SetEventType(ABORT_EVENT_ID)
self.failure = failure
class MacGuiClient(client.Client):
def __init__(self, basedir, app):
self.app = app
client.Client.__init__(self, basedir)
def _abort_process(self, failure):
event = AbortEvent(failure)
wx.PostEvent(self.app.guiapp.frame, event)
class App(object):
def __init__(self, basedir):
self.basedir = basedir
@ -89,8 +106,8 @@ class App(object):
self.start_reactor()
try:
guiapp = MacGuiApp(app=self)
guiapp.MainLoop()
self.guiapp = MacGuiApp(app=self)
self.guiapp.MainLoop()
log.msg('gui mainloop exited')
except:
log.err()
@ -105,7 +122,8 @@ class App(object):
def launch_reactor(self):
# run the node itself
c = client.Client(self.basedir)
#c = client.Client(self.basedir)
c = MacGuiClient(self.basedir, self)
reactor.callLater(0, c.startService) # after reactor startup
reactor.run(installSignalHandlers=False)
self.reactor_shutdown.set()
@ -176,8 +194,9 @@ ACCOUNT_PAGE_ID = wx.NewId()
MOUNT_ID = wx.NewId()
class SplashFrame(wx.Frame):
def __init__(self):
def __init__(self, app):
wx.Frame.__init__(self, None, -1, 'Allmydata Tahoe')
self.app = app
self.SetSizeHints(100, 100, 600, 800)
self.SetIcon(amdicon.getIcon())
@ -196,9 +215,16 @@ class SplashFrame(wx.Frame):
self.Fit()
self.Layout()
# plumb up event handler for abort
self.Connect(-1, -1, ABORT_EVENT_ID, self.wx_abort)
def on_close(self, event):
self.Show(False)
def wx_abort(self, event):
wx.MessageBox(event.failure.getTraceback(), 'Fatal Error in Node startup')
self.app.ExitMainLoop()
class SplashPanel(wx.Panel):
def __init__(self, parent, on_close):
wx.Panel.__init__(self, parent, -1)
@ -369,7 +395,7 @@ class MacGuiApp(wx.App):
def OnInit(self):
try:
self.frame = SplashFrame()
self.frame = SplashFrame(self)
self.frame.Show(True)
self.SetTopWindow(self.frame)

View File

@ -172,11 +172,15 @@ class Node(service.MultiService):
print "Node._startService failed, aborting"
print failure
#reactor.stop() # for unknown reasons, reactor.stop() isn't working. [ ] TODO
self.log('calling os.abort()')
print "calling os.abort()"
os.abort()
self._abort_process(failure)
d.addErrback(_die)
def _abort_process(self, failure):
self.log('calling os.abort()')
log('calling os.abort()')
print "calling os.abort()"
os.abort()
def stopService(self):
self.log("Node.stopService")
d = self._tub_ready_observerlist.when_fired()