Make XMLRPC proxy object callback semantics saner
This commit is contained in:
parent
7774073276
commit
f0205fde5c
@ -33,9 +33,6 @@ import SimpleHTTPServer
|
|||||||
import SocketServer
|
import SocketServer
|
||||||
|
|
||||||
|
|
||||||
RESULT_FAILED = 0
|
|
||||||
RESULT_SUCCESS = 1
|
|
||||||
|
|
||||||
__authinfos = {}
|
__authinfos = {}
|
||||||
|
|
||||||
def _add_authinfo(authinfo):
|
def _add_authinfo(authinfo):
|
||||||
@ -187,17 +184,14 @@ class GlibURLDownloader(gobject.GObject):
|
|||||||
|
|
||||||
def start(self):
|
def start(self):
|
||||||
self._info = urllib.urlopen(self._url)
|
self._info = urllib.urlopen(self._url)
|
||||||
self._fname = _get_filename_from_headers(info.headers)
|
self._suggested_fname = _get_filename_from_headers(info.headers)
|
||||||
if not self._fname:
|
import tempfile
|
||||||
import tempfile
|
garbage, path = urllib.splittype(url)
|
||||||
garbage, path = urllib.splittype(url)
|
garbage, path = urllib.splithost(path or "")
|
||||||
garbage, path = urllib.splithost(path or "")
|
path, garbage = urllib.splitquery(path or "")
|
||||||
path, garbage = urllib.splitquery(path or "")
|
path, garbage = urllib.splitattr(path or "")
|
||||||
path, garbage = urllib.splitattr(path or "")
|
suffix = os.path.splitext(path)[1]
|
||||||
suffix = os.path.splitext(path)[1]
|
(outf, self._fname) = tempfile.mkstemp(suffix=suffix, dir=self._destdir)
|
||||||
(outf, self._fname) = tempfile.mkstemp(suffix=suffix, dir=self._destdir)
|
|
||||||
else:
|
|
||||||
outf = open(os.path.join(self._destdir, self._fname), "w")
|
|
||||||
|
|
||||||
fcntl.fcntl(self._info.fp.fileno(), fcntl.F_SETFD, os.O_NDELAY)
|
fcntl.fcntl(self._info.fp.fileno(), fcntl.F_SETFD, os.O_NDELAY)
|
||||||
self._srcid = gobject.io_add_watch(self._info.fp.fileno(), gobject.IO_IN, self._read_next_chunk)
|
self._srcid = gobject.io_add_watch(self._info.fp.fileno(), gobject.IO_IN, self._read_next_chunk)
|
||||||
@ -221,14 +215,15 @@ class GlibURLDownloader(gobject.GObject):
|
|||||||
def _read_next_chunk(self, source, condition):
|
def _read_next_chunk(self, source, condition):
|
||||||
if not (condition & gobject.IO_IN):
|
if not (condition & gobject.IO_IN):
|
||||||
self.cleanup()
|
self.cleanup()
|
||||||
self.emit("finished", None)
|
os.remove(self._fname)
|
||||||
|
self.emit("finished", None, None)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
data = info.fp.read(self.CHUNK_SIZE)
|
data = info.fp.read(self.CHUNK_SIZE)
|
||||||
count = outf.write(data)
|
count = outf.write(data)
|
||||||
if len(data) < self.CHUNK_SIZE:
|
if len(data) < self.CHUNK_SIZE:
|
||||||
self.cleanup()
|
self.cleanup()
|
||||||
self.emit("finished", self._fname)
|
self.emit("finished", self._fname, self._suggested_fname)
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@ -319,8 +314,6 @@ class GlibHTTP(httplib.HTTP):
|
|||||||
def connect(self, host=None, port=None):
|
def connect(self, host=None, port=None):
|
||||||
httplib.HTTP.connect(self, host, port)
|
httplib.HTTP.connect(self, host, port)
|
||||||
self._conn.sock.setblocking(0)
|
self._conn.sock.setblocking(0)
|
||||||
def get_sock(self):
|
|
||||||
return self._conn.sock
|
|
||||||
|
|
||||||
class GlibXMLRPCTransport(xmlrpclib.Transport):
|
class GlibXMLRPCTransport(xmlrpclib.Transport):
|
||||||
"""Integrate the request with the glib mainloop rather than blocking."""
|
"""Integrate the request with the glib mainloop rather than blocking."""
|
||||||
@ -349,7 +342,7 @@ class GlibXMLRPCTransport(xmlrpclib.Transport):
|
|||||||
# @param verbose Debugging flag.
|
# @param verbose Debugging flag.
|
||||||
# @return Parsed response.
|
# @return Parsed response.
|
||||||
|
|
||||||
def start_request(self, host, handler, request_body, verbose=0, request_cb=None, user_data=None):
|
def start_request(self, host, handler, request_body, verbose=0, reply_handler=None, error_handler=None, user_data=None):
|
||||||
"""Do the first half of the request by sending data to the remote
|
"""Do the first half of the request by sending data to the remote
|
||||||
server. The bottom half bits get run when the remote server's response
|
server. The bottom half bits get run when the remote server's response
|
||||||
actually comes back."""
|
actually comes back."""
|
||||||
@ -365,10 +358,10 @@ class GlibXMLRPCTransport(xmlrpclib.Transport):
|
|||||||
self.send_content(h, request_body)
|
self.send_content(h, request_body)
|
||||||
|
|
||||||
# Schedule a GIOWatch so we don't block waiting for the response
|
# Schedule a GIOWatch so we don't block waiting for the response
|
||||||
gobject.io_add_watch(h.get_sock(), gobject.IO_IN, self._finish_request,
|
gobject.io_add_watch(h._conn.sock, gobject.IO_IN, self._finish_request,
|
||||||
h, host, handler, verbose, request_cb, user_data)
|
h, host, handler, verbose, reply_handler, error_handler, user_data)
|
||||||
|
|
||||||
def _finish_request(self, source, condition, h, host, handler, verbose, request_cb, user_data):
|
def _finish_request(self, source, condition, h, host, handler, verbose, reply_handler=None, error_handler=None, user_data=None):
|
||||||
"""Parse and return response when the remote server actually returns it."""
|
"""Parse and return response when the remote server actually returns it."""
|
||||||
if not (condition & gobject.IO_IN):
|
if not (condition & gobject.IO_IN):
|
||||||
return True
|
return True
|
||||||
@ -379,17 +372,18 @@ class GlibXMLRPCTransport(xmlrpclib.Transport):
|
|||||||
if err[0] != 104:
|
if err[0] != 104:
|
||||||
raise socket.error(err)
|
raise socket.error(err)
|
||||||
else:
|
else:
|
||||||
gobject.idle_add(request_cb, RESULT_FAILED, None, user_data)
|
if error_handler:
|
||||||
|
gobject.idle_add(error_handler, err, user_data)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if errcode != 200:
|
if errcode != 200:
|
||||||
raise xmlrpclib.ProtocolError(host + handler, errcode, errmsg, headers)
|
raise xmlrpclib.ProtocolError(host + handler, errcode, errmsg, headers)
|
||||||
self.verbose = verbose
|
self.verbose = verbose
|
||||||
response = self._parse_response(h.getfile(), h.get_sock())
|
response = self._parse_response(h.getfile(), h._conn.sock)
|
||||||
if request_cb:
|
if reply_handler:
|
||||||
if len(response) == 1:
|
response = response[0]
|
||||||
response = response[0]
|
response.append(user_data)
|
||||||
gobject.idle_add(request_cb, RESULT_SUCCESS, response, user_data)
|
gobject.idle_add(reply_handler, *response)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
class _Method:
|
class _Method:
|
||||||
@ -402,8 +396,8 @@ class _Method:
|
|||||||
self.__name = name
|
self.__name = name
|
||||||
def __getattr__(self, name):
|
def __getattr__(self, name):
|
||||||
return _Method(self.__send, "%s.%s" % (self.__name, name))
|
return _Method(self.__send, "%s.%s" % (self.__name, name))
|
||||||
def __call__(self, request_cb, user_data, *args):
|
def __call__(self, *args, **kwargs):
|
||||||
return self.__send(self.__name, request_cb, user_data, args)
|
return self.__send(self.__name, *args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class GlibServerProxy(xmlrpclib.ServerProxy):
|
class GlibServerProxy(xmlrpclib.ServerProxy):
|
||||||
@ -442,25 +436,30 @@ class GlibServerProxy(xmlrpclib.ServerProxy):
|
|||||||
if not self._handler:
|
if not self._handler:
|
||||||
self._handler = "/RPC2"
|
self._handler = "/RPC2"
|
||||||
|
|
||||||
def __request(self, methodname, request_cb, user_data, params):
|
def __request(self, methodname, *args, **kwargs):
|
||||||
"""Call the method on the remote server. We just start the request here
|
"""Call the method on the remote server. We just start the request here
|
||||||
and the transport itself takes care of scheduling the response callback
|
and the transport itself takes care of scheduling the response callback
|
||||||
when the remote server returns the response. We don't want to block anywhere."""
|
when the remote server returns the response. We don't want to block anywhere."""
|
||||||
|
|
||||||
request = xmlrpclib.dumps(params, methodname, encoding=self._encoding,
|
request = xmlrpclib.dumps(args, methodname, encoding=self._encoding,
|
||||||
allow_none=self._allow_none)
|
allow_none=self._allow_none)
|
||||||
|
|
||||||
|
reply_hdl = kwargs.get("reply_handler")
|
||||||
|
err_hdl = kwargs.get("error_handler")
|
||||||
|
udata = kwargs.get("user_data")
|
||||||
try:
|
try:
|
||||||
response = self._transport.start_request(
|
response = self._transport.start_request(
|
||||||
self._host,
|
self._host,
|
||||||
self._handler,
|
self._handler,
|
||||||
request,
|
request,
|
||||||
verbose=self._verbose,
|
verbose=self._verbose,
|
||||||
request_cb=request_cb,
|
reply_handler=reply_hdl,
|
||||||
user_data=user_data
|
error_handler=err_hdl,
|
||||||
|
user_data=udata
|
||||||
)
|
)
|
||||||
except socket.error, exc:
|
except socket.error, exc:
|
||||||
gobject.idle_add(request_cb, RESULT_FAILED, None, user_data)
|
if err_hdl:
|
||||||
|
gobject.idle_add(err_hdl, exc, udata)
|
||||||
|
|
||||||
def __getattr__(self, name):
|
def __getattr__(self, name):
|
||||||
# magic method dispatcher
|
# magic method dispatcher
|
||||||
@ -523,33 +522,34 @@ class GroupClient(object):
|
|||||||
self._send_sock.sendto(data, (self._address, self._port))
|
self._send_sock.sendto(data, (self._address, self._port))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Test(object):
|
class Test(object):
|
||||||
def test(self, arg1):
|
def test(self, arg1, arg2):
|
||||||
print "Request got %s" % arg1
|
print "Request got %s, %s" % (arg1, arg2)
|
||||||
return "success"
|
return "success", "bork"
|
||||||
|
|
||||||
def xmlrpc_test_cb(response, user_data=None):
|
def xmlrpc_success_cb(response, resp2, loop):
|
||||||
print "Response was %s, user_data was %s" % (response, user_data)
|
print "Response was %s %s" % (response, resp2)
|
||||||
import gtk
|
loop.quit()
|
||||||
gtk.main_quit()
|
|
||||||
|
|
||||||
|
def xmlrpc_error_cb(err, loop):
|
||||||
|
print "Error: %s" % err
|
||||||
|
loop.quit()
|
||||||
|
|
||||||
def xmlrpc_test():
|
def xmlrpc_test(loop):
|
||||||
client = GlibServerProxy("http://127.0.0.1:8888")
|
client = GlibServerProxy("http://127.0.0.1:8888")
|
||||||
client.test(xmlrpc_test_cb, "bar", "test data")
|
client.test("bar", "baz",
|
||||||
|
reply_handler=xmlrpc_success_cb,
|
||||||
|
error_handler=xmlrpc_error_cb,
|
||||||
|
user_data=loop)
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
import gtk
|
loop = gobject.MainLoop()
|
||||||
server = GlibXMLRPCServer(("", 8888))
|
server = GlibXMLRPCServer(("", 8888))
|
||||||
inst = Test()
|
inst = Test()
|
||||||
server.register_instance(inst)
|
server.register_instance(inst)
|
||||||
|
gobject.idle_add(xmlrpc_test, loop)
|
||||||
gobject.idle_add(xmlrpc_test)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
gtk.main()
|
loop.run()
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
print 'Ctrl+C pressed, exiting...'
|
print 'Ctrl+C pressed, exiting...'
|
||||||
print "Done."
|
print "Done."
|
||||||
|
Loading…
Reference in New Issue
Block a user