kopia lustrzana https://github.com/cirospaciari/socketify.py
rodzic
d73ed582d5
commit
d0fa9f32d7
2
SSGI.md
2
SSGI.md
|
@ -15,7 +15,7 @@ class SSGIHttpResponse:
|
||||||
# send chunk of data, can be used to perform with less backpressure than using send
|
# send chunk of data, can be used to perform with less backpressure than using send
|
||||||
# total_size is the sum of all lengths in bytes of all chunks to be sended
|
# total_size is the sum of all lengths in bytes of all chunks to be sended
|
||||||
# connection will end when total_size is met
|
# connection will end when total_size is met
|
||||||
# returns tuple(bool, bool) first bool represents if the chunk is succefully sended, the second if the connection has ended
|
# returns tuple(bool, bool) first bool represents if the chunk is successfully sended, the second if the connection has ended
|
||||||
def send_chunk(self, chunk: Union[str, bytes, bytearray, memoryview], total_size: int = False) -> Awaitable:
|
def send_chunk(self, chunk: Union[str, bytes, bytearray, memoryview], total_size: int = False) -> Awaitable:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
|
@ -64,7 +64,7 @@ if __name__ == "__main__":
|
||||||
|
|
||||||
# run_app() # run app on the main process too :)
|
# run_app() # run app on the main process too :)
|
||||||
|
|
||||||
# # sigint everything to gracefull shutdown
|
# # sigint everything to graceful shutdown
|
||||||
# import signal
|
# import signal
|
||||||
# for pid in pid_list:
|
# for pid in pid_list:
|
||||||
# os.kill(pid, signal.SIGINT)
|
# os.kill(pid, signal.SIGINT)
|
||||||
|
|
|
@ -30,7 +30,7 @@ Options:
|
||||||
--ws-close-on-backpressure-limit BOOLEAN Close connections that hits maximum backpressure [default: False]
|
--ws-close-on-backpressure-limit BOOLEAN Close connections that hits maximum backpressure [default: False]
|
||||||
--lifespan [auto|on|off] Lifespan implementation. [default: auto]
|
--lifespan [auto|on|off] Lifespan implementation. [default: auto]
|
||||||
--interface [auto|asgi|asgi3|wsgi|ssgi|socketify] Select ASGI (same as ASGI3), ASGI3, WSGI or SSGI as the application interface. [default: auto]
|
--interface [auto|asgi|asgi3|wsgi|ssgi|socketify] Select ASGI (same as ASGI3), ASGI3, WSGI or SSGI as the application interface. [default: auto]
|
||||||
--disable-listen-log BOOLEAN Disable log when start listenning [default: False]
|
--disable-listen-log BOOLEAN Disable log when start listening [default: False]
|
||||||
--version or -v Display the socketify.py version and exit.
|
--version or -v Display the socketify.py version and exit.
|
||||||
--ssl-keyfile TEXT SSL key file
|
--ssl-keyfile TEXT SSL key file
|
||||||
--ssl-certfile TEXT SSL certificate file
|
--ssl-certfile TEXT SSL certificate file
|
||||||
|
|
|
@ -27,7 +27,7 @@ for _ in range(1, multiprocessing.cpu_count()):
|
||||||
|
|
||||||
run_app() # run app on the main process too :)
|
run_app() # run app on the main process too :)
|
||||||
|
|
||||||
# sigint everything to gracefull shutdown
|
# sigint everything to graceful shutdown
|
||||||
import signal
|
import signal
|
||||||
for pid in pid_list:
|
for pid in pid_list:
|
||||||
os.kill(pid, signal.SIGINT)
|
os.kill(pid, signal.SIGINT)
|
|
@ -6,7 +6,7 @@ from socketify import App
|
||||||
def middleware(*functions):
|
def middleware(*functions):
|
||||||
def middleware_route(res, req):
|
def middleware_route(res, req):
|
||||||
data = None
|
data = None
|
||||||
# cicle to all middlewares
|
# circle to all middlewares
|
||||||
for function in functions:
|
for function in functions:
|
||||||
# call middlewares
|
# call middlewares
|
||||||
data = function(res, req, data)
|
data = function(res, req, data)
|
||||||
|
|
|
@ -688,7 +688,7 @@ class _ASGI:
|
||||||
asgi_app = self
|
asgi_app = self
|
||||||
self.is_starting = True
|
self.is_starting = True
|
||||||
self.is_stopped = False
|
self.is_stopped = False
|
||||||
self.status = 0 # 0 starting, 1 ok, 2 error, 3 stoping, 4 stopped, 5 stopped with error, 6 no lifespan
|
self.status = 0 # 0 starting, 1 ok, 2 error, 3 stopping, 4 stopped, 5 stopped with error, 6 no lifespan
|
||||||
self.status_message = ""
|
self.status_message = ""
|
||||||
self.stop_future = self.server.loop.create_future()
|
self.stop_future = self.server.loop.create_future()
|
||||||
|
|
||||||
|
@ -850,7 +850,7 @@ class ASGI:
|
||||||
|
|
||||||
if block:
|
if block:
|
||||||
run_task() # run app on the main process too :)
|
run_task() # run app on the main process too :)
|
||||||
# sigint everything to gracefull shutdown
|
# sigint everything to graceful shutdown
|
||||||
import signal
|
import signal
|
||||||
for pid in pid_list:
|
for pid in pid_list:
|
||||||
os.kill(pid, signal.SIGINT)
|
os.kill(pid, signal.SIGINT)
|
||||||
|
|
|
@ -28,7 +28,7 @@ Options:
|
||||||
--ws-close-on-backpressure-limit BOOLEAN Close connections that hits maximum backpressure [default: False]
|
--ws-close-on-backpressure-limit BOOLEAN Close connections that hits maximum backpressure [default: False]
|
||||||
--lifespan [auto|on|off] Lifespan implementation. [default: auto]
|
--lifespan [auto|on|off] Lifespan implementation. [default: auto]
|
||||||
--interface [auto|asgi|asgi3|wsgi|ssgi|socketify] Select ASGI (same as ASGI3), ASGI3, WSGI or SSGI as the application interface. [default: auto]
|
--interface [auto|asgi|asgi3|wsgi|ssgi|socketify] Select ASGI (same as ASGI3), ASGI3, WSGI or SSGI as the application interface. [default: auto]
|
||||||
--disable-listen-log BOOLEAN Disable log when start listenning [default: False]
|
--disable-listen-log BOOLEAN Disable log when start listening [default: False]
|
||||||
--version or -v Display the socketify.py version and exit.
|
--version or -v Display the socketify.py version and exit.
|
||||||
--ssl-keyfile TEXT SSL key file
|
--ssl-keyfile TEXT SSL key file
|
||||||
--ssl-certfile TEXT SSL certificate file
|
--ssl-certfile TEXT SSL certificate file
|
||||||
|
@ -188,10 +188,10 @@ def execute(args):
|
||||||
|
|
||||||
elif interface == "ssgi":
|
elif interface == "ssgi":
|
||||||
# if not is_ssgi(module):
|
# if not is_ssgi(module):
|
||||||
# return print("SSGI is in development yet but is comming soon")
|
# return print("SSGI is in development yet but is coming soon")
|
||||||
# from . import SSGI as Interface
|
# from . import SSGI as Interface
|
||||||
# interface = "ssgi"
|
# interface = "ssgi"
|
||||||
return print("SSGI is in development yet but is comming soon")
|
return print("SSGI is in development yet but is coming soon")
|
||||||
elif interface != "socketify":
|
elif interface != "socketify":
|
||||||
return print(f"{interface} interface is not supported yet")
|
return print(f"{interface} interface is not supported yet")
|
||||||
|
|
||||||
|
@ -322,7 +322,7 @@ def execute(args):
|
||||||
|
|
||||||
run_app() # run app on the main process too :)
|
run_app() # run app on the main process too :)
|
||||||
|
|
||||||
# sigint everything to gracefull shutdown
|
# sigint everything to graceful shutdown
|
||||||
import signal
|
import signal
|
||||||
for pid in pid_list:
|
for pid in pid_list:
|
||||||
os.kill(pid, signal.SIGINT)
|
os.kill(pid, signal.SIGINT)
|
||||||
|
|
|
@ -70,7 +70,7 @@ async def sendfile(res, req, filename):
|
||||||
|
|
||||||
def send_headers(res):
|
def send_headers(res):
|
||||||
res.write_status(status)
|
res.write_status(status)
|
||||||
# tells the broswer the last modified date
|
# tells the browser the last modified date
|
||||||
res.write_header(b"Last-Modified", last_modified)
|
res.write_header(b"Last-Modified", last_modified)
|
||||||
|
|
||||||
# tells the browser that we support range
|
# tells the browser that we support range
|
||||||
|
@ -147,7 +147,7 @@ def middleware(*functions):
|
||||||
|
|
||||||
# we use Optional data=None at the end so you can use and middleware inside a middleware
|
# we use Optional data=None at the end so you can use and middleware inside a middleware
|
||||||
def optimized_middleware_route(res, req, data=None):
|
def optimized_middleware_route(res, req, data=None):
|
||||||
# cicle to all middlewares
|
# circle to all middlewares
|
||||||
for function in syncs:
|
for function in syncs:
|
||||||
# call middlewares
|
# call middlewares
|
||||||
data = function(res, req, data)
|
data = function(res, req, data)
|
||||||
|
@ -156,7 +156,7 @@ def middleware(*functions):
|
||||||
return
|
return
|
||||||
|
|
||||||
async def wrapper(res, req, data):
|
async def wrapper(res, req, data):
|
||||||
# cicle to all middlewares
|
# circle to all middlewares
|
||||||
for function in asyncs:
|
for function in asyncs:
|
||||||
# detect if is coroutine or not
|
# detect if is coroutine or not
|
||||||
if inspect.iscoroutinefunction(function):
|
if inspect.iscoroutinefunction(function):
|
||||||
|
@ -182,7 +182,7 @@ def middleware(*functions):
|
||||||
def sync_middleware(*functions):
|
def sync_middleware(*functions):
|
||||||
# we use Optional data=None at the end so you can use and middleware inside a middleware
|
# we use Optional data=None at the end so you can use and middleware inside a middleware
|
||||||
def middleware_route(res, req, data=None):
|
def middleware_route(res, req, data=None):
|
||||||
# cicle to all middlewares
|
# circle to all middlewares
|
||||||
for function in functions:
|
for function in functions:
|
||||||
# call middlewares
|
# call middlewares
|
||||||
data = function(res, req, data)
|
data = function(res, req, data)
|
||||||
|
@ -198,7 +198,7 @@ def async_middleware(*functions):
|
||||||
# we use Optional data=None at the end so you can use and middleware inside a middleware
|
# we use Optional data=None at the end so you can use and middleware inside a middleware
|
||||||
async def middleware_route(res, req, data=None):
|
async def middleware_route(res, req, data=None):
|
||||||
some_async_as_run = False
|
some_async_as_run = False
|
||||||
# cicle to all middlewares
|
# circle to all middlewares
|
||||||
for function in functions:
|
for function in functions:
|
||||||
# detect if is coroutine or not
|
# detect if is coroutine or not
|
||||||
if inspect.iscoroutinefunction(function):
|
if inspect.iscoroutinefunction(function):
|
||||||
|
|
|
@ -101,7 +101,7 @@ class Loop:
|
||||||
self.loop.call_later(self.idle_relaxation_time, self._keep_alive)
|
self.loop.call_later(self.idle_relaxation_time, self._keep_alive)
|
||||||
else:
|
else:
|
||||||
self.uv_loop.run_nowait()
|
self.uv_loop.run_nowait()
|
||||||
# be more agressive when needed
|
# be more aggressive when needed
|
||||||
self.loop.call_soon(self._keep_alive)
|
self.loop.call_soon(self._keep_alive)
|
||||||
|
|
||||||
def create_task(self, *args, **kwargs):
|
def create_task(self, *args, **kwargs):
|
||||||
|
@ -194,7 +194,7 @@ class Loop:
|
||||||
return self.uv_loop.get_native_loop()
|
return self.uv_loop.get_native_loop()
|
||||||
|
|
||||||
def _run_async_pypy(self, task, response=None):
|
def _run_async_pypy(self, task, response=None):
|
||||||
# this garanties error 500 in case of uncaught exceptions, and can trigger the custom error handler
|
# this guarantees error 500 in case of uncaught exceptions, and can trigger the custom error handler
|
||||||
# using an coroutine wrapper generates less overhead than using add_done_callback
|
# using an coroutine wrapper generates less overhead than using add_done_callback
|
||||||
# this is an custom task/future with less overhead and that calls the first step
|
# this is an custom task/future with less overhead and that calls the first step
|
||||||
future = self._task_factory(
|
future = self._task_factory(
|
||||||
|
@ -203,7 +203,7 @@ class Loop:
|
||||||
return None # this future maybe already done and reused not safe to await
|
return None # this future maybe already done and reused not safe to await
|
||||||
|
|
||||||
def _run_async_cpython(self, task, response=None):
|
def _run_async_cpython(self, task, response=None):
|
||||||
# this garanties error 500 in case of uncaught exceptions, and can trigger the custom error handler
|
# this guarantees error 500 in case of uncaught exceptions, and can trigger the custom error handler
|
||||||
# using an coroutine wrapper generates less overhead than using add_done_callback
|
# using an coroutine wrapper generates less overhead than using add_done_callback
|
||||||
# this is an custom task/future with less overhead and that calls the first step
|
# this is an custom task/future with less overhead and that calls the first step
|
||||||
future = create_task(self.loop, task_wrapper(self.exception_handler, self.loop, response, task))
|
future = create_task(self.loop, task_wrapper(self.exception_handler, self.loop, response, task))
|
||||||
|
|
|
@ -25,7 +25,7 @@ class SSGIHttpResponse:
|
||||||
# send chunk of data, can be used to perform with less backpressure than using send
|
# send chunk of data, can be used to perform with less backpressure than using send
|
||||||
# total_size is the sum of all lengths in bytes of all chunks to be sended
|
# total_size is the sum of all lengths in bytes of all chunks to be sended
|
||||||
# connection will end when total_size is met
|
# connection will end when total_size is met
|
||||||
# returns tuple(bool, bool) first bool represents if the chunk is succefully sended, the second if the connection has ended
|
# returns tuple(bool, bool) first bool represents if the chunk is successfully sended, the second if the connection has ended
|
||||||
def send_chunk(self, chunk: Union[bytes, bytearray, memoryview], total_size: int) -> Awaitable:
|
def send_chunk(self, chunk: Union[bytes, bytearray, memoryview], total_size: int) -> Awaitable:
|
||||||
return self.res.send_chunk(chunk, total_size)
|
return self.res.send_chunk(chunk, total_size)
|
||||||
|
|
||||||
|
|
|
@ -444,7 +444,7 @@ def wsgi(ssl, response, info, user_data):
|
||||||
app._data_refs[_id] = data_retry
|
app._data_refs[_id] = data_retry
|
||||||
lib.uws_res_on_aborted(ssl, response, wsgi_on_data_ref_abort_handler, data_retry._ptr)
|
lib.uws_res_on_aborted(ssl, response, wsgi_on_data_ref_abort_handler, data_retry._ptr)
|
||||||
lib.uws_res_on_writable(ssl, response, wsgi_on_writable_handler, data_retry._ptr)
|
lib.uws_res_on_writable(ssl, response, wsgi_on_writable_handler, data_retry._ptr)
|
||||||
elif result is None or (not bool(result.has_responded) and bool(result.ok)): # not reachs Content-Length
|
elif result is None or (not bool(result.has_responded) and bool(result.ok)): # not reaches Content-Length
|
||||||
logging.error(AssertionError("Content-Length do not match sended content"))
|
logging.error(AssertionError("Content-Length do not match sended content"))
|
||||||
lib.uws_res_close(
|
lib.uws_res_close(
|
||||||
ssl,
|
ssl,
|
||||||
|
@ -495,7 +495,7 @@ def wsgi(ssl, response, info, user_data):
|
||||||
content_length,
|
content_length,
|
||||||
0,
|
0,
|
||||||
)
|
)
|
||||||
# this should be very very rare fot HTTP
|
# this should be very very rare for HTTP
|
||||||
if not bool(result.ok):
|
if not bool(result.ok):
|
||||||
failed_chunks = []
|
failed_chunks = []
|
||||||
# just mark the chunks
|
# just mark the chunks
|
||||||
|
@ -522,7 +522,7 @@ def wsgi(ssl, response, info, user_data):
|
||||||
app._data_refs[_id] = data_retry
|
app._data_refs[_id] = data_retry
|
||||||
lib.uws_res_on_aborted(ssl, response, wsgi_on_data_ref_abort_handler, data_retry._ptr)
|
lib.uws_res_on_aborted(ssl, response, wsgi_on_data_ref_abort_handler, data_retry._ptr)
|
||||||
lib.uws_res_on_writable(ssl, response, wsgi_on_writable_handler, data_retry._ptr)
|
lib.uws_res_on_writable(ssl, response, wsgi_on_writable_handler, data_retry._ptr)
|
||||||
elif result is None or (not bool(result.has_responded) and bool(result.ok)): # not reachs Content-Length
|
elif result is None or (not bool(result.has_responded) and bool(result.ok)): # not reaches Content-Length
|
||||||
logging.error(AssertionError("Content-Length do not match sended content"))
|
logging.error(AssertionError("Content-Length do not match sended content"))
|
||||||
lib.uws_res_close(
|
lib.uws_res_close(
|
||||||
ssl,
|
ssl,
|
||||||
|
@ -768,7 +768,7 @@ class WSGI:
|
||||||
|
|
||||||
if block:
|
if block:
|
||||||
run_task() # run app on the main process too :)
|
run_task() # run app on the main process too :)
|
||||||
# sigint everything to gracefull shutdown
|
# sigint everything to graceful shutdown
|
||||||
import signal
|
import signal
|
||||||
for pid in pid_list:
|
for pid in pid_list:
|
||||||
os.kill(pid, signal.SIGINT)
|
os.kill(pid, signal.SIGINT)
|
||||||
|
|
Ładowanie…
Reference in New Issue