ray-core/ray/api.py
import json, bottle, logging
from bottle import request as bottle_req, response as bottle_resp, static_file
from .endpoint import EndpointHandler
from .login import LoginHandler, LogoutHandler, increase_cookie_timestamp
from .actions import Action
from . import exceptions, http
from . import application as app_control
from .single_request import SingleRequestHandler
from functools import wraps
application = bottle.Bottle()
log = logging.getLogger('ray')
def to_json(fnc):
@wraps(fnc)
def inner(*args, **kwargs):
bottle_resp.headers['Content-Type'] = 'application/json'
from_func = fnc(*args, **kwargs)
if from_func is not None:
return json.dumps({'result': from_func})
return inner
@application.route('/static/<filepath:path>')
def server_static(filepath):
return static_file(filepath, root='static')
@application.route('/api/<url:re:.+>', method=['GET', 'POST', 'PUT', 'DELETE'], apply=to_json)
def dispatch(url):
"""
This class is the beginning of all entrypoints in the Ray API. Here, each url
will be redirect to the right handler
"""
url = bottle_req.path
log.info('request: %s', bottle_req.url)
if url[-1] == '/':
url = url[:-1]
response_code = 200
try:
processed = process(url, bottle_req, bottle_resp)
try:
from_func, http_status = processed[0], processed[1]
bottle_resp.status = http_status
return from_func
except:
return processed
except exceptions.RayException as e:
log.exception('ray exception: ')
response_code = e.http_code
except:
log.exception('exception:')
raise
bottle_resp.status = response_code
def process(fullpath, request, response):
if __is_login(fullpath):
return LoginHandler.process(request, response)
elif __is_ping_status(fullpath):
return _handle_ping_status()
elif __is_logout(fullpath):
return LogoutHandler.logout(response)
elif _is_single_url(fullpath):
return SingleRequestHandler.process(fullpath, bottle_req.method.lower(), bottle_req, bottle_resp)
elif _is_endpoint(fullpath):
return EndpointHandler(request, fullpath).process()
elif _is_action(fullpath):
return __handle_action(fullpath), 200
raise exceptions.BadRequest()
def _handle_ping_status():
cookie_name, user_token = increase_cookie_timestamp()
bottle_resp.set_cookie(cookie_name, user_token.decode('utf-8'))
def __handle_action(url):
# url e.g: /api/user/123/action
arg = None
if len(url.split('/')) >= 5: # indicate that has an id between endpoint and action_name
arg = http.param_at(url, -2)
return Action(url, arg, bottle_req).process_action()
def _is_single_url(fullpath):
return app_control.has_single_url(fullpath)
def __is_ping_status(fullpath):
return fullpath == '/api/_ping'
def __is_login(full_path):
return full_path == '/api/_login'
def __is_logout(full_path):
return full_path == '/api/_logout'
def _is_endpoint(full_path):
full_path = full_path.split('?')[0]
if len(full_path.split('/')) == 4:
try:
int(full_path.split('/')[-1])
return True
except:
return False
return len(full_path.split('/')) <= 4 and len(full_path.split('/')) > 2
def _is_action(full_path):
# full_path e.g: /api/user/123/action
# full_path e.g: /api/user/action
if len(full_path.split('/')) >= 4:
try:
int(full_path.split('/')[-1])
except Exception:
return True
return len(full_path.split('/')) == 5