source: OpenRLabs-Git/deploy/rlabs-docker/web2py-rlabs/gluon/contrib/simplejsonrpc.py

main
Last change on this file was 42bd667, checked in by David Fuertes <dfuertes@…>, 4 years ago

Historial Limpio

  • Property mode set to 100755
File size: 5.2 KB
Line 
1# -*- coding: utf-8 -*-
2# This program is free software; you can redistribute it and/or modify
3# it under the terms of the GNU Lesser General Public License as published by the
4# Free Software Foundation; either version 3, or (at your option) any later
5# version.
6#
7# This program is distributed in the hope that it will be useful, but
8# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY
9# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
10# for more details.
11
12"Pythonic simple JSON RPC Client implementation"
13from __future__ import print_function
14
15__author__ = "Mariano Reingart (reingart@gmail.com)"
16__copyright__ = "Copyright (C) 2011 Mariano Reingart"
17__license__ = "LGPL 3.0"
18__version__ = "0.05"
19
20import sys
21PY2 = sys.version_info[0] == 2
22
23if PY2:
24    import urllib
25    from xmlrpclib import Transport, SafeTransport
26    from cStringIO import StringIO
27else:
28    import urllib.request as urllib
29    from xmlrpc.client import Transport, SafeTransport
30    from io import StringIO
31import random
32import json
33from gluon._compat import basestring
34
35class JSONRPCError(RuntimeError):
36    "Error object for remote procedure call fail"
37    def __init__(self, code, message, data=''):       
38        if isinstance(data, basestring):
39            data = [data]
40        value = "%s: %s\n%s" % (code, message, '\n'.join(data))
41        RuntimeError.__init__(self, value)
42        self.code = code
43        self.message = message
44        self.data = data
45
46
47class JSONDummyParser:
48    "json wrapper for xmlrpclib parser interfase"
49    def __init__(self):
50        self.buf = StringIO()
51
52    def feed(self, data):
53        self.buf.write(data.decode('utf-8'))
54
55    def close(self):
56        return self.buf.getvalue()
57
58
59class JSONTransportMixin:
60    "json wrapper for xmlrpclib transport interfase"
61
62    def send_content(self, connection, request_body):
63        connection.putheader("Content-Type", "application/json")
64        connection.putheader("Content-Length", str(len(request_body)))
65        connection.endheaders()
66        if request_body:
67            connection.send(str.encode(request_body))
68        # todo: add gzip compression
69
70    def getparser(self):
71        # get parser and unmarshaller
72        parser = JSONDummyParser()
73        return parser, parser
74
75
76class JSONTransport(JSONTransportMixin, Transport):
77    pass
78
79
80class JSONSafeTransport(JSONTransportMixin, SafeTransport):
81    pass
82
83
84class ServerProxy(object):
85    "JSON RPC Simple Client Service Proxy"
86
87    def __init__(self, uri, transport=None, encoding=None, verbose=0, version=None, json_encoder=None):
88        self.location = uri             # server location (url)
89        self.trace = verbose            # show debug messages
90        self.exceptions = True          # raise errors? (JSONRPCError)
91        self.timeout = None
92        self.json_request = self.json_response = ''
93        self.version = version          # '2.0' for jsonrpc2
94        self.json_encoder = json_encoder  # Allow for a custom JSON encoding class
95
96        type, uri = urllib.splittype(uri)
97        if type not in ("http", "https"):
98            raise IOError("unsupported JSON-RPC protocol")
99        self.__host, self.__handler = urllib.splithost(uri)
100
101        if transport is None:
102            if type == "https":
103                transport = JSONSafeTransport()
104            else:
105                transport = JSONTransport()
106        self.__transport = transport
107        self.__encoding = encoding
108        self.__verbose = verbose
109
110    def __getattr__(self, attr):
111        "pseudo method that can be called"
112        return lambda *args, **vars: self.call(attr, *args, **vars)
113
114    def call(self, method, *args, **vars):
115        "JSON RPC communication (method invocation)"
116
117        # build data sent to the service
118        request_id = random.randint(0, sys.maxsize)
119        data = {'id': request_id, 'method': method, 'params': args or vars, }
120        if self.version:
121            data['jsonrpc'] = self.version #mandatory key/value for jsonrpc2 validation else err -32600
122        request = json.dumps(data, cls=self.json_encoder)
123
124        # make HTTP request (retry if connection is lost)
125        response = self.__transport.request(
126            self.__host,
127            self.__handler,
128            request,
129            verbose=self.__verbose
130        )
131
132        # store plain request and response for further debugging
133        self.json_request = request
134        self.json_response = response
135
136        # parse json data coming from service
137        # {'version': '1.1', 'id': id, 'result': result, 'error': None}
138        response = json.loads(response)
139
140        self.error = response.get('error', {})
141        if self.error and self.exceptions:
142            raise JSONRPCError(self.error.get('code', 0),
143                               self.error.get('message', ''),
144                               self.error.get('data', None))
145        if response['id'] != request_id:
146            raise JSONRPCError(0, "JSON Request ID != Response ID")
147
148        return response.get('result')
149
150
151ServiceProxy = ServerProxy
152
153
154if __name__ == "__main__":
155    # basic tests:
156    location = "http://www.web2py.com.ar/webservices/sample/call/jsonrpc"
157    client = ServerProxy(location, verbose='--verbose' in sys.argv,)
158    print(client.add(1, 2))
Note: See TracBrowser for help on using the repository browser.