]> git.saurik.com Git - wxWidgets.git/blobdiff - wxPython/wx/lib/rpcMixin.py
move wxPython to new trunk
[wxWidgets.git] / wxPython / wx / lib / rpcMixin.py
diff --git a/wxPython/wx/lib/rpcMixin.py b/wxPython/wx/lib/rpcMixin.py
deleted file mode 100644 (file)
index 7a0c342..0000000
+++ /dev/null
@@ -1,422 +0,0 @@
-#
-#  This was modified from rpcMixin.py distributed with wxPython
-#
-#----------------------------------------------------------------------
-# Name:        rpcMixin
-# Version:     0.2.0
-# Purpose:     provides xmlrpc server functionality for wxPython
-#              applications via a mixin class
-#
-# Requires:    (1) Python with threading enabled.
-#              (2) xmlrpclib from PythonWare
-#                  (http://www.pythonware.com/products/xmlrpc/)
-#                  the code was developed and tested using version 0.9.8
-#
-# Author:      greg Landrum (Landrum@RationalDiscovery.com)
-#
-# Copyright:   (c) 2000, 2001 by Greg Landrum and Rational Discovery LLC
-# Licence:     wxWindows license
-#----------------------------------------------------------------------
-# 12/11/2003 - Jeff Grimmett (grimmtooth@softhome.net)
-#
-# o 2.5 compatability update.
-# o xmlrpcserver not available.
-#
-
-"""provides xmlrpc server functionality for wxPython applications via a mixin class
-
-**Some Notes:**
-
-  1)  The xmlrpc server runs in a separate thread from the main GUI
-      application, communication between the two threads using a custom
-      event (see the Threads demo in the wxPython docs for more info).
-
-  2)  Neither the server nor the client are particularly smart about
-      checking method names.  So it's easy to shoot yourself in the foot
-      by calling improper methods.  It would be pretty easy to add
-      either a list of allowed methods or a list of forbidden methods.
-
-  3)  Authentication of xmlrpc clients is *not* performed.  I think it
-      would be pretty easy to do this in a hacky way, but I haven't done
-      it yet.
-
-  4)  See the bottom of this file for an example of using the class.
-
-**Obligatory disclaimer:**
-  This is my first crack at both using xmlrpc and multi-threaded
-  programming, so there could be huge horrible bugs or design
-  flaws. If you see one, I'd love to hear about them.
-
-"""
-
-
-""" ChangeLog
-23 May 2001:  Version bumped to 0.2.0
-  Numerous code and design changes
-
-21 Mar. 2001:  Version bumped to 0.1.4
-  Updated rpcMixin.OnExternal to support methods with further references
-   (i.e. now you can do rpcClient.foo.bar() and have it work)
-  This probably ain't super legal in xmlrpc land, but it works just fine here
-   and we need it.
-
-6  Mar. 2001:  Version bumped to 0.1.3
-  Documentation changes to make this compatible with happydoc
-
-21 Jan. 2001:  Version bumped to 0.1.2
-  OnExternal() method in the mixin class now uses getattr() to check if
-    a desired method is present.  It should have been done this way in
-    the first place.
-14 Dec. 2000:  Version bumped to 0.1.1
-  rearranged locking code and made other changes so that multiple
-    servers in one application are possible.
-
-"""
-
-import  new
-import  SocketServer
-import  sys
-import  threading
-import  xmlrpclib
-import  xmlrpcserver
-
-import  wx
-
-rpcPENDING = 0
-rpcDONE = 1
-rpcEXCEPT = 2
-
-class RPCRequest:
-  """A wrapper to use for handling requests and their responses"""
-  status = rpcPENDING
-  result = None
-
-# here's the ID for external events
-wxEVT_EXTERNAL_EVENT = wx.NewEventType()
-EVT_EXTERNAL_EVENT = wx.PyEventBinder(wxEVT_EXTERNAL_EVENT, 0)
-
-class ExternalEvent(wx.PyEvent):
-  """The custom event class used to pass xmlrpc calls from
-     the server thread into the GUI thread
-
-  """
-  def __init__(self,method,args):
-    wx.PyEvent.__init__(self)
-    self.SetEventType(wxEVT_EXTERNAL_EVENT)
-    self.method = method
-    self.args = args
-    self.rpcStatus = RPCRequest()
-    self.rpcStatusLock = threading.Lock()
-    self.rpcCondVar = threading.Condition()
-
-  def Destroy(self):
-    self.method=None
-    self.args=None
-    self.rpcStatus = None
-    self.rpcStatusLock = None
-    self.rpcondVar = None
-
-class Handler(xmlrpcserver.RequestHandler):
-  """The handler class that the xmlrpcserver actually calls
-     when a request comes in.
-
-  """
-  def log_message(self,*args):
-    """ causes the server to stop spewing messages every time a request comes in
-
-    """
-    pass
-  def call(self,method,params):
-    """When an xmlrpc request comes in, this is the method that
-       gets called.
-
-       **Arguments**
-
-         - method: name of the method to be called
-
-         - params: arguments to that method
-
-    """
-    if method == '_rpcPing':
-      # we just acknowledge these without processing them
-      return 'ack'
-
-    # construct the event
-    evt = ExternalEvent(method,params)
-
-    # update the status variable
-    evt.rpcStatusLock.acquire()
-    evt.rpcStatus.status = rpcPENDING
-    evt.rpcStatusLock.release()
-
-    evt.rpcCondVar.acquire()
-    # dispatch the event to the GUI
-    wx.PostEvent(self._app,evt)
-
-    # wait for the GUI to finish
-    while evt.rpcStatus.status == rpcPENDING:
-      evt.rpcCondVar.wait()
-    evt.rpcCondVar.release()
-    evt.rpcStatusLock.acquire()
-    if evt.rpcStatus.status == rpcEXCEPT:
-      # The GUI threw an exception, release the status lock
-      #  and re-raise the exception
-      evt.rpcStatusLock.release()
-      raise evt.rpcStatus.result[0],evt.rpcStatus.result[1]
-    else:
-      # everything went through without problems
-      s = evt.rpcStatus.result
-
-      evt.rpcStatusLock.release()
-      evt.Destroy()
-      self._app = None
-      return s
-
-# this global Event is used to let the server thread
-#  know when it should quit
-stopEvent = threading.Event()
-stopEvent.clear()
-
-class _ServerThread(threading.Thread):
-  """ this is the Thread class which actually runs the server
-
-  """
-  def __init__(self,server,verbose=0):
-    self._xmlServ = server
-    threading.Thread.__init__(self,verbose=verbose)
-
-  def stop(self):
-    stopEvent.set()
-
-  def shouldStop(self):
-    return stopEvent.isSet()
-
-  def run(self):
-    while not self.shouldStop():
-      self._xmlServ.handle_request()
-    self._xmlServ = None
-
-class rpcMixin:
-  """A mixin class to provide xmlrpc server functionality to wxPython
-     frames/windows
-
-     If you want to customize this, probably the best idea is to
-     override the OnExternal method, which is what's invoked when an
-     RPC is handled.
-
-  """
-
-  # we'll try a range of ports for the server, this is the size of the
-  #  range to be scanned
-  nPortsToTry=20
-  if sys.platform == 'win32':
-    defPort = 800
-  else:
-    defPort = 8023
-
-  def __init__(self,host='',port=-1,verbose=0,portScan=1):
-    """Constructor
-
-      **Arguments**
-
-        - host: (optional) the hostname for the server
-
-        - port: (optional) the port the server will use
-
-        - verbose: (optional) if set, the server thread will be launched
-          in verbose mode
-
-        - portScan: (optional) if set, we'll scan across a number of ports
-          to find one which is avaiable
-
-    """
-    if port == -1:
-      port = self.defPort
-    self.verbose=verbose
-    self.Bind(EVT_EXTERNAL_EVENT,self.OnExternal)
-    if hasattr(self,'OnClose'):
-      self._origOnClose = self.OnClose
-      self.Disconnect(-1,-1,wx.EVT_CLOSE_WINDOW)
-    else:
-      self._origOnClose = None
-    self.OnClose = self.RPCOnClose
-    self.Bind(wx.EVT_CLOSE,self.RPCOnClose)
-
-    tClass = new.classobj('Handler%d'%(port),(Handler,),{})
-    tClass._app = self
-    if portScan:
-      self.rpcPort = -1
-      for i in xrange(self.nPortsToTry):
-        try:
-          xmlServ = SocketServer.TCPServer((host,port+i),tClass)
-        except:
-          pass
-        else:
-          self.rpcPort = port+i
-    else:
-      self.rpcPort = port
-      try:
-        xmlServ = SocketServer.TCPServer((host,port),tClass)
-      except:
-        self.rpcPort = -1
-
-    if self.rpcPort == -1:
-      raise 'RPCMixinError','Cannot initialize server'
-    self.servThread = _ServerThread(xmlServ,verbose=self.verbose)
-    self.servThread.setName('XML-RPC Server')
-    self.servThread.start()
-
-  def RPCOnClose(self,event):
-    """ callback for when the application is closed
-
-       be sure to shutdown the server and the server thread before
-       leaving
-
-    """
-    # by setting the global stopEvent we inform the server thread
-    # that it's time to shut down.
-    stopEvent.set()
-    if event is not None:
-      # if we came in here from a user event (as opposed to an RPC event),
-      #  then we'll need to kick the server one last time in order
-      #  to get that thread to terminate.  do so now
-      s1 = xmlrpclib.Server('http://localhost:%d'%(self.rpcPort))
-      try:
-        s1._rpcPing()
-      except:
-        pass
-
-    if self._origOnClose is not None:
-      self._origOnClose(event)
-
-  def RPCQuit(self):
-    """ shuts down everything, including the rpc server
-
-    """
-    self.RPCOnClose(None)
-  def OnExternal(self,event):
-    """ this is the callback used to handle RPCs
-
-      **Arguments**
-
-        - event: an _ExternalEvent_ sent by the rpc server
-
-      Exceptions are caught and returned in the global _rpcStatus
-      structure.  This allows the xmlrpc server to report the
-      exception to the client without mucking up any of the delicate
-      thread stuff.
-
-    """
-    event.rpcStatusLock.acquire()
-    doQuit = 0
-    try:
-      methsplit = event.method.split('.')
-      meth = self
-      for piece in methsplit:
-        meth = getattr(meth,piece)
-    except AttributeError,msg:
-      event.rpcStatus.result = 'No Such Method',msg
-      event.rpcStatus.status = rpcEXCEPT
-    else:
-      try:
-        res = apply(meth,event.args)
-      except:
-        import traceback
-        if self.verbose: traceback.print_exc()
-        event.rpcStatus.result = sys.exc_info()[:2]
-        event.rpcStatus.status = rpcEXCEPT
-      else:
-        if res is None:
-          # returning None across the xmlrpc interface is problematic
-          event.rpcStatus.result = []
-        else:
-          event.rpcStatus.result = res
-        event.rpcStatus.status = rpcDONE
-
-    event.rpcStatusLock.release()
-
-    # broadcast (using the condition var) that we're done with the event
-    event.rpcCondVar.acquire()
-    event.rpcCondVar.notify()
-    event.rpcCondVar.release()
-
-
-if __name__ == '__main__':
-  import time
-  if sys.platform == 'win32':
-    port = 800
-  else:
-    port = 8023
-
-  class rpcFrame(wx.Frame,rpcMixin):
-    """A simple wxFrame with the rpcMixin functionality added
-    """
-    def __init__(self,*args,**kwargs):
-      """ rpcHost or rpcPort keyword arguments will be passed along to
-          the xmlrpc server.
-      """
-      mixinArgs = {}
-      if kwargs.has_key('rpcHost'):
-        mixinArgs['host'] = kwargs['rpcHost']
-        del kwargs['rpcHost']
-      if kwargs.has_key('rpcPort'):
-        mixinArgs['port'] = kwargs['rpcPort']
-        del kwargs['rpcPort']
-      if kwargs.has_key('rpcPortScan'):
-        mixinArgs['portScan'] = kwargs['rpcPortScan']
-        del kwargs['rpcPortScan']
-
-      apply(wx.Frame.__init__,(self,)+args,kwargs)
-      apply(rpcMixin.__init__,(self,),mixinArgs)
-
-      self.Bind(wx.EVT_CHAR,self.OnChar)
-
-    def TestFunc(self,args):
-      """a demo method"""
-      return args
-
-    def OnChar(self,event):
-      key = event.GetKeyCode()
-      if key == ord('q'):
-        self.OnQuit(event)
-
-    def OnQuit(self,event):
-      self.OnClose(event)
-
-    def OnClose(self,event):
-      self.Destroy()
-
-
-
-  class MyApp(wx.App):
-    def OnInit(self):
-      self.frame = rpcFrame(None, -1, "wxPython RPCDemo", wx.DefaultPosition,
-                            (300,300), rpcHost='localhost',rpcPort=port)
-      self.frame.Show(True)
-      return True
-
-
-  def testcon(port):
-    s1 = xmlrpclib.Server('http://localhost:%d'%(port))
-    s1.SetTitle('Munged')
-    s1._rpcPing()
-    if doQuit:
-      s1.RPCQuit()
-
-  doQuit = 1
-  if len(sys.argv)>1 and sys.argv[1] == '-q':
-    doQuit = 0
-  nT = threading.activeCount()
-  app = MyApp(0)
-  activePort = app.frame.rpcPort
-  t = threading.Thread(target=lambda x=activePort:testcon(x),verbose=0)
-  t.start()
-
-  app.MainLoop()
-  # give the threads time to shut down
-  if threading.activeCount() > nT:
-    print 'waiting for all threads to terminate'
-    while threading.activeCount() > nT:
-      time.sleep(0.5)
-
-