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
	 Dan Williams
						Dan Williams