kopia lustrzana https://github.com/cirospaciari/socketify.py
fixed UVLoop, and added better strategy to Loop, added post support, get_data(), get_json(), get_text(), get_cookie(), set_cookie(), pending x-www-form-urlencoded and form-data (maybe only with another package), added more options for keys in response, added fallback to None if decode fails in request, added on_writable and on_data events, pending try_end and stream examples, added upload and post examples
rodzic
98f855e46c
commit
093b0f5c93
|
@ -34,12 +34,17 @@ class Loop:
|
|||
|
||||
asyncio.set_event_loop(self.loop)
|
||||
self.started = False
|
||||
self.last_defer = False
|
||||
# self.loop_thread = None
|
||||
|
||||
def create_future(self):
|
||||
return self.loop.create_future()
|
||||
|
||||
def start(self):
|
||||
self.started = True
|
||||
#start relaxed until first task
|
||||
self.timer = self.uv_loop.create_timer(0, 100, lambda loop: loop.run_once_asyncio(), self)
|
||||
|
||||
|
||||
def run(self):
|
||||
self.uv_loop.run()
|
||||
|
||||
|
@ -50,6 +55,13 @@ class Loop:
|
|||
#run only one step
|
||||
self.loop.call_soon(self.loop.stop)
|
||||
self.loop.run_forever()
|
||||
if self.started:
|
||||
pending = len(asyncio.all_tasks(self.loop))
|
||||
if pending < 1: #relaxed if has no tasks
|
||||
self.timer.set_repeat(100)
|
||||
else: #urge when needs
|
||||
self.timer.set_repeat(1)
|
||||
|
||||
def stop(self):
|
||||
if(self.started):
|
||||
self.timer.stop()
|
||||
|
@ -59,6 +71,7 @@ class Loop:
|
|||
if self.loop.is_running():
|
||||
self.loop.stop()
|
||||
|
||||
self.last_defer = None
|
||||
# Find all running tasks in main thread:
|
||||
pending = asyncio.all_tasks(self.loop)
|
||||
# Run loop until tasks done
|
||||
|
@ -74,6 +87,9 @@ class Loop:
|
|||
|
||||
#with threads
|
||||
future.add_done_callback(lambda f: future_handler(f, self.loop, self.exception_handler, response))
|
||||
|
||||
#force asyncio run once to enable req in async functions before first await
|
||||
self.run_once_asyncio()
|
||||
return future
|
||||
|
||||
|
||||
|
|
|
@ -89,7 +89,7 @@ void socketify_destroy_loop(socketify_loop* loop){
|
|||
free(loop);
|
||||
}
|
||||
|
||||
socketify_timer* socketify_create_timer(socketify_loop* loop, int64_t timeout, int64_t repeat, socketify_timer_handler handler, void* user_data){
|
||||
socketify_timer* socketify_create_timer(socketify_loop* loop, uint64_t timeout, uint64_t repeat, socketify_timer_handler handler, void* user_data){
|
||||
|
||||
uv_timer_t* uv_timer = malloc(sizeof(uv_timer_t));
|
||||
// uv_timer_init(loop->uv_loop, uv_timer);
|
||||
|
@ -109,6 +109,12 @@ socketify_timer* socketify_create_timer(socketify_loop* loop, int64_t timeout, i
|
|||
return timer;
|
||||
}
|
||||
|
||||
void socketify_timer_set_repeat(socketify_timer* timer, uint64_t repeat){
|
||||
uv_timer_set_repeat( timer->uv_timer_ptr, repeat);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//stops and destroy timer info
|
||||
void socketify_timer_destroy(socketify_timer* timer){
|
||||
uv_timer_stop(timer->uv_timer_ptr);
|
||||
|
|
|
@ -26,6 +26,8 @@ typedef struct{
|
|||
void* user_data;
|
||||
} socketify_timer;
|
||||
|
||||
|
||||
|
||||
socketify_loop * socketify_create_loop();
|
||||
bool socketify_constructor_failed(socketify_loop* loop);
|
||||
bool socketify_on_prepare(socketify_loop* loop, socketify_prepare_handler handler, void* user_data);
|
||||
|
@ -36,6 +38,8 @@ void* socketify_get_native_loop(socketify_loop* loop);
|
|||
int socketify_loop_run(socketify_loop* loop, socketify_run_mode mode);
|
||||
void socketify_loop_stop(socketify_loop* loop);
|
||||
|
||||
socketify_timer* socketify_create_timer(socketify_loop* loop, int64_t timeout, int64_t repeat, socketify_timer_handler handler, void* user_data);
|
||||
socketify_timer* socketify_create_timer(socketify_loop* loop, uint64_t timeout, uint64_t repeat, socketify_timer_handler handler, void* user_data);
|
||||
void socketify_timer_destroy(socketify_timer* timer);
|
||||
void socketify_timer_set_repeat(socketify_timer* timer, uint64_t repeat);
|
||||
|
||||
#endif
|
|
@ -8,6 +8,7 @@ ffi.cdef("""
|
|||
|
||||
typedef void (*socketify_prepare_handler)(void* user_data);
|
||||
typedef void (*socketify_timer_handler)(void* user_data);
|
||||
typedef void (*socketify_async_handler)(void* user_data);
|
||||
|
||||
typedef enum {
|
||||
SOCKETIFY_RUN_DEFAULT = 0,
|
||||
|
@ -28,6 +29,12 @@ typedef struct{
|
|||
void* user_data;
|
||||
} socketify_timer;
|
||||
|
||||
typedef struct{
|
||||
void* uv_async_ptr;
|
||||
socketify_async_handler handler;
|
||||
void* user_data;
|
||||
} socketify_async;
|
||||
|
||||
socketify_loop * socketify_create_loop();
|
||||
bool socketify_constructor_failed(socketify_loop* loop);
|
||||
bool socketify_on_prepare(socketify_loop* loop, socketify_prepare_handler handler, void* user_data);
|
||||
|
@ -38,9 +45,10 @@ void* socketify_get_native_loop(socketify_loop* loop);
|
|||
int socketify_loop_run(socketify_loop* loop, socketify_run_mode mode);
|
||||
void socketify_loop_stop(socketify_loop* loop);
|
||||
|
||||
socketify_timer* socketify_create_timer(socketify_loop* loop, int64_t timeout, int64_t repeat, socketify_timer_handler handler, void* user_data);
|
||||
socketify_timer* socketify_create_timer(socketify_loop* loop, uint64_t timeout, uint64_t repeat, socketify_timer_handler handler, void* user_data);
|
||||
void socketify_timer_destroy(socketify_timer* timer);
|
||||
|
||||
bool socketify_async_call(socketify_loop* loop, socketify_async_handler handler, void* user_data);
|
||||
void socketify_timer_set_repeat(socketify_timer* timer, uint64_t repeat);
|
||||
|
||||
""")
|
||||
library_path = os.path.join(os.path.dirname(__file__), "libsocketify.so")
|
||||
|
@ -56,17 +64,20 @@ def socketify_generic_handler(data):
|
|||
class UVTimer:
|
||||
def __init__(self, loop, timeout, repeat, handler, user_data):
|
||||
self._handler_data = ffi.new_handle((handler, user_data))
|
||||
self._ptr = lib.socketify_create_timer(loop, ffi.cast("int64_t", timeout), ffi.cast("int64_t", repeat), socketify_generic_handler, self._handler_data)
|
||||
self._ptr = lib.socketify_create_timer(loop, ffi.cast("uint64_t", timeout), ffi.cast("uint64_t", repeat), socketify_generic_handler, self._handler_data)
|
||||
|
||||
def stop(self):
|
||||
lib.socketify_timer_destroy(self._ptr)
|
||||
self._handler_data = None
|
||||
self._ptr = ffi.NULL
|
||||
|
||||
def set_repeat(self, repeat):
|
||||
lib.socketify_timer_set_repeat(self._ptr, ffi.cast("uint64_t", repeat))
|
||||
|
||||
def __del__(self):
|
||||
if self._ptr != ffi.NULL:
|
||||
lib.socketify_timer_destroy(self._ptr)
|
||||
self.self._handler_data = None
|
||||
self._handler_data = None
|
||||
|
||||
|
||||
class UVLoop:
|
||||
|
@ -90,7 +101,7 @@ class UVLoop:
|
|||
|
||||
def __del__(self):
|
||||
lib.socketify_destroy_loop(self._loop)
|
||||
self.self._handler_data = None
|
||||
self._handler_data = None
|
||||
|
||||
def run(self):
|
||||
return lib.socketify_loop_run(self._loop, lib.SOCKETIFY_RUN_DEFAULT)
|
||||
|
|
|
@ -5,7 +5,8 @@ from .status_codes import status_codes
|
|||
import json
|
||||
import inspect
|
||||
import signal
|
||||
|
||||
from http import cookies
|
||||
from datetime import datetime
|
||||
ffi = cffi.FFI()
|
||||
ffi.cdef("""
|
||||
|
||||
|
@ -220,7 +221,7 @@ def uws_generic_method_handler(res, req, user_data):
|
|||
try:
|
||||
if inspect.iscoroutinefunction(handler):
|
||||
response.grab_aborted_handler()
|
||||
app.run_async(handler(response, request), response)
|
||||
response.run_async(handler(response, request))
|
||||
else:
|
||||
handler(response, request)
|
||||
except Exception as err:
|
||||
|
@ -236,7 +237,7 @@ def uws_generic_ssl_method_handler(res, req, user_data):
|
|||
try:
|
||||
if inspect.iscoroutinefunction(handler):
|
||||
response.grab_aborted_handler()
|
||||
app.run_async(handler(response, request), response)
|
||||
response.run_async(handler(response, request))
|
||||
else:
|
||||
handler(response, request)
|
||||
except Exception as err:
|
||||
|
@ -261,46 +262,112 @@ def uws_generic_aborted_handler(response, user_data):
|
|||
res = ffi.from_handle(user_data)
|
||||
res.trigger_aborted()
|
||||
|
||||
@ffi.callback("void(uws_res_t *, const char *, size_t, bool, void*)")
|
||||
def uws_generic_on_data_handler(res, chunk, chunk_length, is_end, user_data):
|
||||
if not user_data == ffi.NULL:
|
||||
res = ffi.from_handle(user_data)
|
||||
if chunk == ffi.NULL:
|
||||
data = None
|
||||
else:
|
||||
data = ffi.unpack(chunk, chunk_length)
|
||||
|
||||
res.trigger_data_handler(data, bool(is_end))
|
||||
|
||||
@ffi.callback("bool(uws_res_t *, uintmax_t, void*)")
|
||||
def uws_generic_on_writable_handler(res, offset, user_data):
|
||||
if not user_data == ffi.NULL:
|
||||
res = ffi.from_handle(user_data)
|
||||
return res.trigger_writable_handler(offset)
|
||||
return False
|
||||
|
||||
class AppRequest:
|
||||
def __init__(self, request):
|
||||
self.req = request
|
||||
self.read_jar = None
|
||||
self.jar_parsed = False
|
||||
|
||||
def get_cookie(self, name):
|
||||
if self.read_jar == None:
|
||||
if self.jar_parsed:
|
||||
return None
|
||||
raw_cookies = self.get_header("cookie")
|
||||
if raw_cookies:
|
||||
self.jar_parsed = True
|
||||
self.read_jar = cookies.SimpleCookie(raw_cookies)
|
||||
else:
|
||||
self.jar_parsed = True
|
||||
return None
|
||||
try:
|
||||
return self.read_jar[name].value
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
def get_url(self):
|
||||
buffer = ffi.new("char**")
|
||||
length = lib.uws_req_get_url(self.req, buffer)
|
||||
buffer_address = ffi.addressof(buffer, 0)[0]
|
||||
if buffer_address == ffi.NULL:
|
||||
return None
|
||||
return ffi.unpack(buffer_address, length).decode("utf-8")
|
||||
try:
|
||||
return ffi.unpack(buffer_address, length).decode("utf-8")
|
||||
except Exception: #invalid utf-8
|
||||
return None
|
||||
def get_method(self):
|
||||
buffer = ffi.new("char**")
|
||||
length = lib.uws_req_get_method(self.req, buffer)
|
||||
buffer_address = ffi.addressof(buffer, 0)[0]
|
||||
if buffer_address == ffi.NULL:
|
||||
return None
|
||||
return ffi.unpack(buffer_address, length).decode("utf-8")
|
||||
|
||||
try:
|
||||
return ffi.unpack(buffer_address, length).decode("utf-8")
|
||||
except Exception: #invalid utf-8
|
||||
return None
|
||||
def get_header(self, lower_case_header):
|
||||
if isinstance(lower_case_header, str):
|
||||
data = lower_case_header.encode("utf-8")
|
||||
elif isinstance(lower_case_header, bytes):
|
||||
data = lower_case_header
|
||||
else:
|
||||
data = json.dumps(lower_case_header).encode("utf-8")
|
||||
|
||||
buffer = ffi.new("char**")
|
||||
data = lower_case_header.encode("utf-8")
|
||||
length = lib.uws_req_get_header(self.req, data, len(data), buffer)
|
||||
buffer_address = ffi.addressof(buffer, 0)[0]
|
||||
if buffer_address == ffi.NULL:
|
||||
return None
|
||||
return ffi.unpack(buffer_address, length).decode("utf-8")
|
||||
try:
|
||||
return ffi.unpack(buffer_address, length).decode("utf-8")
|
||||
except Exception: #invalid utf-8
|
||||
return None
|
||||
def get_query(self, key):
|
||||
buffer = ffi.new("char**")
|
||||
data = key.encode("utf-8")
|
||||
length = lib.uws_req_get_query(self.req, data, len(data), buffer)
|
||||
|
||||
if isinstance(key, str):
|
||||
key_data = key.encode("utf-8")
|
||||
elif isinstance(key, bytes):
|
||||
key_data = key
|
||||
else:
|
||||
key_data = json.dumps(key).encode("utf-8")
|
||||
|
||||
length = lib.uws_req_get_query(self.req, key_data, len(key_data), buffer)
|
||||
buffer_address = ffi.addressof(buffer, 0)[0]
|
||||
if buffer_address == ffi.NULL:
|
||||
return None
|
||||
return ffi.unpack(buffer_address, length).decode("utf-8")
|
||||
try:
|
||||
return ffi.unpack(buffer_address, length).decode("utf-8")
|
||||
except Exception: #invalid utf-8
|
||||
return None
|
||||
def get_parameter(self, index):
|
||||
buffer = ffi.new("char**")
|
||||
length = lib.uws_req_get_parameter(self.req, ffi.cast("unsigned short", index), buffer)
|
||||
buffer_address = ffi.addressof(buffer, 0)[0]
|
||||
if buffer_address == ffi.NULL:
|
||||
return None
|
||||
return ffi.unpack(buffer_address, length).decode("utf-8")
|
||||
try:
|
||||
return ffi.unpack(buffer_address, length).decode("utf-8")
|
||||
except Exception: #invalid utf-8
|
||||
return None
|
||||
def set_yield(self, has_yield):
|
||||
lib.uws_req_set_field(self.req, 1 if has_yield else 0)
|
||||
def get_yield(self):
|
||||
|
@ -316,23 +383,105 @@ class AppResponse:
|
|||
self.aborted = False
|
||||
self._ptr = ffi.NULL
|
||||
self.loop = loop
|
||||
self._aborted_handler = None
|
||||
self._writable_handler = None
|
||||
self._data_handler = None
|
||||
self._ptr = ffi.new_handle(self)
|
||||
self._grabed_abort_handler_once = False
|
||||
self._write_jar = None
|
||||
|
||||
def set_cookie(self, name, value, options={}):
|
||||
if self._write_jar == None:
|
||||
self._write_jar = cookies.SimpleCookie()
|
||||
self._write_jar[name] = value
|
||||
if isinstance(options, dict):
|
||||
for key in options:
|
||||
if key == "expires" and isinstance(options[key], datetime):
|
||||
self._write_jar[name][key] = options[key].strftime("%a, %d %b %Y %H:%M:%S GMT")
|
||||
else:
|
||||
self._write_jar[name][key] = options[key]
|
||||
|
||||
def trigger_aborted(self):
|
||||
self.aborted = True
|
||||
self.res = ffi.NULL
|
||||
self._ptr = ffi.NULL
|
||||
if hasattr(self, "_aborted_handler") and hasattr(self._aborted_handler, '__call__'):
|
||||
self._aborted_handler()
|
||||
try:
|
||||
if inspect.iscoroutinefunction(self._aborted_handler):
|
||||
self.run_async(self._aborted_handler(self))
|
||||
else:
|
||||
self._aborted_handler(self)
|
||||
except Exception as err:
|
||||
print("Error on abort handler %s" % str(err))
|
||||
return self
|
||||
|
||||
def trigger_data_handler(self, data, is_end):
|
||||
if self.aborted:
|
||||
return self
|
||||
if hasattr(self, "_data_handler") and hasattr(self._data_handler, '__call__'):
|
||||
try:
|
||||
if inspect.iscoroutinefunction(self._data_handler):
|
||||
self.run_async(self._data_handler(self, data, is_end))
|
||||
else:
|
||||
self._data_handler(self, data, is_end)
|
||||
except Exception as err:
|
||||
print("Error on data handler %s" % str(err))
|
||||
|
||||
return self
|
||||
|
||||
def trigger_writable_handler(self, offset):
|
||||
if self.aborted:
|
||||
return False
|
||||
if hasattr(self, "_writable_handler") and hasattr(self._writable_handler, '__call__'):
|
||||
try:
|
||||
if inspect.iscoroutinefunction(self._writable_handler):
|
||||
raise RuntimeError("AppResponse.on_writable must be synchronous")
|
||||
return self._writable_handler(self, offset)
|
||||
except Exception as err:
|
||||
print("Error on writable handler %s" % str(err))
|
||||
return False
|
||||
return False
|
||||
|
||||
def run_async(self, task):
|
||||
self.grab_aborted_handler()
|
||||
return self.loop.run_async(task, self)
|
||||
|
||||
|
||||
async def get_text(self, encoding='utf-8'):
|
||||
data = await self.get_data()
|
||||
try:
|
||||
return b''.join(data).decode(encoding)
|
||||
except Exception:
|
||||
return None #invalid encoding
|
||||
|
||||
async def get_json(self):
|
||||
data = await self.get_data()
|
||||
try:
|
||||
return json.loads(b''.join(data).decode('utf-8'))
|
||||
except Exception:
|
||||
return None #invalid json
|
||||
|
||||
|
||||
def get_data(self):
|
||||
future = self.loop.create_future()
|
||||
data = []
|
||||
def is_aborted(res):
|
||||
future.set_result(data)
|
||||
|
||||
def get_chunks(res, chunk, is_end):
|
||||
data.append(chunk)
|
||||
if is_end:
|
||||
future.set_result(data)
|
||||
|
||||
self.on_aborted(is_aborted)
|
||||
self.on_data(get_chunks)
|
||||
return future
|
||||
|
||||
|
||||
def grab_aborted_handler(self):
|
||||
#only needed if is async
|
||||
if self._ptr == ffi.NULL and not self.aborted:
|
||||
self._ptr = ffi.new_handle(self)
|
||||
if not self.aborted and not self._grabed_abort_handler_once:
|
||||
self._grabed_abort_handler_once = True
|
||||
lib.uws_res_on_aborted(self.SSL, self.res, uws_generic_aborted_handler, self._ptr)
|
||||
|
||||
def redirect(self, location, status_code=302):
|
||||
|
@ -342,6 +491,9 @@ class AppResponse:
|
|||
|
||||
def end(self, message, end_connection=False):
|
||||
if not self.aborted:
|
||||
if self._write_jar != None:
|
||||
self.write_header("Set-Cookie", self._write_jar.output(header=""))
|
||||
|
||||
if isinstance(message, str):
|
||||
data = message.encode("utf-8")
|
||||
elif isinstance(message, bytes):
|
||||
|
@ -350,7 +502,7 @@ class AppResponse:
|
|||
self.end_without_body(end_connection)
|
||||
return self
|
||||
else:
|
||||
self.write_header("Content-Type", "application/json")
|
||||
self.write_header(b'Content-Type', b'application/json')
|
||||
data = json.dumps(message).encode("utf-8")
|
||||
lib.uws_res_end(self.SSL, self.res, data, len(data), 1 if end_connection else 0)
|
||||
return self
|
||||
|
@ -370,11 +522,17 @@ class AppResponse:
|
|||
lib.uws_res_write_continue(self.SSL, self.res)
|
||||
return self
|
||||
|
||||
# /* Try and end the response. Returns [true, true] on success.
|
||||
# * Starts a timeout in some cases. Returns [ok, hasResponded] */
|
||||
# std::pair<bool, bool> tryEnd(std::string_view data, uintmax_t totalSize = 0) {
|
||||
# return {internalEnd(data, totalSize, true), hasResponded()};
|
||||
# }
|
||||
|
||||
def write_status(self, status_or_status_text):
|
||||
if not self.aborted:
|
||||
if isinstance(status_or_status_text, int):
|
||||
try:
|
||||
data = status_codes[status_or_status_text].encode("utf-8")
|
||||
data = status_codes[status_or_status_text]
|
||||
except: #invalid status
|
||||
raise RuntimeError("\"%d\" Is not an valid Status Code" % status_or_status_text)
|
||||
elif isinstance(status_text, str):
|
||||
|
@ -389,7 +547,13 @@ class AppResponse:
|
|||
|
||||
def write_header(self, key, value):
|
||||
if not self.aborted:
|
||||
key_data = key.encode("utf-8")
|
||||
if isinstance(key, str):
|
||||
key_data = key.encode("utf-8")
|
||||
elif isinstance(key, bytes):
|
||||
key_data = key
|
||||
else:
|
||||
key_data = json.dumps(key).encode("utf-8")
|
||||
|
||||
if isinstance(value, int):
|
||||
lib.uws_res_write_header_int(self.SSL, self.res, key_data, len(key_data), ffi.cast("uint64_t", value))
|
||||
elif isinstance(value, str):
|
||||
|
@ -403,6 +567,8 @@ class AppResponse:
|
|||
|
||||
def end_without_body(self, end_connection=False):
|
||||
if not self.aborted:
|
||||
if self._write_jar != None:
|
||||
self.write_header("Set-Cookie", self._write_jar.output(header=""))
|
||||
lib.uws_res_end_without_body(self.SSL, self.res, 1 if end_connection else 0)
|
||||
return self
|
||||
|
||||
|
@ -439,6 +605,22 @@ class AppResponse:
|
|||
self._aborted_handler = handler
|
||||
return self
|
||||
|
||||
def on_data(self, handler):
|
||||
if not self.aborted:
|
||||
if hasattr(handler, '__call__'):
|
||||
self.grab_aborted_handler()
|
||||
self._data_handler = handler
|
||||
lib.uws_res_on_data(self.SSL, self.res, uws_generic_on_data_handler, self._ptr)
|
||||
return self
|
||||
|
||||
def on_writable(self, handler):
|
||||
if not self.aborted:
|
||||
if hasattr(handler, '__call__'):
|
||||
self.grab_aborted_handler()
|
||||
self._writable_handler = handler
|
||||
lib.uws_res_on_writable(self.SSL, self.res, uws_generic_on_writable_handler, self._ptr)
|
||||
return self
|
||||
|
||||
def __del__(self):
|
||||
self.res = ffi.NULL
|
||||
self._ptr = ffi.NULL
|
||||
|
@ -546,9 +728,6 @@ class App:
|
|||
lib.uws_app_listen_with_config(self.SSL, self.app, options, uws_generic_listen_handler, self._ptr)
|
||||
|
||||
return self
|
||||
|
||||
def get_loop():
|
||||
return self.loop.loop
|
||||
|
||||
def run_async(self, task, response=None):
|
||||
return self.loop.run_async(task, response)
|
||||
|
@ -557,7 +736,6 @@ class App:
|
|||
signal.signal(signal.SIGINT, lambda sig, frame: self.close())
|
||||
self.loop.start()
|
||||
self.loop.run()
|
||||
# lib.uws_app_run(self.SSL, self.app)
|
||||
return self
|
||||
|
||||
def close(self):
|
||||
|
|
|
@ -1,65 +1,65 @@
|
|||
status_codes = {
|
||||
100 : "100 Continue",
|
||||
101 : "101 Switching Protocols",
|
||||
102 : "102 Processing",
|
||||
103 : "103 Early Hints",
|
||||
200 : "200 OK",
|
||||
201 : "201 Created",
|
||||
202 : "202 Accepted",
|
||||
203 : "203 Non-Authoritative Information",
|
||||
204 : "204 No Content",
|
||||
205 : "205 Reset Content",
|
||||
206 : "206 Partial Content",
|
||||
207 : "207 Multi-Status",
|
||||
208 : "208 Already Reported",
|
||||
226 : "226 IM Used (HTTP Delta encoding)",
|
||||
300 : "300 Multiple Choices",
|
||||
301 : "301 Moved Permanently",
|
||||
302 : "302 Found",
|
||||
303 : "303 See Other",
|
||||
304 : "304 Not Modified",
|
||||
305 : "305 Use Proxy Deprecated",
|
||||
306 : "306 unused",
|
||||
307 : "307 Temporary Redirect",
|
||||
308 : "308 Permanent Redirect",
|
||||
400 : "400 Bad Request",
|
||||
401 : "401 Unauthorized",
|
||||
402 : "402 Payment Required Experimental",
|
||||
403 : "403 Forbidden",
|
||||
404 : "404 Not Found",
|
||||
405 : "405 Method Not Allowed",
|
||||
406 : "406 Not Acceptable",
|
||||
407 : "407 Proxy Authentication Required",
|
||||
408 : "408 Request Timeout",
|
||||
409 : "409 Conflict",
|
||||
410 : "410 Gone",
|
||||
411 : "411 Length Required",
|
||||
412 : "412 Precondition Failed",
|
||||
413 : "413 Payload Too Large",
|
||||
414 : "414 URI Too Long",
|
||||
415 : "415 Unsupported Media Type",
|
||||
416 : "416 Range Not Satisfiable",
|
||||
417 : "417 Expectation Failed",
|
||||
418 : "418 I'm a teapot",
|
||||
421 : "421 Misdirected Request",
|
||||
422 : "422 Unprocessable Entity",
|
||||
423 : "423 Locked",
|
||||
424 : "424 Failed Dependency",
|
||||
425 : "425 Too Early Experimental",
|
||||
426 : "426 Upgrade Required",
|
||||
428 : "428 Precondition Required",
|
||||
429 : "429 Too Many Requests",
|
||||
431 : "431 Request Header Fields Too Large",
|
||||
451 : "451 Unavailable For Legal Reasons",
|
||||
500 : "500 Internal Server Error",
|
||||
501 : "501 Not Implemented",
|
||||
502 : "502 Bad Gateway",
|
||||
503 : "503 Service Unavailable",
|
||||
504 : "504 Gateway Timeout",
|
||||
505 : "505 HTTP Version Not Supported",
|
||||
506 : "506 Variant Also Negotiates",
|
||||
507 : "507 Insufficient Storage",
|
||||
508 : "508 Loop Detected",
|
||||
510 : "510 Not Extended",
|
||||
511 : "511 Network Authentication Required"
|
||||
100 : b'100 Continue',
|
||||
101 : b'101 Switching Protocols',
|
||||
102 : b'102 Processing',
|
||||
103 : b'103 Early Hints',
|
||||
200 : b'200 OK',
|
||||
201 : b'201 Created',
|
||||
202 : b'202 Accepted',
|
||||
203 : b'203 Non-Authoritative Information',
|
||||
204 : b'204 No Content',
|
||||
205 : b'205 Reset Content',
|
||||
206 : b'206 Partial Content',
|
||||
207 : b'207 Multi-Status',
|
||||
208 : b'208 Already Reported',
|
||||
226 : b'226 IM Used (HTTP Delta encoding)',
|
||||
300 : b'300 Multiple Choices',
|
||||
301 : b'301 Moved Permanently',
|
||||
302 : b'302 Found',
|
||||
303 : b'303 See Other',
|
||||
304 : b'304 Not Modified',
|
||||
305 : b'305 Use Proxy Deprecated',
|
||||
306 : b'306 unused',
|
||||
307 : b'307 Temporary Redirect',
|
||||
308 : b'308 Permanent Redirect',
|
||||
400 : b'400 Bad Request',
|
||||
401 : b'401 Unauthorized',
|
||||
402 : b'402 Payment Required Experimental',
|
||||
403 : b'403 Forbidden',
|
||||
404 : b'404 Not Found',
|
||||
405 : b'405 Method Not Allowed',
|
||||
406 : b'406 Not Acceptable',
|
||||
407 : b'407 Proxy Authentication Required',
|
||||
408 : b'408 Request Timeout',
|
||||
409 : b'409 Conflict',
|
||||
410 : b'410 Gone',
|
||||
411 : b'411 Length Required',
|
||||
412 : b'412 Precondition Failed',
|
||||
413 : b'413 Payload Too Large',
|
||||
414 : b'414 URI Too Long',
|
||||
415 : b'415 Unsupported Media Type',
|
||||
416 : b'416 Range Not Satisfiable',
|
||||
417 : b'417 Expectation Failed',
|
||||
418 : b'418 I\'m a teapot',
|
||||
421 : b'421 Misdirected Request',
|
||||
422 : b'422 Unprocessable Entity',
|
||||
423 : b'423 Locked',
|
||||
424 : b'424 Failed Dependency',
|
||||
425 : b'425 Too Early Experimental',
|
||||
426 : b'426 Upgrade Required',
|
||||
428 : b'428 Precondition Required',
|
||||
429 : b'429 Too Many Requests',
|
||||
431 : b'431 Request Header Fields Too Large',
|
||||
451 : b'451 Unavailable For Legal Reasons',
|
||||
500 : b'500 Internal Server Error',
|
||||
501 : b'501 Not Implemented',
|
||||
502 : b'502 Bad Gateway',
|
||||
503 : b'503 Service Unavailable',
|
||||
504 : b'504 Gateway Timeout',
|
||||
505 : b'505 HTTP Version Not Supported',
|
||||
506 : b'506 Variant Also Negotiates',
|
||||
507 : b'507 Insufficient Storage',
|
||||
508 : b'508 Loop Detected',
|
||||
510 : b'510 Not Extended',
|
||||
511 : b'511 Network Authentication Required'
|
||||
}
|
|
@ -8,8 +8,8 @@ from helpers.twolevel_cache import TwoLevelCache
|
|||
redis_pool = redis.ConnectionPool(host='localhost', port=6379, db=0)
|
||||
redis_conection = redis.Redis(connection_pool=redis_pool)
|
||||
# 2 LEVEL CACHE (Redis to share amoung workers, Memory to be much faster)
|
||||
# cache in memory is 5s, cache in redis is 10s duration
|
||||
cache = TwoLevelCache(redis_conection, 5, 10)
|
||||
# cache in memory is 30s, cache in redis is 60s duration
|
||||
cache = TwoLevelCache(redis_conection, 30, 60)
|
||||
|
||||
###
|
||||
# Model
|
||||
|
@ -19,17 +19,17 @@ async def get_pokemon(number):
|
|||
async with aiohttp.ClientSession() as session:
|
||||
async with session.get(f'https://pokeapi.co/api/v2/pokemon/{number}') as response:
|
||||
pokemon = await response.text()
|
||||
#cache only works with strings/bytes/buffer
|
||||
#cache only works with strings/bytes
|
||||
#we will not change nothing here so no needs to parse json
|
||||
return pokemon
|
||||
return pokemon.encode("utf-8")
|
||||
|
||||
async def get_original_pokemons():
|
||||
async with aiohttp.ClientSession() as session:
|
||||
async with session.get(f'https://pokeapi.co/api/v2/pokemon?limit=151') as response:
|
||||
#cache only works with strings/bytes/buffer
|
||||
#cache only works with strings/bytes
|
||||
#we will not change nothing here so no needs to parse json
|
||||
pokemons = await response.text()
|
||||
return pokemons
|
||||
return pokemons.encode("utf-8")
|
||||
|
||||
|
||||
###
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
|
||||
from socketify import App, AppOptions, AppListenOptions
|
||||
import asyncio
|
||||
|
||||
from datetime import datetime
|
||||
from datetime import timedelta
|
||||
app = App()
|
||||
|
||||
def home(res, req):
|
||||
|
@ -10,6 +11,27 @@ def home(res, req):
|
|||
def anything(res, req):
|
||||
res.end("Any route with method: %s" % req.get_method())
|
||||
|
||||
def cookies(res, req):
|
||||
#cookies are writen after end
|
||||
res.set_cookie("spaciari", "1234567890",{
|
||||
# expires
|
||||
# path
|
||||
# comment
|
||||
# domain
|
||||
# max-age
|
||||
# secure
|
||||
# version
|
||||
# httponly
|
||||
# samesite
|
||||
"path": "/",
|
||||
# "domain": "*.test.com",
|
||||
"httponly": True,
|
||||
"samesite": "None",
|
||||
"secure": True,
|
||||
"expires": datetime.utcnow() + timedelta(minutes=30)
|
||||
})
|
||||
res.end("Your session_id cookie is: %s" % req.get_cookie('session_id'));
|
||||
|
||||
def useragent(res,req):
|
||||
res.end("Your user agent is: %s" % req.get_header('user-agent'));
|
||||
|
||||
|
@ -77,9 +99,11 @@ app.get("/delayed", delayed)
|
|||
app.get("/json", json)
|
||||
app.get("/sleepy", sleepy_json)
|
||||
app.get("/custom_header", custom_header)
|
||||
app.get("/cookies", cookies)
|
||||
app.get("/send_in_parts", send_in_parts)
|
||||
app.get("/redirect", redirect)
|
||||
app.get("/redirected", redirected)
|
||||
# too see about app.post go to ./upload_or_post.py :D
|
||||
# Wildcard at last always :)
|
||||
app.any("/*", not_found)
|
||||
|
||||
|
|
Ładowanie…
Reference in New Issue