Changeset 202 for etherws


Ignore:
Timestamp:
08/01/12 21:17:29 (12 years ago)
Author:
atzm
Message:
  • support JSON-RPC 2.0
File:
1 edited

Legend:

Unmodified
Added
Removed
  • etherws/trunk/etherws.py

    r201 r202  
    393393    def open(self): 
    394394        if not self.closed: 
    395             raise ValueError('already opened') 
     395            raise ValueError('Already opened') 
    396396        self._tap = TunTapDevice(self._dev, IFF_TAP | IFF_NO_PI) 
    397397        self._tap.up() 
     
    464464 
    465465        if not self.closed: 
    466             raise websocket.WebSocketException('already opened') 
     466            raise websocket.WebSocketException('Already opened') 
    467467 
    468468        if self._ssl: 
     
    480480    def close(self): 
    481481        if self.closed: 
    482             raise websocket.WebSocketException('already closed') 
     482            raise websocket.WebSocketException('Already closed') 
    483483        self._switch.unregister_port(self) 
    484484        self._ioloop.remove_handler(self.fileno()) 
     
    489489    def fileno(self): 
    490490        if self.closed: 
    491             raise websocket.WebSocketException('closed socket') 
     491            raise websocket.WebSocketException('Closed socket') 
    492492        return self._sock.io_sock.fileno() 
    493493 
    494494    def write_message(self, message, binary=False): 
    495495        if self.closed: 
    496             raise websocket.WebSocketException('closed socket') 
     496            raise websocket.WebSocketException('Closed socket') 
    497497        if binary: 
    498498            flag = websocket.ABNF.OPCODE_BINARY 
     
    527527 
    528528    def post(self): 
    529         id_ = None 
    530  
    531         try: 
    532             req = json.loads(self.request.body) 
    533             method = req['method'] 
    534             params = req['params'] 
    535             id_ = req.get('id') 
    536  
     529        try: 
     530            request = json.loads(self.request.body) 
     531        except Exception as e: 
     532            return self._jsonrpc_response(error={ 
     533                'code':    0 - 32700, 
     534                'message': 'Parse error', 
     535                'data':    '%s: %s' % (e.__class__.__name__, str(e)), 
     536            }) 
     537 
     538        try: 
     539            id_ = request.get('id') 
     540            params = request.get('params') 
     541            version = request['jsonrpc'] 
     542            method = request['method'] 
     543            if version != '2.0': 
     544                raise ValueError('Invalid JSON-RPC version: %s' % version) 
     545        except Exception as e: 
     546            return self._jsonrpc_response(id_=id_, error={ 
     547                'code':    0 - 32600, 
     548                'message': 'Invalid Request', 
     549                'data':    '%s: %s' % (e.__class__.__name__, str(e)), 
     550            }) 
     551 
     552        try: 
    537553            if not method.startswith(self.NAMESPACE + '.'): 
    538                 raise ValueError('invalid method: %s' % method) 
    539  
    540             if not isinstance(params, list): 
    541                 raise ValueError('invalid params: %s' % params) 
    542  
     554                raise ValueError('Invalid method namespace: %s' % method) 
    543555            handler = 'handle_' + method[len(self.NAMESPACE) + 1:] 
    544             result = getattr(self, handler)(params) 
    545             self.finish({'result': result, 'error': None, 'id': id_}) 
    546  
     556            handler = getattr(self, handler) 
     557        except Exception as e: 
     558            return self._jsonrpc_response(id_=id_, error={ 
     559                'code':    0 - 32601, 
     560                'message': 'Method not found', 
     561                'data':    '%s: %s' % (e.__class__.__name__, str(e)), 
     562            }) 
     563 
     564        try: 
     565            return self._jsonrpc_response(id_=id_, result=handler(params)) 
    547566        except Exception as e: 
    548567            traceback.print_exc() 
    549             msg = '%s: %s' % (e.__class__.__name__, str(e)) 
    550             self.finish({'result': None, 'error': {'message': msg}, 'id': id_}) 
     568            return self._jsonrpc_response(id_=id_, error={ 
     569                'code':    0 - 32602, 
     570                'message': 'Invalid params', 
     571                'data':     '%s: %s' % (e.__class__.__name__, str(e)), 
     572            }) 
    551573 
    552574    def handle_listFdb(self, params): 
     
    565587 
    566588    def handle_listPort(self, params): 
    567         list_ = [self._portstat(p) for p in self._switch.portlist] 
    568         return {'entries': list_} 
     589        return {'entries': [self._portstat(p) for p in self._switch.portlist]} 
    569590 
    570591    def handle_addPort(self, params): 
    571         list_ = [] 
    572         for p in params: 
    573             type_ = p['type'] 
    574             target = p['target'] 
    575             options = getattr(self, '_optparse_' + type_)(p.get('options', {})) 
    576             klass = self.IFTYPES[type_] 
    577             interface = klass(self._ioloop, self._switch, target, **options) 
    578             portnum = interface.open() 
    579             list_.append(self._portstat(self._switch.get_port(portnum))) 
    580         return {'entries': list_} 
     592        type_ = params['type'] 
     593        target = params['target'] 
     594        opts = getattr(self, '_optparse_' + type_)(params.get('options', {})) 
     595        cls = self.IFTYPES[type_] 
     596        interface = cls(self._ioloop, self._switch, target, **opts) 
     597        portnum = interface.open() 
     598        return {'entries': [self._portstat(self._switch.get_port(portnum))]} 
    581599 
    582600    def handle_delPort(self, params): 
    583         list_ = [] 
    584         for p in params: 
    585             port = self._switch.get_port(int(p['port'])) 
    586             list_.append(self._portstat(port)) 
    587             port.interface.close() 
    588         return {'entries': list_} 
     601        port = self._switch.get_port(int(params['port'])) 
     602        port.interface.close() 
     603        return {'entries': [self._portstat(port)]} 
    589604 
    590605    def handle_shutPort(self, params): 
    591         list_ = [] 
    592         for p in params: 
    593             port = self._switch.get_port(int(p['port'])) 
    594             port.shut = bool(p['shut']) 
    595             list_.append(self._portstat(port)) 
    596         return {'entries': list_} 
     606        port = self._switch.get_port(int(params['port'])) 
     607        port.shut = bool(params['shut']) 
     608        return {'entries': [self._portstat(port)]} 
    597609 
    598610    def _optparse_tap(self, opt): 
     
    606618        cred = {'user': opt.get('user'), 'passwd': opt.get('passwd')} 
    607619        return {'ssl_': ssl_, 'cred': cred, 'debug': self._debug} 
     620 
     621    def _jsonrpc_response(self, id_=None, result=None, error=None): 
     622        res = {'jsonrpc': '2.0', 'id': id_} 
     623        if result: 
     624            res['result'] = result 
     625        if error: 
     626            res['error'] = error 
     627        self.finish(res) 
    608628 
    609629    @staticmethod 
     
    647667        val = getattr(ns, path, '') 
    648668        if not val.startswith('/'): 
    649             raise ValueError('invalid %: %s' % (path, val)) 
     669            raise ValueError('Invalid %: %s' % (path, val)) 
    650670 
    651671    def getsslopt(ns, key, cert): 
     
    655675            return {'keyfile': kval, 'certfile': cval} 
    656676        elif kval or cval: 
    657             raise ValueError('both %s and %s are required' % (key, cert)) 
     677            raise ValueError('Both %s and %s are required' % (key, cert)) 
    658678        return None 
    659679 
     
    673693            return setattr(ns, port, 80) 
    674694        if not (0 <= val <= 65535): 
    675             raise ValueError('invalid %s: %s' % (port, val)) 
     695            raise ValueError('Invalid %s: %s' % (port, val)) 
    676696 
    677697    def sethtpasswd(ns, htpasswd): 
     
    684704 
    685705    if args.ageout <= 0: 
    686         raise ValueError('invalid ageout: %s' % args.ageout) 
     706        raise ValueError('Invalid ageout: %s' % args.ageout) 
    687707 
    688708    setrealpath(args, 'htpasswd', 'sslkey', 'sslcert') 
     
    707727    if args.port == args.ctlport and args.host == args.ctlhost: 
    708728        if args.path == args.ctlpath: 
    709             raise ValueError('same path/ctlpath on same host') 
     729            raise ValueError('Same path/ctlpath on same host') 
    710730        if args.sslkey != args.ctlsslkey: 
    711             raise ValueError('different sslkey/ctlsslkey on same host') 
     731            raise ValueError('Different sslkey/ctlsslkey on same host') 
    712732        if args.sslcert != args.ctlsslcert: 
    713             raise ValueError('different sslcert/ctlsslcert on same host') 
     733            raise ValueError('Different sslcert/ctlsslcert on same host') 
    714734 
    715735        app = Application([ 
     
    754774 
    755775def start_ctl(args): 
    756     def request(args, method, params): 
    757         method = '.'.join([EtherWebSocketControlHandler.NAMESPACE, method]) 
    758         data = json.dumps({'method': method, 'params': params}) 
     776    def request(args, method, params=None, id_=0): 
    759777        req = urllib2.Request(args.ctlurl) 
    760778        req.add_header('Content-type', 'application/json') 
     
    764782            token = base64.b64encode('%s:%s' % (args.ctluser, args.ctlpasswd)) 
    765783            req.add_header('Authorization', 'Basic %s' % token) 
    766         return json.loads(urllib2.urlopen(req, data).read()) 
     784        method = '.'.join([EtherWebSocketControlHandler.NAMESPACE, method]) 
     785        data = {'jsonrpc': '2.0', 'method': method, 'id': id_} 
     786        if params is not None: 
     787            data['params'] = params 
     788        return json.loads(urllib2.urlopen(req, json.dumps(data)).read()) 
    767789 
    768790    def maxlen(dict_, key, min_): 
     
    786808                  (r['port'], r['type'], shut, r['rx'], r['tx'], r['target'])) 
    787809 
     810    def print_error(error): 
     811        print('  %s (%s)' % (error['message'], error['code'])) 
     812        print('    %s' % error['data']) 
     813 
    788814    def handle_ctl_addport(args): 
    789         params = [{ 
     815        result = request(args, 'addPort', { 
    790816            'type':    args.type, 
    791817            'target':  args.target, 
     
    795821                'user':     args.user, 
    796822                'passwd':   args.passwd, 
    797             } 
    798         }] 
    799         result = request(args, 'addPort', params) 
    800         if result['error']: 
    801             print(result['error']['message']) 
     823            }, 
     824        }) 
     825        if 'error' in result: 
     826            print_error(result['error']) 
    802827        else: 
    803828            print_portlist(result['result']['entries']) 
     
    805830    def handle_ctl_shutport(args): 
    806831        if args.port <= 0: 
    807             raise ValueError('invalid port: %d' % args.port) 
    808         params = [{'port': args.port, 'shut': args.no}] 
    809         result = request(args, 'shutPort', params) 
    810         if result['error']: 
    811             print(result['error']['message']) 
     832            raise ValueError('Invalid port: %d' % args.port) 
     833        result = request(args, 'shutPort', { 
     834            'port': args.port, 
     835            'shut': args.no, 
     836        }) 
     837        if 'error' in result: 
     838            print_error(result['error']) 
    812839        else: 
    813840            print_portlist(result['result']['entries']) 
     
    815842    def handle_ctl_delport(args): 
    816843        if args.port <= 0: 
    817             raise ValueError('invalid port: %d' % args.port) 
    818         params = [{'port': args.port}] 
    819         result = request(args, 'delPort', params) 
    820         if result['error']: 
    821             print(result['error']['message']) 
     844            raise ValueError('Invalid port: %d' % args.port) 
     845        result = request(args, 'delPort', {'port': args.port}) 
     846        if 'error' in result: 
     847            print_error(result['error']) 
    822848        else: 
    823849            print_portlist(result['result']['entries']) 
    824850 
    825851    def handle_ctl_listport(args): 
    826         result = request(args, 'listPort', []) 
    827         if result['error']: 
    828             print(result['error']['message']) 
     852        result = request(args, 'listPort') 
     853        if 'error' in result: 
     854            print_error(result['error']) 
    829855        else: 
    830856            print_portlist(result['result']['entries']) 
    831857 
    832858    def handle_ctl_listfdb(args): 
    833         result = request(args, 'listFdb', []) 
    834         if result['error']: 
    835             print(result['error']['message']) 
    836             return 
     859        result = request(args, 'listFdb') 
     860        if 'error' in result: 
     861            return print_error(result['error']) 
    837862        result = result['result']['entries'] 
    838863        pmax = maxlen(result, 'port', 4) 
Note: See TracChangeset for help on using the changeset viewer.