Top-level dispatch method

def _dispatch(self, method_name):
        """
        Top-level dispatch method
        """
        URLENCODING_CLASS = r'[a-zA-Z0-9\-_.~%]'

        routes = {
            r'^/v1/ping$': {
                'routes': {
                    'GET': self.GET_ping,
                },
            },
            r'^/v1/info$': {
                'routes': {
                    'GET': self.GET_getinfo,
                },
            },
            r'^/v1/addresses/({}{{1,256}})/({}{{1,40}})$'.format(URLENCODING_CLASS, URLENCODING_CLASS): {
                'routes': {
                    'GET': self.GET_names_owned_by_address,
                },
            },
            r'^/v1/accounts/({}{{1,256}})/tokens$'.format(URLENCODING_CLASS): {
                'routes': {
                    'GET': self.GET_account_tokens,
                },
            },
            r'^/v1/accounts/({}{{1,256}})/({}{{1,40}})/status$'.format(URLENCODING_CLASS, URLENCODING_CLASS): {
                'routes': {
                    'GET': self.GET_account_record,
                },
            },
            r'^/v1/accounts/({}{{1,256}})/({}{{1,40}})/balance$'.format(URLENCODING_CLASS, URLENCODING_CLASS): {
                'routes': {
                    'GET': self.GET_account_balance,
                },
            },
            r'^/v1/accounts/({}{{1,256}})/history/([0-9]+)$'.format(URLENCODING_CLASS): {
                'routes': {
                    'GET': self.GET_account_at,
                },
            },
            r'^/v1/accounts/({}{{1,256}})/history$'.format(URLENCODING_CLASS): {
                'routes': {
                    'GET': self.GET_account_history,
                 },
            },
            r'^/v1/blockchains/({}{{1,40}})/name_count'.format(URLENCODING_CLASS) : {
                'routes': {
                    'GET': self.GET_blockchain_num_names
                },
            },
            r'^/v1/blockchains/({}{{1,256}})/subdomains_count'.format(URLENCODING_CLASS) : {
                'routes': {
                    'GET': self.GET_blockchain_num_subdomains
                },
            },
            r'^/v1/blockchains/({}{{1,40}})/operations/([0-9]+)$'.format(URLENCODING_CLASS): {
                'routes': {
                    'GET': self.GET_blockchain_ops
                },
            },
            r'^/v1/blockchains/({}{{1,40}})/names/({}{{1,40}})$'.format(URLENCODING_CLASS, URLENCODING_CLASS): {
                'routes': {
                    'GET': self.GET_blockchain_name_record,
                },
            },
            r'^/v1/blockchains/({}{{1,40}})/consensus$'.format(URLENCODING_CLASS): {
                'routes': {
                    'GET': self.GET_blockchain_consensus,
                },
            },
            r'^/v1/dids/(did:stack:v0:{}+-[0-9]+)$'.format(OP_BASE58CHECK_CLASS): {
                'routes': {
                    'GET': self.GET_did,
                },
            },
            r'^/v1/names$': {
                'routes': {
                    'GET': self.GET_names,
                },
            },
            r'^/v1/names/({}{{1,256}})$'.format(URLENCODING_CLASS): {
                'routes': {
                    'GET': self.GET_name_info,
                },
            },
            r'^/v1/names/({}{{1,256}})/history$'.format(URLENCODING_CLASS): {
                'routes': {
                    'GET': self.GET_name_history,
                },
            },
            r'^/v1/names/({}{{1,256}})/zonefile$'.format(URLENCODING_CLASS): {
                'routes': {
                    'GET': self.GET_name_zonefile,
                },
            },
            r'^/v1/names/({}{{1,256}})/zonefile/([0-9a-fA-F]{{{}}})$'.format(URLENCODING_CLASS, LENGTHS['value_hash'] * 2): {
                'routes': {
                    'GET': self.GET_name_zonefile_by_hash,     # returns a zonefile
                },
            },
            r'^/v1/namespaces$': {
                'routes': {
                    'GET': self.GET_namespaces,
                },
            },
            r'^/v1/namespaces/({}{{1,40}})$'.format(URLENCODING_CLASS): {
                'routes': {
                    'GET': self.GET_namespace_info,
                },
            },
            r'^/v1/namespaces/({}{{1,40}})/names$'.format(URLENCODING_CLASS): {
                'routes': {
                    'GET': self.GET_namespace_names,
                },
            },
            r'^/v1/namespaces/({}{{1,40}})/name_count$'.format(URLENCODING_CLASS): {
                'routes': {
                    'GET': self.GET_namespace_num_names,
                },
            },
            r'^/v1/node/ping$': {
                'routes': {
                    'GET': self.GET_ping,
                },
            },
            r'^/v1/prices/namespaces/({}{{1,40}})$'.format(URLENCODING_CLASS): {
                'routes': {
                    'GET': self.GET_prices_namespace,
                },
            },
            r'^/v1/prices/names/({}{{1,256}})$'.format(URLENCODING_CLASS): {
                'routes': {
                    'GET': self.GET_prices_name,
                },
            },
            r'^/v2/prices/namespaces/({}{{1,40}})$'.format(URLENCODING_CLASS): {
                'routes': {
                    'GET': self.GET_prices_namespace,
                },
            },
            r'^/v2/prices/names/({}{{1,256}})$'.format(URLENCODING_CLASS): {
                'routes': {
                    'GET': self.GET_prices_name,
                },
            },
            r'^/v1/subdomains$': {
                'routes': {
                    'GET': self.GET_subdomains
                },
            },
            r'^/v1/subdomains/([0-9a-fA-F]{64})$': {
                'routes': {
                    'GET': self.GET_subdomain_ops,
                },
            },
            r'^/v1/users/({}{{1,256}})$'.format(URLENCODING_CLASS): {
                'routes': {
                    'GET': self.GET_user_profile,
                },
            },
            r'^/insight-api/addr/({}{{1,40}})/balance$'.format(URLENCODING_CLASS): {
                'routes': {
                    'GET': self.GET_confirmed_balance_insight,
                },
            },
            r'^/insight-api/addr/({}{{1,40}})/unconfirmedBalance$'.format(URLENCODING_CLASS): {
                'routes': {
                    'GET': self.GET_unconfirmed_balance_insight,
                },
            },
            r'^/insight-api/addr/({}{{1,40}})/utxo$'.format(URLENCODING_CLASS): {
                'routes': {
                    'GET': self.GET_utxos_insight,
                },
            },
            r'^/v1/zonefiles/([0-9a-fA-F]{{{}}})$'.format(LENGTHS['value_hash']*2): {
                'routes': {
                    'GET': self.GET_zonefile,
                },
            },
            r'^/v1/zonefile$': {
                'routes': {
                    'POST': self.POST_zonefile,
                },
            },
            r'^/v1/.*$': {
                'routes': {
                    'OPTIONS': self.OPTIONS_preflight,
                },
            },
            r'^/v2/.*$': {
                'routes': {
                    'OPTIONS': self.OPTIONS_preflight,
                },
            },
        }
        
        conf = get_blockstack_api_opts()
        if not conf['enabled']:
            # this feature is not enabled
            self._send_headers(status_code=404, content_type='text/plain')
            return 

        path_info = self.get_path_and_qs()
        if 'error' in path_info:
            self._send_headers(status_code=400, content_type='text/plain')
            return

        qs_values = path_info['qs_values']

        route_info = self._route_match( method_name, path_info, routes )
        if route_info is None:
            if BLOCKSTACK_DEBUG and BLOCKSTACK_TEST:
                log.warning("Unmatched route: {} '{}'".format(method_name, path_info['path']))

            routes = routes.keys()
            routes.sort()
            log.debug(json.dumps(routes, sort_keys=True, indent=4))
            return self._reply_json({'error': 'No such endpoint'}, status_code=404)

        route_args = route_info['args']
        route_method = route_info['method']
        route = route_info['route']

        if BLOCKSTACK_TEST:
            log.debug("\nfull path: {}\nmethod: {}\npath: {}\nqs: {}\nheaders:\n{}\n".format(self.path, method_name, path_info['path'], qs_values, '\n'.join( '{}: {}'.format(k, v) for (k, v) in self.headers.items() )))

        try:
            return route_method( path_info, *route_args )
        except Exception as e:
            log.exception(e)
            return self._send_headers(status_code=500, content_type='text/plain')