Added examples and form processing
This commit is contained in:
parent
8fbc6c2c4e
commit
49c499f44d
11
examples/Dockerfile
Normal file
11
examples/Dockerfile
Normal file
|
@ -0,0 +1,11 @@
|
|||
FROM python:3.5
|
||||
MAINTAINER Channel Cat <channelcat@gmail.com>
|
||||
|
||||
ADD . /code
|
||||
RUN pip3 install git+https://github.com/channelcat/sanic
|
||||
|
||||
EXPOSE 8000
|
||||
|
||||
WORKDIR /code
|
||||
|
||||
CMD ["python", "simple_server.py"]
|
6
examples/docker-compose.yml
Normal file
6
examples/docker-compose.yml
Normal file
|
@ -0,0 +1,6 @@
|
|||
version: '2'
|
||||
services:
|
||||
sanic:
|
||||
build: .
|
||||
ports:
|
||||
- "8000:8000"
|
10
examples/simple_server.py
Normal file
10
examples/simple_server.py
Normal file
|
@ -0,0 +1,10 @@
|
|||
from sanic import Sanic
|
||||
from sanic.response import json
|
||||
|
||||
app = Sanic(__name__)
|
||||
|
||||
@app.route("/")
|
||||
async def test(request):
|
||||
return json({ "test": True })
|
||||
|
||||
app.run(host="0.0.0.0", port=8000)
|
59
examples/try_everything.py
Normal file
59
examples/try_everything.py
Normal file
|
@ -0,0 +1,59 @@
|
|||
from sanic import Sanic
|
||||
from sanic.log import log
|
||||
from sanic.response import json, text
|
||||
from sanic.exceptions import ServerError
|
||||
|
||||
app = Sanic(__name__)
|
||||
|
||||
@app.route("/")
|
||||
async def test_async(request):
|
||||
return json({ "test": True })
|
||||
|
||||
@app.route("/sync", methods=['GET', 'POST'])
|
||||
def test_sync(request):
|
||||
return json({ "test": True })
|
||||
|
||||
@app.route("/dynamic/<name>/<id:int>")
|
||||
def test_params(request, name, id):
|
||||
return text("yeehaww {} {}".format(name, id))
|
||||
|
||||
@app.route("/exception")
|
||||
def exception(request):
|
||||
raise ServerError("It's dead jim")
|
||||
|
||||
# ----------------------------------------------- #
|
||||
# Exceptions
|
||||
# ----------------------------------------------- #
|
||||
|
||||
@app.exception(ServerError)
|
||||
async def test(request, exception):
|
||||
return json({ "exception": "{}".format(exception), "status": exception.status_code }, status=exception.status_code)
|
||||
|
||||
# ----------------------------------------------- #
|
||||
# Read from request
|
||||
# ----------------------------------------------- #
|
||||
|
||||
@app.route("/json")
|
||||
def post_json(request):
|
||||
return json({ "received": True, "message": request.json })
|
||||
|
||||
@app.route("/form")
|
||||
def post_json(request):
|
||||
return json({ "received": True, "form_data": request.form, "penos": request.form.get('penos') })
|
||||
|
||||
@app.route("/query_string")
|
||||
def query_string(request):
|
||||
return json({ "parsed": True, "args": request.args, "url": request.url, "query_string": request.query_string })
|
||||
|
||||
# ----------------------------------------------- #
|
||||
# Run Server
|
||||
# ----------------------------------------------- #
|
||||
|
||||
def before_start(loop):
|
||||
log.info("OH OH OH OH OHHHHHHHH")
|
||||
def before_stop(loop):
|
||||
log.info("TRIED EVERYTHING")
|
||||
|
||||
app.run(host="0.0.0.0", port=8000, debug=True, before_start=before_start, before_stop=before_stop)
|
||||
|
||||
|
|
@ -2,7 +2,10 @@ from .response import text
|
|||
from traceback import format_exc
|
||||
|
||||
class SanicException(Exception):
|
||||
pass
|
||||
def __init__(self, message, status_code=None):
|
||||
super().__init__(message)
|
||||
if status_code is not None:
|
||||
self.status_code = status_code
|
||||
|
||||
class NotFound(SanicException):
|
||||
status_code = 404
|
||||
|
@ -13,26 +16,28 @@ class ServerError(SanicException):
|
|||
|
||||
class Handler:
|
||||
handlers = None
|
||||
debug = False
|
||||
def __init__(self):
|
||||
def __init__(self, sanic):
|
||||
self.handlers = {}
|
||||
self.sanic = sanic
|
||||
|
||||
def add(self, exception_type, handler):
|
||||
self.handlers[exception_type] = handler
|
||||
def add(self, exception, handler):
|
||||
self.handlers[exception] = handler
|
||||
|
||||
def response(self, request, exception):
|
||||
handler = self.handlers.get(type(exception))
|
||||
if handler:
|
||||
response = handler(request, exception)
|
||||
else:
|
||||
response = Handler.default(request, exception, self.debug)
|
||||
"""
|
||||
Fetches and executes an exception handler and returns a reponse object
|
||||
:param request: Request
|
||||
:param exception: Exception to handle
|
||||
:return: Response object
|
||||
"""
|
||||
handler = self.handlers.get(type(exception), self.default)
|
||||
response = handler(request=request, exception=exception)
|
||||
return response
|
||||
|
||||
@staticmethod
|
||||
def default(request, exception, debug):
|
||||
def default(self, request, exception):
|
||||
if issubclass(type(exception), SanicException):
|
||||
return text("Error: {}".format(exception), status=getattr(exception, 'status_code', 500))
|
||||
elif debug:
|
||||
elif self.sanic.debug:
|
||||
return text("Error: {}\nException: {}".format(exception, format_exc()), status=500)
|
||||
else:
|
||||
return text("An error occurred while generating the request", status=500)
|
|
@ -2,8 +2,26 @@ from httptools import parse_url
|
|||
from urllib.parse import parse_qs
|
||||
from ujson import loads as json_loads
|
||||
|
||||
class RequestParameters(dict):
|
||||
"""
|
||||
Hosts a dict with lists as values where get returns the first
|
||||
value of the list and getlist returns the whole shebang
|
||||
"""
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.super = super()
|
||||
self.super.__init__(*args, **kwargs)
|
||||
def get(self, name, default=None):
|
||||
values = self.super.get(name)
|
||||
return values[0] if values else default
|
||||
def getlist(self, name, default=None):
|
||||
return self.super.get(name, default)
|
||||
|
||||
class Request:
|
||||
__slots__ = ('url', 'headers', 'version', 'method', 'query_string', 'body', 'parsed_json', 'parsed_args')
|
||||
__slots__ = (
|
||||
'url', 'headers', 'version', 'method',
|
||||
'query_string', 'body',
|
||||
'parsed_json', 'parsed_args', 'parsed_form',
|
||||
)
|
||||
|
||||
def __init__(self, url_bytes, headers, version, method):
|
||||
# TODO: Content-Encoding detection
|
||||
|
@ -17,27 +35,38 @@ class Request:
|
|||
# Init but do not inhale
|
||||
self.body = None
|
||||
self.parsed_json = None
|
||||
self.parsed_form = None
|
||||
self.parsed_args = None
|
||||
|
||||
@property
|
||||
def json(self):
|
||||
if not self.parsed_json:
|
||||
if not self.body:
|
||||
raise ValueError("No body to parse")
|
||||
self.parsed_json = json_loads(self.body)
|
||||
try:
|
||||
self.parsed_json = json_loads(self.body)
|
||||
except:
|
||||
pass
|
||||
|
||||
return self.parsed_json
|
||||
|
||||
@property
|
||||
def form(self):
|
||||
if not self.parsed_form:
|
||||
content_type = self.headers.get('Content-Type')
|
||||
try:
|
||||
# TODO: form-data
|
||||
if content_type is None or content_type == 'application/x-www-form-urlencoded':
|
||||
self.parsed_form = RequestParameters(parse_qs(self.body.decode('utf-8')))
|
||||
except:
|
||||
pass
|
||||
|
||||
return self.parsed_form
|
||||
|
||||
@property
|
||||
def args(self):
|
||||
if self.parsed_args is None:
|
||||
if self.query_string:
|
||||
parsed_query_string = parse_qs(self.query_string).items()
|
||||
self.parsed_args = {k:[_v for _v in v] if len(v)>1 else v[0] for k,v in parsed_query_string}
|
||||
print(self.parsed_args)
|
||||
self.parsed_args = RequestParameters(parse_qs(self.query_string))
|
||||
else:
|
||||
self.parsed_args = {}
|
||||
|
||||
return self.parsed_args
|
||||
|
||||
# TODO: Files
|
|
@ -10,7 +10,7 @@ STATUS_CODES = {
|
|||
402: 'Payment Required',
|
||||
403: 'Forbidden',
|
||||
404: 'Not Found',
|
||||
400: 'Method Not Allowed',
|
||||
405: 'Method Not Allowed',
|
||||
500: 'Internal Server Error',
|
||||
501: 'Not Implemented',
|
||||
502: 'Bad Gateway',
|
||||
|
@ -19,9 +19,9 @@ STATUS_CODES = {
|
|||
}
|
||||
|
||||
class HTTPResponse:
|
||||
__slots__ = ('body', 'status', 'content_type')
|
||||
__slots__ = ('body', 'status', 'content_type', 'headers')
|
||||
|
||||
def __init__(self, body=None, status=200, content_type='text/plain', body_bytes=b''):
|
||||
def __init__(self, body=None, status=200, headers=[], content_type='text/plain', body_bytes=b''):
|
||||
self.content_type = content_type
|
||||
|
||||
if not body is None:
|
||||
|
@ -30,6 +30,7 @@ class HTTPResponse:
|
|||
self.body = body_bytes
|
||||
|
||||
self.status = status
|
||||
self.headers = headers
|
||||
|
||||
def output(self, version="1.1", keep_alive=False, keep_alive_timeout=None):
|
||||
# This is all returned in a kind-of funky way
|
||||
|
@ -37,6 +38,9 @@ class HTTPResponse:
|
|||
additional_headers = []
|
||||
if keep_alive and not keep_alive_timeout is None:
|
||||
additional_headers = [b'Keep-Alive: timeout=', str(keep_alive_timeout).encode(), b's\r\n']
|
||||
if self.headers:
|
||||
for name, value in self.headers.items():
|
||||
additional_headers.append('{}: {}\r\n'.format(name, value).encode('utf-8'))
|
||||
|
||||
return b''.join([
|
||||
'HTTP/{} {} {}\r\n'.format(version, self.status, STATUS_CODES.get(self.status, 'FAIL')).encode(),
|
||||
|
@ -48,9 +52,9 @@ class HTTPResponse:
|
|||
self.body,
|
||||
])
|
||||
|
||||
def json(body, status=200):
|
||||
return HTTPResponse(ujson.dumps(body), status=status, content_type="application/json")
|
||||
def text(body, status=200):
|
||||
return HTTPResponse(body, status=status, content_type="text/plain")
|
||||
def html(body, status=200):
|
||||
return HTTPResponse(body, status=status, content_type="text/html")
|
||||
def json(body, status=200, headers=None):
|
||||
return HTTPResponse(ujson.dumps(body), headers=headers, status=status, content_type="application/json")
|
||||
def text(body, status=200, headers=None):
|
||||
return HTTPResponse(body, status=status, headers=headers, content_type="text/plain")
|
||||
def html(body, status=200, headers=None):
|
||||
return HTTPResponse(body, status=status, headers=headers, content_type="text/html")
|
133
sanic/router.py
133
sanic/router.py
|
@ -1,18 +1,123 @@
|
|||
from .log import log
|
||||
from .exceptions import NotFound
|
||||
import re
|
||||
from collections import namedtuple
|
||||
from .exceptions import NotFound, InvalidUsage
|
||||
|
||||
class Router():
|
||||
routes = None
|
||||
Route = namedtuple("Route", ['handler', 'methods', 'pattern', 'parameters'])
|
||||
Parameter = namedtuple("Parameter", ['name', 'cast'])
|
||||
|
||||
def __init__(self):
|
||||
self.routes = {}
|
||||
class Router:
|
||||
"""
|
||||
Router supports basic routing with parameters and method checks
|
||||
Usage:
|
||||
@sanic.route('/my/url/<my_parameter>', methods=['GET', 'POST', ...])
|
||||
def my_route(request, my_parameter):
|
||||
do stuff...
|
||||
|
||||
def add(self, uri, handler):
|
||||
self.routes[uri] = handler
|
||||
Parameters will be passed as keyword arguments to the request handling function provided
|
||||
Parameters can also have a type by appending :type to the <parameter>. If no type is provided,
|
||||
a string is expected. A regular expression can also be passed in as the type
|
||||
|
||||
def get(self, request):
|
||||
handler = self.routes.get(request.url)
|
||||
if handler:
|
||||
return handler
|
||||
else:
|
||||
raise NotFound("Requested URL {} not found".format(request.url))
|
||||
TODO:
|
||||
This probably needs optimization for larger sets of routes,
|
||||
since it checks every route until it finds a match which is bad and I should feel bad
|
||||
"""
|
||||
routes = None
|
||||
regex_types = {
|
||||
"string": (None, "\w+"),
|
||||
"int": (int, "\d+"),
|
||||
"number": (float, "[0-9\\.]+"),
|
||||
"alpha": (None, "[A-Za-z]+"),
|
||||
}
|
||||
|
||||
def __init__(self):
|
||||
self.routes = []
|
||||
|
||||
def add(self, uri, methods, handler):
|
||||
"""
|
||||
Adds a handler to the route list
|
||||
:param uri: Path to match
|
||||
:param methods: Array of accepted method names. If none are provided, any method is allowed
|
||||
:param handler: Request handler function. When executed, it should provide a response object.
|
||||
:return: Nothing
|
||||
"""
|
||||
|
||||
# Dict for faster lookups of if method allowed
|
||||
methods_dict = { method: True for method in methods } if methods else None
|
||||
|
||||
parameters = []
|
||||
def add_parameter(match):
|
||||
# We could receive NAME or NAME:PATTERN
|
||||
parts = match.group(1).split(':')
|
||||
if len(parts) == 2:
|
||||
parameter_name, parameter_pattern = parts
|
||||
else:
|
||||
parameter_name = parts[0]
|
||||
parameter_pattern = 'string'
|
||||
|
||||
# Pull from pre-configured types
|
||||
parameter_regex = self.regex_types.get(parameter_pattern)
|
||||
if parameter_regex:
|
||||
parameter_type, parameter_pattern = parameter_regex
|
||||
else:
|
||||
parameter_type = None
|
||||
|
||||
parameter = Parameter(name=parameter_name, cast=parameter_type)
|
||||
parameters.append(parameter)
|
||||
|
||||
return "({})".format(parameter_pattern)
|
||||
|
||||
pattern_string = re.sub("<(.+?)>", add_parameter, uri)
|
||||
pattern = re.compile("^{}$".format(pattern_string))
|
||||
|
||||
route = Route(handler=handler, methods=methods_dict, pattern=pattern, parameters=parameters)
|
||||
self.routes.append(route)
|
||||
|
||||
def get(self, request):
|
||||
"""
|
||||
Gets a request handler based on the URL of the request, or raises an error
|
||||
:param request: Request object
|
||||
:return: handler, arguments, keyword arguments
|
||||
"""
|
||||
|
||||
route = None
|
||||
args = []
|
||||
kwargs = {}
|
||||
for _route in self.routes:
|
||||
match = _route.pattern.match(request.url)
|
||||
if match:
|
||||
for index, parameter in enumerate(_route.parameters, start=1):
|
||||
value = match.group(index)
|
||||
kwargs[parameter.name] = parameter.cast(value) if parameter.cast is not None else value
|
||||
route = _route
|
||||
break
|
||||
|
||||
if route:
|
||||
if route.methods and not request.method in route.methods:
|
||||
raise InvalidUsage("Method {} not allowed for URL {}".format(request.method, request.url), status_code=405)
|
||||
return route.handler, args, kwargs
|
||||
else:
|
||||
raise NotFound("Requested URL {} not found".format(request.url))
|
||||
|
||||
class SimpleRouter:
|
||||
"""
|
||||
Simple router records and reads all routes from a dictionary
|
||||
It does not support parameters in routes, but is very fast
|
||||
"""
|
||||
routes = None
|
||||
|
||||
def __init__(self):
|
||||
self.routes = {}
|
||||
|
||||
def add(self, uri, methods, handler):
|
||||
# Dict for faster lookups of method allowed
|
||||
methods_dict = { method: True for method in methods } if methods else None
|
||||
self.routes[uri] = Route(handler=handler, methods=methods_dict, pattern=uri, parameters=None)
|
||||
|
||||
def get(self, request):
|
||||
route = self.routes.get(request.url)
|
||||
if route:
|
||||
if route.methods and not request.method in route.methods:
|
||||
raise InvalidUsage("Method {} not allowed for URL {}".format(request.method, request.url), status_code=405)
|
||||
return route.handler, [], {}
|
||||
else:
|
||||
raise NotFound("Requested URL {} not found".format(request.url))
|
|
@ -6,6 +6,7 @@ from .router import Router
|
|||
from .server import serve
|
||||
from .exceptions import ServerError
|
||||
from inspect import isawaitable
|
||||
from traceback import format_exc
|
||||
|
||||
class Sanic:
|
||||
name = None
|
||||
|
@ -17,47 +18,89 @@ class Sanic:
|
|||
def __init__(self, name, router=None, error_handler=None):
|
||||
self.name = name
|
||||
self.router = router or Router()
|
||||
self.error_handler = error_handler or Handler()
|
||||
self.error_handler = error_handler or Handler(self)
|
||||
self.config = Config()
|
||||
|
||||
def route(self, uri):
|
||||
# -------------------------------------------------------------------- #
|
||||
# Decorators
|
||||
# -------------------------------------------------------------------- #
|
||||
|
||||
def route(self, uri, methods=None):
|
||||
"""
|
||||
Decorates a function to be registered as a route
|
||||
:param uri: path of the URL
|
||||
:param methods: list or tuple of methods allowed
|
||||
:return: decorated function
|
||||
"""
|
||||
def response(handler):
|
||||
self.router.add(uri=uri, handler=handler)
|
||||
self.router.add(uri=uri, methods=methods, handler=handler)
|
||||
return handler
|
||||
|
||||
return response
|
||||
|
||||
def exception(self, *args, **kwargs):
|
||||
def exception(self, *exceptions):
|
||||
"""
|
||||
Decorates a function to be registered as a route
|
||||
:param uri: path of the URL
|
||||
:param methods: list or tuple of methods allowed
|
||||
:return: decorated function
|
||||
"""
|
||||
def response(handler):
|
||||
self.error_handler.add(*args, **kwargs)
|
||||
for exception in exceptions:
|
||||
self.error_handler.add(exception, handler)
|
||||
return handler
|
||||
|
||||
return response
|
||||
|
||||
async def handle_request(self, request, respond):
|
||||
# -------------------------------------------------------------------- #
|
||||
# Request Handling
|
||||
# -------------------------------------------------------------------- #
|
||||
|
||||
async def handle_request(self, request, response_callback):
|
||||
"""
|
||||
Takes a request from the HTTP Server and returns a response object to be sent back
|
||||
The HTTP Server only expects a response object, so exception handling must be done here
|
||||
:param request: HTTP Request object
|
||||
:param response_callback: Response function to be called with the response as the only argument
|
||||
:return: Nothing
|
||||
"""
|
||||
try:
|
||||
handler = self.router.get(request)
|
||||
handler, args, kwargs = self.router.get(request)
|
||||
if handler is None:
|
||||
raise ServerError("'None' was returned while requesting a handler from the router")
|
||||
|
||||
response = handler(request)
|
||||
# Check if the handler is asynchronous
|
||||
response = handler(request, *args, **kwargs)
|
||||
if isawaitable(response):
|
||||
response = await response
|
||||
|
||||
except Exception as e:
|
||||
try:
|
||||
response = self.error_handler.response(request, e)
|
||||
if isawaitable(response):
|
||||
response = await response
|
||||
except Exception as e:
|
||||
if self.debug:
|
||||
response = HTTPResponse("Error while handling error: {}\nStack: {}".format(e, format_exc()))
|
||||
else:
|
||||
response = HTTPResponse("An error occured while handling an error")
|
||||
|
||||
respond(response)
|
||||
response_callback(response)
|
||||
|
||||
# -------------------------------------------------------------------- #
|
||||
# Execution
|
||||
# -------------------------------------------------------------------- #
|
||||
|
||||
def run(self, host="127.0.0.1", port=8000, debug=False, on_start=None, on_stop=None):
|
||||
def run(self, host="127.0.0.1", port=8000, debug=False, before_start=None, before_stop=None):
|
||||
"""
|
||||
Runs the HTTP Server and listens until keyboard interrupt or term signal.
|
||||
On termination, drains connections before closing.
|
||||
:param host: Address to host on
|
||||
:param port: Port to host on
|
||||
:param debug: Enables debug output (slows server)
|
||||
:param before_start: Function to be executed after the event loop is created and before the server starts
|
||||
:param before_stop: Function to be executed when a stop signal is received before it is respected
|
||||
:return: Nothing
|
||||
"""
|
||||
self.error_handler.debug=True
|
||||
self.debug = debug
|
||||
|
||||
|
@ -68,13 +111,16 @@ class Sanic:
|
|||
# Serve
|
||||
log.info('Goin\' Fast @ {}:{}'.format(host, port))
|
||||
|
||||
return serve(
|
||||
host=host,
|
||||
port=port,
|
||||
debug=debug,
|
||||
on_start=on_start,
|
||||
on_stop=on_stop,
|
||||
request_handler=self.handle_request,
|
||||
request_timeout=self.config.REQUEST_TIMEOUT,
|
||||
request_max_size=self.config.REQUEST_MAX_SIZE,
|
||||
)
|
||||
try:
|
||||
serve(
|
||||
host=host,
|
||||
port=port,
|
||||
debug=debug,
|
||||
before_start=before_start,
|
||||
before_stop=before_stop,
|
||||
request_handler=self.handle_request,
|
||||
request_timeout=self.config.REQUEST_TIMEOUT,
|
||||
request_max_size=self.config.REQUEST_MAX_SIZE,
|
||||
)
|
||||
except:
|
||||
pass
|
|
@ -78,10 +78,10 @@ class HttpProtocol(asyncio.Protocol):
|
|||
self.url = url
|
||||
|
||||
def on_header(self, name, value):
|
||||
if name == 'Content-Length' and int(value) > self.request_max_size:
|
||||
if name == b'Content-Length' and int(value) > self.request_max_size:
|
||||
return self.bail_out("Request body too large ({}), connection closed".format(value))
|
||||
|
||||
self.headers.append((name, value.decode('utf-8')))
|
||||
self.headers.append((name.decode(), value.decode('utf-8')))
|
||||
|
||||
def on_headers_complete(self):
|
||||
self.request = Request(
|
||||
|
@ -122,15 +122,25 @@ class HttpProtocol(asyncio.Protocol):
|
|||
self.headers = None
|
||||
self._total_request_size = 0
|
||||
|
||||
def serve(host, port, request_handler, on_start=None, on_stop=None, debug=False, request_timeout=60, request_max_size=None):
|
||||
def close_if_idle(self):
|
||||
"""
|
||||
Close the connection if a request is not being sent or received
|
||||
:return: boolean - True if closed, false if staying open
|
||||
"""
|
||||
if not self.parser:
|
||||
self.transport.close()
|
||||
return True
|
||||
return False
|
||||
|
||||
def serve(host, port, request_handler, before_start=None, before_stop=None, debug=False, request_timeout=60, request_max_size=None):
|
||||
# Create Event Loop
|
||||
loop = async_loop.new_event_loop()
|
||||
asyncio.set_event_loop(loop)
|
||||
loop.set_debug(debug)
|
||||
|
||||
# Run the on_start function if provided
|
||||
if on_start:
|
||||
result = on_start(loop)
|
||||
if before_start:
|
||||
result = before_start(loop)
|
||||
if isawaitable(result):
|
||||
loop.run_until_complete(result)
|
||||
|
||||
|
@ -154,8 +164,8 @@ def serve(host, port, request_handler, on_start=None, on_stop=None, debug=False,
|
|||
log.info("Stop requested, draining connections...")
|
||||
|
||||
# Run the on_stop function if provided
|
||||
if on_stop:
|
||||
result = on_stop(loop)
|
||||
if before_stop:
|
||||
result = before_stop(loop)
|
||||
if isawaitable(result):
|
||||
loop.run_until_complete(result)
|
||||
|
||||
|
@ -165,6 +175,9 @@ def serve(host, port, request_handler, on_start=None, on_stop=None, debug=False,
|
|||
|
||||
# Complete all tasks on the loop
|
||||
signal.stopped = True
|
||||
for connection in connections.keys():
|
||||
connection.close_if_idle()
|
||||
|
||||
while connections:
|
||||
loop.run_until_complete(asyncio.sleep(0.1))
|
||||
|
||||
|
|
|
@ -6,8 +6,7 @@ currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentfram
|
|||
sys.path.insert(0,currentdir + '/../../../')
|
||||
|
||||
from sanic import Sanic
|
||||
from sanic.response import json, text
|
||||
from sanic.exceptions import ServerError
|
||||
from sanic.response import json
|
||||
|
||||
app = Sanic("test")
|
||||
|
||||
|
@ -15,71 +14,4 @@ app = Sanic("test")
|
|||
async def test(request):
|
||||
return json({ "test": True })
|
||||
|
||||
@app.route("/sync")
|
||||
def test(request):
|
||||
return json({ "test": True })
|
||||
|
||||
|
||||
|
||||
|
||||
@app.route("/text")
|
||||
def rtext(request):
|
||||
return text("yeehaww")
|
||||
|
||||
@app.route("/exception")
|
||||
def exception(request):
|
||||
raise ServerError("yep")
|
||||
|
||||
@app.route("/exception/async")
|
||||
async def test(request):
|
||||
raise ServerError("asunk")
|
||||
|
||||
@app.route("/post_json")
|
||||
def post_json(request):
|
||||
return json({ "received": True, "message": request.json })
|
||||
|
||||
@app.route("/query_string")
|
||||
def query_string(request):
|
||||
return json({ "parsed": True, "args": request.args, "url": request.url, "query_string": request.query_string })
|
||||
|
||||
import sys
|
||||
app.run(host="0.0.0.0", port=sys.argv[1],)#, on_start=setup)
|
||||
|
||||
|
||||
|
||||
# import asyncio_redis
|
||||
# import asyncpg
|
||||
# async def setup(sanic, loop):
|
||||
# sanic.conn = []
|
||||
# sanic.redis = []
|
||||
# for x in range(10):
|
||||
# sanic.conn.append(await asyncpg.connect(user='postgres', password='zomgdev', database='postgres', host='192.168.99.100'))
|
||||
# for n in range(30):
|
||||
# connection = await asyncio_redis.Connection.create(host='192.168.99.100', port=6379)
|
||||
# sanic.redis.append(connection)
|
||||
|
||||
|
||||
# c=0
|
||||
# @app.route("/postgres")
|
||||
# async def postgres(request):
|
||||
# global c
|
||||
# values = await app.conn[c].fetch('''SELECT * FROM players''')
|
||||
# c += 1
|
||||
# if c == 10:
|
||||
# c = 0
|
||||
# return text("yep")
|
||||
|
||||
# r=0
|
||||
# @app.route("/redis")
|
||||
# async def redis(request):
|
||||
# global r
|
||||
# try:
|
||||
# values = await app.redis[r].get('my_key')
|
||||
# except asyncio_redis.exceptions.ConnectionLostError:
|
||||
# app.redis[r] = await asyncio_redis.Connection.create(host='127.0.0.1', port=6379)
|
||||
# values = await app.redis[r].get('my_key')
|
||||
|
||||
# r += 1
|
||||
# if r == 30:
|
||||
# r = 0
|
||||
# return text(values)
|
||||
app.run(host="0.0.0.0", port=sys.argv[1])
|
83
tests/performance/sanic/varied_server.py
Normal file
83
tests/performance/sanic/varied_server.py
Normal file
|
@ -0,0 +1,83 @@
|
|||
import sys
|
||||
import os
|
||||
import inspect
|
||||
|
||||
currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
|
||||
sys.path.insert(0,currentdir + '/../../../')
|
||||
|
||||
from sanic import Sanic
|
||||
from sanic.response import json, text
|
||||
from sanic.exceptions import ServerError
|
||||
|
||||
app = Sanic("test")
|
||||
|
||||
@app.route("/")
|
||||
async def test(request):
|
||||
return json({ "test": True })
|
||||
|
||||
@app.route("/sync", methods=['GET', 'POST'])
|
||||
def test(request):
|
||||
return json({ "test": True })
|
||||
|
||||
|
||||
@app.route("/text/<name>/<butt:int>")
|
||||
def rtext(request, name, butt):
|
||||
return text("yeehaww {} {}".format(name, butt))
|
||||
|
||||
@app.route("/exception")
|
||||
def exception(request):
|
||||
raise ServerError("yep")
|
||||
|
||||
@app.route("/exception/async")
|
||||
async def test(request):
|
||||
raise ServerError("asunk")
|
||||
|
||||
@app.route("/post_json")
|
||||
def post_json(request):
|
||||
return json({ "received": True, "message": request.json })
|
||||
|
||||
@app.route("/query_string")
|
||||
def query_string(request):
|
||||
return json({ "parsed": True, "args": request.args, "url": request.url, "query_string": request.query_string })
|
||||
|
||||
import sys
|
||||
app.run(host="0.0.0.0", port=sys.argv[1])
|
||||
|
||||
|
||||
|
||||
# import asyncio_redis
|
||||
# import asyncpg
|
||||
# async def setup(sanic, loop):
|
||||
# sanic.conn = []
|
||||
# sanic.redis = []
|
||||
# for x in range(10):
|
||||
# sanic.conn.append(await asyncpg.connect(user='postgres', password='zomgdev', database='postgres', host='192.168.99.100'))
|
||||
# for n in range(30):
|
||||
# connection = await asyncio_redis.Connection.create(host='192.168.99.100', port=6379)
|
||||
# sanic.redis.append(connection)
|
||||
|
||||
|
||||
# c=0
|
||||
# @app.route("/postgres")
|
||||
# async def postgres(request):
|
||||
# global c
|
||||
# values = await app.conn[c].fetch('''SELECT * FROM players''')
|
||||
# c += 1
|
||||
# if c == 10:
|
||||
# c = 0
|
||||
# return text("yep")
|
||||
|
||||
# r=0
|
||||
# @app.route("/redis")
|
||||
# async def redis(request):
|
||||
# global r
|
||||
# try:
|
||||
# values = await app.redis[r].get('my_key')
|
||||
# except asyncio_redis.exceptions.ConnectionLostError:
|
||||
# app.redis[r] = await asyncio_redis.Connection.create(host='127.0.0.1', port=6379)
|
||||
# values = await app.redis[r].get('my_key')
|
||||
|
||||
# r += 1
|
||||
# if r == 30:
|
||||
# r = 0
|
||||
# return text(values)
|
Loading…
Reference in New Issue
Block a user