Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

""" 

This module implements the JSON-RPC 2.0 protocol, as defined in: 

http://groups.google.com/group/json-rpc/web/json-rpc-2-0 

""" 

 

import urllib 

import json 

import traceback 

 

from scrapy.utils.serialize import ScrapyJSONDecoder 

 

# JSON-RPC 2.0 errors, as defined in: 

class jsonrpc_errors: 

    PARSE_ERROR = -32700 

    INVALID_REQUEST = -32600 

    METHOD_NOT_FOUND = -32601 

    INVALID_PARAMS = -32602 

    INTERNAL_ERROR = -32603 

 

class JsonRpcError(Exception): 

 

    def __init__(self, code, message, data=None): 

        super(JsonRpcError, self).__init__() 

        self.code = code 

        self.message = message 

        self.data = data 

 

    def __str__(self): 

        return "JSON-RPC error (code %d): %s" % (self.code, self.message) 

 

def jsonrpc_client_call(url, method, *args, **kwargs): 

    """Execute a JSON-RPC call on the given url""" 

    _urllib = kwargs.pop('_urllib', urllib) 

    if args and kwargs: 

        raise ValueError("Pass *args or **kwargs but not both to jsonrpc_client_call") 

    req = {'jsonrpc': '2.0', 'method': method, 'params': args or kwargs, 'id': 1} 

    res = json.loads(_urllib.urlopen(url, json.dumps(req)).read()) 

    if 'result' in res: 

        return res['result'] 

    elif 'error' in res: 

        er = res['error'] 

        raise JsonRpcError(er['code'], er['message'], er['data']) 

    else: 

        msg = "JSON-RPC response must contain 'result' or 'error': %s" % res 

        raise ValueError(msg) 

 

def jsonrpc_server_call(target, jsonrpc_request, json_decoder=None): 

    """Execute the given JSON-RPC request (as JSON-encoded string) on the given 

    target object and return the JSON-RPC response, as a dict 

    """ 

52    if json_decoder is None: 

        json_decoder = ScrapyJSONDecoder() 

 

    try: 

        req = json_decoder.decode(jsonrpc_request) 

    except Exception, e: 

        return jsonrpc_error(None, jsonrpc_errors.PARSE_ERROR, 'Parse error', \ 

            traceback.format_exc()) 

 

    try: 

        id, methname = req['id'], req['method'] 

    except KeyError: 

        return jsonrpc_error(None, jsonrpc_errors.INVALID_REQUEST, 'Invalid Request') 

 

    try: 

        method = getattr(target, methname) 

    except AttributeError: 

        return jsonrpc_error(id, jsonrpc_errors.METHOD_NOT_FOUND, 'Method not found') 

 

    params = req.get('params', []) 

    a, kw = ([], params) if isinstance(params, dict) else (params, {}) 

    kw = dict([(str(k), v) for k, v in kw.items()]) # convert kw keys to str 

    try: 

        return jsonrpc_result(id, method(*a, **kw)) 

    except Exception, e: 

        return jsonrpc_error(id, jsonrpc_errors.INTERNAL_ERROR, str(e), \ 

            traceback.format_exc()) 

 

def jsonrpc_error(id, code, message, data=None): 

    """Create JSON-RPC error response""" 

    return { 

        'jsonrpc': '2.0', 

        'error': { 

            'code': code, 

            'message': message, 

            'data': data, 

        }, 

        'id': id, 

    } 

 

def jsonrpc_result(id, result): 

    """Create JSON-RPC result response""" 

    return { 

        'jsonrpc': '2.0', 

        'result': result, 

        'id': id, 

    }