use black as code formatter

pull/39/head
Ciro 2022-11-16 16:28:46 -03:00
rodzic aa11d8bd58
commit 021dda7d2a
53 zmienionych plików z 1824 dodań i 1085 usunięć

Wyświetl plik

@ -2,6 +2,7 @@ from wsgiref.simple_server import make_server
import falcon import falcon
class Home: class Home:
def on_get(self, req, resp): def on_get(self, req, resp):
resp.status = falcon.HTTP_200 # This is the default status resp.status = falcon.HTTP_200 # This is the default status
@ -12,11 +13,11 @@ class Home:
app = falcon.App() app = falcon.App()
home = Home() home = Home()
app.add_route('/', home) app.add_route("/", home)
if __name__ == '__main__': if __name__ == "__main__":
with make_server('', 8000, app) as httpd: with make_server("", 8000, app) as httpd:
print('Serving on port 8000...') print("Serving on port 8000...")
# Serve until process is killed # Serve until process is killed
httpd.serve_forever() httpd.serve_forever()

Wyświetl plik

@ -2,10 +2,12 @@ from robyn import Robyn
app = Robyn(__file__) app = Robyn(__file__)
@app.get("/") @app.get("/")
async def h(request): async def h(request):
return "Hello, world!" return "Hello, world!"
app.start(port=8000) app.start(port=8000)
# python3 ./robyn_plaintext.py --processes 4 --log-level CRITICAL # python3 ./robyn_plaintext.py --processes 4 --log-level CRITICAL

Wyświetl plik

@ -3,21 +3,28 @@ import os
import multiprocessing import multiprocessing
def run_app(): def run_app():
app = App() app = App()
app.get("/", lambda res, req: res.end("Hello, World!")) app.get("/", lambda res, req: res.end("Hello, World!"))
app.listen(8000, lambda config: print("PID %d Listening on port http://localhost:%d now\n" % (os.getpid(), config.port))) app.listen(
8000,
lambda config: print(
"PID %d Listening on port http://localhost:%d now\n"
% (os.getpid(), config.port)
),
)
app.run() app.run()
def create_fork(): def create_fork():
n = os.fork() n = os.fork()
# n greater than 0 means parent process # n greater than 0 means parent process
if not n > 0: if not n > 0:
run_app() run_app()
# fork limiting the cpu count - 1 # fork limiting the cpu count - 1
# for i in range(1, multiprocessing.cpu_count()): for i in range(1, multiprocessing.cpu_count()):
# create_fork() create_fork()
run_app() # run app on the main process too :) run_app() # run app on the main process too :)

Wyświetl plik

@ -1,17 +1,22 @@
async def app(scope, receive, send): async def app(scope, receive, send):
assert scope['type'] == 'http' assert scope["type"] == "http"
await send({ await send(
'type': 'http.response.start', {
'status': 200, "type": "http.response.start",
'headers': [ "status": 200,
[b'content-type', b'text/plain'], "headers": [
[b"content-type", b"text/plain"],
], ],
}) }
await send({ )
'type': 'http.response.body', await send(
'body': b'Hello, world!', {
}) "type": "http.response.body",
"body": b"Hello, world!",
}
)
# python3 -m gunicorn uvicorn_guvicorn_plaintext:app -w 1 -k uvicorn.workers.UvicornWorker # python3 -m gunicorn uvicorn_guvicorn_plaintext:app -w 1 -k uvicorn.workers.UvicornWorker
# pypy3 -m gunicorn uvicorn_guvicorn_plaintext:app -w 1 -k uvicorn.workers.UvicornWorker # pypy3 -m gunicorn uvicorn_guvicorn_plaintext:app -w 1 -k uvicorn.workers.UvicornWorker

Wyświetl plik

@ -5,6 +5,7 @@ import asyncio
clients = set([]) clients = set([])
remaining_clients = 16 remaining_clients = 16
async def broadcast(message): async def broadcast(message):
# some clients got disconnected if we tried to to all async :/ # some clients got disconnected if we tried to to all async :/
# tasks = [ws.send_text(message) for ws in client] # tasks = [ws.send_text(message) for ws in client]
@ -14,7 +15,6 @@ async def broadcast(message):
class SomeResource: class SomeResource:
async def on_get(self, req): async def on_get(self, req):
pass pass
@ -36,10 +36,7 @@ class SomeResource:
remaining_clients = remaining_clients + 1 remaining_clients = remaining_clients + 1
app = falcon.asgi.App() app = falcon.asgi.App()
app.add_route('/', SomeResource()) app.add_route("/", SomeResource())
# python3 -m gunicorn falcon_server:app -b 127.0.0.1:4001 -w 1 -k uvicorn.workers.UvicornWorker # python3 -m gunicorn falcon_server:app -b 127.0.0.1:4001 -w 1 -k uvicorn.workers.UvicornWorker
# pypy3 -m gunicorn falcon_server:app -b 127.0.0.1:4001 -w 1 -k uvicorn.workers.UvicornH11Worker # pypy3 -m gunicorn falcon_server:app -b 127.0.0.1:4001 -w 1 -k uvicorn.workers.UvicornH11Worker

Wyświetl plik

@ -2,6 +2,7 @@ from socketify import App, AppOptions, OpCode, CompressOptions
remaining_clients = 16 remaining_clients = 16
def ws_open(ws): def ws_open(ws):
ws.subscribe("room") ws.subscribe("room")
global remaining_clients global remaining_clients
@ -20,19 +21,27 @@ def ws_message(ws, message, opcode):
ws.publish("room", message, opcode) ws.publish("room", message, opcode)
ws.send(message, opcode) ws.send(message, opcode)
def ws_close(ws, close, message): def ws_close(ws, close, message):
global remaining_clients global remaining_clients
remaining_clients = remaining_clients + 1 remaining_clients = remaining_clients + 1
app = App() app = App()
app.ws("/*", { app.ws(
'compression': CompressOptions.DISABLED, "/*",
'max_payload_length': 16 * 1024 * 1024, {
'idle_timeout': 60, "compression": CompressOptions.DISABLED,
'open': ws_open, "max_payload_length": 16 * 1024 * 1024,
'message': ws_message, "idle_timeout": 60,
'close': ws_close "open": ws_open,
}) "message": ws_message,
"close": ws_close,
},
)
app.any("/", lambda res, req: res.end("Nothing to see here!'")) app.any("/", lambda res, req: res.end("Nothing to see here!'"))
app.listen(4001, lambda config: print("Listening on port http://localhost:%d now\n" % (config.port))) app.listen(
4001,
lambda config: print("Listening on port http://localhost:%d now\n" % (config.port)),
)
app.run() app.run()

Wyświetl plik

@ -3,10 +3,12 @@ import asyncio
app = App() app = App()
async def delayed_hello(delay, res): async def delayed_hello(delay, res):
await asyncio.sleep(delay) # do something async await asyncio.sleep(delay) # do something async
res.cork_end("Hello with delay!") res.cork_end("Hello with delay!")
def home(res, req): def home(res, req):
# request object only lives during the life time of this call # request object only lives during the life time of this call
# get parameters, query, headers anything you need here # get parameters, query, headers anything you need here
@ -16,6 +18,7 @@ def home(res, req):
# abort handler is grabed here, so responses only will be send if res.aborted == False # abort handler is grabed here, so responses only will be send if res.aborted == False
res.run_async(delayed_hello(delay, res)) res.run_async(delayed_hello(delay, res))
async def json(res, req): async def json(res, req):
# request object only lives during the life time of this call # request object only lives during the life time of this call
# get parameters, query, headers anything you need here before first await :) # get parameters, query, headers anything you need here before first await :)
@ -25,13 +28,20 @@ async def json(res, req):
res.cork_end({"message": "I'm delayed!", "user-agent": user_agent}) res.cork_end({"message": "I'm delayed!", "user-agent": user_agent})
def not_found(res, req): def not_found(res, req):
res.write_status(404).end("Not Found") res.write_status(404).end("Not Found")
app.get("/", home) app.get("/", home)
app.get("/json", json) app.get("/json", json)
app.any("/*", not_found) app.any("/*", not_found)
app.listen(3000, lambda config: print("Listening on port http://localhost:%s now\n" % str(config.port))) app.listen(
3000,
lambda config: print(
"Listening on port http://localhost:%s now\n" % str(config.port)
),
)
app.run() app.run()

Wyświetl plik

@ -2,5 +2,7 @@ from socketify import App
app = App() app = App()
app.get("/", lambda res, req: res.end("Hello World socketify from Python!")) app.get("/", lambda res, req: res.end("Hello World socketify from Python!"))
app.listen(0, lambda config: print("Listening on port http://localhost:%d now\n" % config.port)) app.listen(
0, lambda config: print("Listening on port http://localhost:%d now\n" % config.port)
)
app.run() app.run()

Wyświetl plik

@ -7,33 +7,42 @@ backpressure = 1024
messages = 0 messages = 0
message_number = 0 message_number = 0
def ws_open(ws): def ws_open(ws):
print('A WebSocket got connected!') print("A WebSocket got connected!")
# We begin our example by sending until we have backpressure # We begin our example by sending until we have backpressure
global message_number global message_number
global messages global messages
while (ws.get_buffered_amount() < backpressure): while ws.get_buffered_amount() < backpressure:
ws.send("This is a message, let's call it %i" % message_number) ws.send("This is a message, let's call it %i" % message_number)
message_number = message_number + 1 message_number = message_number + 1
messages = messages + 1 messages = messages + 1
def ws_drain(ws): def ws_drain(ws):
# Continue sending when we have drained (some) # Continue sending when we have drained (some)
global message_number global message_number
global messages global messages
while (ws.get_buffered_amount() < backpressure): while ws.get_buffered_amount() < backpressure:
ws.send("This is a message, let's call it %i" % message_number) ws.send("This is a message, let's call it %i" % message_number)
message_number = message_number + 1 message_number = message_number + 1
messages = messages + 1 messages = messages + 1
app = App() app = App()
app.ws("/*", { app.ws(
'compression': CompressOptions.DISABLED, "/*",
'max_payload_length': 16 * 1024 * 1024, {
'idle_timeout': 60, "compression": CompressOptions.DISABLED,
'open': ws_open, "max_payload_length": 16 * 1024 * 1024,
'drain': ws_drain "idle_timeout": 60,
}) "open": ws_open,
"drain": ws_drain,
},
)
app.any("/", lambda res, req: res.end("Nothing to see here!")) app.any("/", lambda res, req: res.end("Nothing to see here!"))
app.listen(3000, lambda config: print("Listening on port http://localhost:%d now\n" % (config.port))) app.listen(
3000,
lambda config: print("Listening on port http://localhost:%d now\n" % (config.port)),
)
app.run() app.run()

Wyświetl plik

@ -1,26 +1,35 @@
from socketify import App, AppOptions, OpCode, CompressOptions from socketify import App, AppOptions, OpCode, CompressOptions
def ws_open(ws): def ws_open(ws):
print('A WebSocket got connected!') print("A WebSocket got connected!")
# Let this client listen to topic "broadcast" # Let this client listen to topic "broadcast"
ws.subscribe('broadcast') ws.subscribe("broadcast")
def ws_message(ws, message, opcode): def ws_message(ws, message, opcode):
# Ok is false if backpressure was built up, wait for drain # Ok is false if backpressure was built up, wait for drain
ok = ws.send(message, opcode) ok = ws.send(message, opcode)
# Broadcast this message # Broadcast this message
ws.publish('broadcast', message, opcode) ws.publish("broadcast", message, opcode)
app = App() app = App()
app.ws("/*", { app.ws(
'compression': CompressOptions.SHARED_COMPRESSOR, "/*",
'max_payload_length': 16 * 1024 * 1024, {
'idle_timeout': 12, "compression": CompressOptions.SHARED_COMPRESSOR,
'open': ws_open, "max_payload_length": 16 * 1024 * 1024,
'message': ws_message, "idle_timeout": 12,
"open": ws_open,
"message": ws_message,
# The library guarantees proper unsubscription at close # The library guarantees proper unsubscription at close
'close': lambda ws, code, message: print('WebSocket closed') "close": lambda ws, code, message: print("WebSocket closed"),
}) },
)
app.any("/", lambda res, req: res.end("Nothing to see here!")) app.any("/", lambda res, req: res.end("Nothing to see here!"))
app.listen(3000, lambda config: print("Listening on port http://localhost:%d now\n" % (config.port))) app.listen(
3000,
lambda config: print("Listening on port http://localhost:%d now\n" % (config.port)),
)
app.run() app.run()

Wyświetl plik

@ -2,5 +2,8 @@ from socketify import App
app = App() app = App()
app.get("/", lambda res, req: res.end("Hello World socketify from Python!")) app.get("/", lambda res, req: res.end("Hello World socketify from Python!"))
app.listen(3000, lambda config: print("Listening on port http://localhost:%d now\n" % config.port)) app.listen(
3000,
lambda config: print("Listening on port http://localhost:%d now\n" % config.port),
)
app.run() app.run()

Wyświetl plik

@ -2,5 +2,8 @@ from socketify import App
app = App() app = App()
app.get("/", lambda res, req: res.end("Hello World socketify from Python!")) app.get("/", lambda res, req: res.end("Hello World socketify from Python!"))
app.listen(3000, lambda config: print("Listening on port http://localhost:%d now\n" % config.port)) app.listen(
3000,
lambda config: print("Listening on port http://localhost:%d now\n" % config.port),
)
app.run() app.run()

Wyświetl plik

@ -2,5 +2,8 @@ from socketify import App
app = App() app = App()
app.get("/", lambda res, req: res.end("Hello World socketify from Python!")) app.get("/", lambda res, req: res.end("Hello World socketify from Python!"))
app.listen(3000, lambda config: print("Listening on port http://localhost:%d now\n" % config.port)) app.listen(
3000,
lambda config: print("Listening on port http://localhost:%d now\n" % config.port),
)
app.run() app.run()

Wyświetl plik

@ -2,5 +2,8 @@ from socketify import App
app = App() app = App()
app.get("/", lambda res, req: res.end("Hello World socketify from Python!")) app.get("/", lambda res, req: res.end("Hello World socketify from Python!"))
app.listen(3000, lambda config: print("Listening on port http://localhost:%d now\n" % config.port)) app.listen(
3000,
lambda config: print("Listening on port http://localhost:%d now\n" % config.port),
)
app.run() app.run()

Wyświetl plik

@ -3,13 +3,16 @@ import asyncio
app = App() app = App()
def xablau(res, req): def xablau(res, req):
raise RuntimeError("Xablau!") raise RuntimeError("Xablau!")
async def async_xablau(res, req): async def async_xablau(res, req):
await asyncio.sleep(1) await asyncio.sleep(1)
raise RuntimeError("Async Xablau!") raise RuntimeError("Async Xablau!")
# this can be async no problems # this can be async no problems
def on_error(error, res, req): def on_error(error, res, req):
# here you can log properly the error and do a pretty response to your clients # here you can log properly the error and do a pretty response to your clients
@ -20,10 +23,16 @@ def on_error(error, res, req):
res.write_status(500) res.write_status(500)
res.end("Sorry we did something wrong") res.end("Sorry we did something wrong")
app.get("/", xablau) app.get("/", xablau)
app.get("/async", async_xablau) app.get("/async", async_xablau)
app.set_error_handler(on_error) app.set_error_handler(on_error)
app.listen(3000, lambda config: print("Listening on port http://localhost:%s now\n" % str(config.port))) app.listen(
3000,
lambda config: print(
"Listening on port http://localhost:%s now\n" % str(config.port)
),
)
app.run() app.run()

Wyświetl plik

@ -7,6 +7,7 @@ from os import path
mimetypes.init() mimetypes.init()
async def home(res, req): async def home(res, req):
# this is just an implementation example see static_files.py example for use of sendfile and app.static usage # this is just an implementation example see static_files.py example for use of sendfile and app.static usage
# there is an static_aiofile.py helper and static.aiofiles helper using async implementation of this # there is an static_aiofile.py helper and static.aiofiles helper using async implementation of this
@ -14,14 +15,14 @@ async def home(res, req):
filename = "./public/media/flower.webm" filename = "./public/media/flower.webm"
# read headers before the first await # read headers before the first await
if_modified_since = req.get_header('if-modified-since') if_modified_since = req.get_header("if-modified-since")
range_header = req.get_header('range') range_header = req.get_header("range")
bytes_range = None bytes_range = None
start = 0 start = 0
end = -1 end = -1
# parse range header # parse range header
if range_header: if range_header:
bytes_range = range_header.replace("bytes=", '').split('-') bytes_range = range_header.replace("bytes=", "").split("-")
start = int(bytes_range[0]) start = int(bytes_range[0])
if bytes_range[1]: if bytes_range[1]:
end = int(bytes_range[1]) end = int(bytes_range[1])
@ -29,26 +30,28 @@ async def home(res, req):
exists = path.exists(filename) exists = path.exists(filename)
# not found # not found
if not exists: if not exists:
return res.write_status(404).end(b'Not Found') return res.write_status(404).end(b"Not Found")
# get size and last modified date # get size and last modified date
stats = os.stat(filename) stats = os.stat(filename)
total_size = stats.st_size total_size = stats.st_size
size = total_size size = total_size
last_modified = time.strftime('%a, %d %b %Y %H:%M:%S GMT', time.gmtime(stats.st_mtime)) last_modified = time.strftime(
"%a, %d %b %Y %H:%M:%S GMT", time.gmtime(stats.st_mtime)
)
# check if modified since is provided # check if modified since is provided
if if_modified_since == last_modified: if if_modified_since == last_modified:
return res.write_status(304).end_without_body() return res.write_status(304).end_without_body()
# tells the broswer the last modified date # tells the broswer the last modified date
res.write_header(b'Last-Modified', last_modified) res.write_header(b"Last-Modified", last_modified)
# add content type # add content type
(content_type, encoding) = mimetypes.guess_type(filename, strict=True) (content_type, encoding) = mimetypes.guess_type(filename, strict=True)
if content_type and encoding: if content_type and encoding:
res.write_header(b'Content-Type', '%s; %s' % (content_type, encoding)) res.write_header(b"Content-Type", "%s; %s" % (content_type, encoding))
elif content_type: elif content_type:
res.write_header(b'Content-Type', content_type) res.write_header(b"Content-Type", content_type)
with open(filename, "rb") as fd: with open(filename, "rb") as fd:
# check range and support it # check range and support it
@ -65,8 +68,10 @@ async def home(res, req):
res.write_status(200) res.write_status(200)
# tells the browser that we support range # tells the browser that we support range
res.write_header(b'Accept-Ranges', b'bytes') res.write_header(b"Accept-Ranges", b"bytes")
res.write_header(b'Content-Range', 'bytes %d-%d/%d' % (start, end, total_size)) res.write_header(
b"Content-Range", "bytes %d-%d/%d" % (start, end, total_size)
)
pending_size = size pending_size = size
# keep sending until abort or done # keep sending until abort or done
while not res.aborted: while not res.aborted:
@ -82,7 +87,11 @@ async def home(res, req):
except Exception as error: except Exception as error:
res.write_status(500).end("Internal Error") res.write_status(500).end("Internal Error")
app = App() app = App()
app.get("/", home) app.get("/", home)
app.listen(3000, lambda config: print("Listening on port http://localhost:%d now\n" % config.port)) app.listen(
3000,
lambda config: print("Listening on port http://localhost:%d now\n" % config.port),
)
app.run() app.run()

Wyświetl plik

@ -2,18 +2,27 @@ from socketify import App
import os import os
import multiprocessing import multiprocessing
def run_app(): def run_app():
app = App() app = App()
app.get("/", lambda res, req: res.end("Hello, World!")) app.get("/", lambda res, req: res.end("Hello, World!"))
app.listen(3000, lambda config: print("PID %d Listening on port http://localhost:%d now\n" % (os.getpid(), config.port))) app.listen(
3000,
lambda config: print(
"PID %d Listening on port http://localhost:%d now\n"
% (os.getpid(), config.port)
),
)
app.run() app.run()
def create_fork(): def create_fork():
n = os.fork() n = os.fork()
# n greater than 0 means parent process # n greater than 0 means parent process
if not n > 0: if not n > 0:
run_app() run_app()
# fork limiting the cpu count - 1 # fork limiting the cpu count - 1
for i in range(1, multiprocessing.cpu_count()): for i in range(1, multiprocessing.cpu_count()):
create_fork() create_fork()

Wyświetl plik

@ -2,14 +2,21 @@ from socketify import App, AppOptions, AppListenOptions
app = App() app = App()
def shutdown(res, req): def shutdown(res, req):
res.end("Good bye!") res.end("Good bye!")
app.close() app.close()
app.get("/", lambda res, req: res.end("Hello!")) app.get("/", lambda res, req: res.end("Hello!"))
app.get("/shutdown", shutdown) app.get("/shutdown", shutdown)
app.listen(3000, lambda config: print("Listening on port http://localhost:%s now\n" % str(config.port))) app.listen(
3000,
lambda config: print(
"Listening on port http://localhost:%s now\n" % str(config.port)
),
)
app.run() app.run()
print("App Closed!") print("App Closed!")

Wyświetl plik

@ -1,4 +1,3 @@
import dataclasses import dataclasses
import strawberry import strawberry
import strawberry.utils.graphiql import strawberry.utils.graphiql
@ -7,10 +6,12 @@ from socketify import App
from typing import List, Optional from typing import List, Optional
from helpers.graphiql import graphiql_from from helpers.graphiql import graphiql_from
@strawberry.type @strawberry.type
class User: class User:
name: str name: str
@strawberry.type @strawberry.type
class Query: class Query:
@strawberry.field @strawberry.field
@ -24,5 +25,8 @@ app.get("/", lambda res, req: res.end(strawberry.utils.graphiql.get_graphiql_htm
app.post("/", graphiql_from(Query)) app.post("/", graphiql_from(Query))
# you can also pass an Mutation as second parameter # you can also pass an Mutation as second parameter
# app.post("/", graphiql_from(Query, Mutation)) # app.post("/", graphiql_from(Query, Mutation))
app.listen(3000, lambda config: print("Listening on port http://localhost:%d now\n" % config.port)) app.listen(
3000,
lambda config: print("Listening on port http://localhost:%d now\n" % config.port),
)
app.run() app.run()

Wyświetl plik

@ -1,4 +1,3 @@
import dataclasses import dataclasses
import strawberry import strawberry
import strawberry.utils.graphiql import strawberry.utils.graphiql
@ -6,10 +5,12 @@ import strawberry.utils.graphiql
from socketify import App from socketify import App
from typing import List, Optional from typing import List, Optional
@strawberry.type @strawberry.type
class User: class User:
name: str name: str
@strawberry.type @strawberry.type
class Query: class Query:
@strawberry.field @strawberry.field
@ -40,14 +41,20 @@ async def graphiql_post(res, req):
operation_name, operation_name,
) )
res.cork_end({ res.cork_end(
{
"data": (data.data), "data": (data.data),
**({"errors": data.errors} if data.errors else {}), **({"errors": data.errors} if data.errors else {}),
**({"extensions": data.extensions} if data.extensions else {}) **({"extensions": data.extensions} if data.extensions else {}),
}) }
)
app = App() app = App()
app.get("/", lambda res, req: res.end(strawberry.utils.graphiql.get_graphiql_html())) app.get("/", lambda res, req: res.end(strawberry.utils.graphiql.get_graphiql_html()))
app.post("/", graphiql_post) app.post("/", graphiql_post)
app.listen(3000, lambda config: print("Listening on port http://localhost:%d now\n" % config.port)) app.listen(
3000,
lambda config: print("Listening on port http://localhost:%d now\n" % config.port),
)
app.run() app.run()

Wyświetl plik

@ -2,5 +2,8 @@ from socketify import App
app = App() app = App()
app.get("/", lambda res, req: res.end("Hello World!")) app.get("/", lambda res, req: res.end("Hello World!"))
app.listen(3000, lambda config: print("Listening on port http://localhost:%d now\n" % config.port)) app.listen(
3000,
lambda config: print("Listening on port http://localhost:%d now\n" % config.port),
)
app.run() app.run()

Wyświetl plik

@ -1,6 +1,7 @@
import strawberry import strawberry
import strawberry.utils.graphiql import strawberry.utils.graphiql
def graphiql_from(Query, Mutation=None): def graphiql_from(Query, Mutation=None):
if Mutation: if Mutation:
schema = strawberry.Schema(query=Query, mutation=Mutation) schema = strawberry.Schema(query=Query, mutation=Mutation)
@ -12,7 +13,7 @@ def graphiql_from(Query, Mutation=None):
context_value = { context_value = {
"query": req.get_queries(), "query": req.get_queries(),
"headers": req.get_headers(), "headers": req.get_headers(),
"params": req.get_parameters() "params": req.get_parameters(),
} }
# get all incomming data and parses as json # get all incomming data and parses as json
@ -31,9 +32,12 @@ def graphiql_from(Query, Mutation=None):
operation_name, operation_name,
) )
res.cork_end({ res.cork_end(
{
"data": (data.data), "data": (data.data),
**({"errors": data.errors} if data.errors else {}), **({"errors": data.errors} if data.errors else {}),
**({"extensions": data.extensions} if data.extensions else {}) **({"extensions": data.extensions} if data.extensions else {}),
}) }
)
return post return post

Wyświetl plik

@ -1,12 +1,15 @@
import datetime import datetime
class MemoryCacheItem: class MemoryCacheItem:
def __init__(self, expires, value): def __init__(self, expires, value):
self.expires = datetime.datetime.utcnow().timestamp() + expires self.expires = datetime.datetime.utcnow().timestamp() + expires
self.value = value self.value = value
def is_expired(self): def is_expired(self):
return datetime.datetime.utcnow().timestamp() > self.expires return datetime.datetime.utcnow().timestamp() > self.expires
class MemoryCache: class MemoryCache:
def __init__(self): def __init__(self):
self.cache = {} self.cache = {}

Wyświetl plik

@ -8,14 +8,14 @@ mimetypes.init()
# In production we highly recomend to use CDN like CloudFlare or/and NGINX or similar for static files # In production we highly recomend to use CDN like CloudFlare or/and NGINX or similar for static files
async def sendfile(res, req, filename): async def sendfile(res, req, filename):
# read headers before the first await # read headers before the first await
if_modified_since = req.get_header('if-modified-since') if_modified_since = req.get_header("if-modified-since")
range_header = req.get_header('range') range_header = req.get_header("range")
bytes_range = None bytes_range = None
start = 0 start = 0
end = -1 end = -1
# parse range header # parse range header
if range_header: if range_header:
bytes_range = range_header.replace("bytes=", '').split('-') bytes_range = range_header.replace("bytes=", "").split("-")
start = int(bytes_range[0]) start = int(bytes_range[0])
if bytes_range[1]: if bytes_range[1]:
end = int(bytes_range[1]) end = int(bytes_range[1])
@ -23,26 +23,28 @@ async def sendfile(res, req, filename):
exists = path.exists(filename) exists = path.exists(filename)
# not found # not found
if not exists: if not exists:
return res.write_status(404).end(b'Not Found') return res.write_status(404).end(b"Not Found")
# get size and last modified date # get size and last modified date
stats = os.stat(filename) stats = os.stat(filename)
total_size = stats.st_size total_size = stats.st_size
size = total_size size = total_size
last_modified = time.strftime('%a, %d %b %Y %H:%M:%S GMT', time.gmtime(stats.st_mtime)) last_modified = time.strftime(
"%a, %d %b %Y %H:%M:%S GMT", time.gmtime(stats.st_mtime)
)
# check if modified since is provided # check if modified since is provided
if if_modified_since == last_modified: if if_modified_since == last_modified:
return res.write_status(304).end_without_body() return res.write_status(304).end_without_body()
# tells the broswer the last modified date # tells the broswer the last modified date
res.write_header(b'Last-Modified', last_modified) res.write_header(b"Last-Modified", last_modified)
# add content type # add content type
(content_type, encoding) = mimetypes.guess_type(filename, strict=True) (content_type, encoding) = mimetypes.guess_type(filename, strict=True)
if content_type and encoding: if content_type and encoding:
res.write_header(b'Content-Type', '%s; %s' % (content_type, encoding)) res.write_header(b"Content-Type", "%s; %s" % (content_type, encoding))
elif content_type: elif content_type:
res.write_header(b'Content-Type', content_type) res.write_header(b"Content-Type", content_type)
async with async_open(filename, "rb") as fd: async with async_open(filename, "rb") as fd:
# check range and support it # check range and support it
@ -78,9 +80,10 @@ async def sendfile(res, req, filename):
except Exception as error: except Exception as error:
res.write_status(500).end("Internal Error") res.write_status(500).end("Internal Error")
def in_directory(file, directory): def in_directory(file, directory):
# make both absolute # make both absolute
directory = path.join(path.realpath(directory), '') directory = path.join(path.realpath(directory), "")
file = path.realpath(file) file = path.realpath(file)
# return true, if the common prefix of both is equal to directory # return true, if the common prefix of both is equal to directory
# e.g. /a/b/c/d.rst and directory is /a/b, the common prefix is /a/b # e.g. /a/b/c/d.rst and directory is /a/b, the common prefix is /a/b
@ -100,6 +103,7 @@ def static_route(app, route, directory):
res.write_status(404).end_without_body() res.write_status(404).end_without_body()
return return
res.run_async(sendfile(res, req, filename)) res.run_async(sendfile(res, req, filename))
if route.startswith("/"): if route.startswith("/"):
route = route[1::] route = route[1::]
app.get("%s/*" % route, route_handler) app.get("%s/*" % route, route_handler)

Wyświetl plik

@ -8,14 +8,14 @@ mimetypes.init()
# In production we highly recomend to use CDN like CloudFlare or/and NGINX or similar for static files # In production we highly recomend to use CDN like CloudFlare or/and NGINX or similar for static files
async def sendfile(res, req, filename): async def sendfile(res, req, filename):
# read headers before the first await # read headers before the first await
if_modified_since = req.get_header('if-modified-since') if_modified_since = req.get_header("if-modified-since")
range_header = req.get_header('range') range_header = req.get_header("range")
bytes_range = None bytes_range = None
start = 0 start = 0
end = -1 end = -1
# parse range header # parse range header
if range_header: if range_header:
bytes_range = range_header.replace("bytes=", '').split('-') bytes_range = range_header.replace("bytes=", "").split("-")
start = int(bytes_range[0]) start = int(bytes_range[0])
if bytes_range[1]: if bytes_range[1]:
end = int(bytes_range[1]) end = int(bytes_range[1])
@ -23,26 +23,28 @@ async def sendfile(res, req, filename):
exists = await os.path.exists(filename) exists = await os.path.exists(filename)
# not found # not found
if not exists: if not exists:
return res.write_status(404).end(b'Not Found') return res.write_status(404).end(b"Not Found")
# get size and last modified date # get size and last modified date
stats = await os.stat(filename) stats = await os.stat(filename)
total_size = stats.st_size total_size = stats.st_size
size = total_size size = total_size
last_modified = time.strftime('%a, %d %b %Y %H:%M:%S GMT', time.gmtime(stats.st_mtime)) last_modified = time.strftime(
"%a, %d %b %Y %H:%M:%S GMT", time.gmtime(stats.st_mtime)
)
# check if modified since is provided # check if modified since is provided
if if_modified_since == last_modified: if if_modified_since == last_modified:
return res.write_status(304).end_without_body() return res.write_status(304).end_without_body()
# tells the broswer the last modified date # tells the broswer the last modified date
res.write_header(b'Last-Modified', last_modified) res.write_header(b"Last-Modified", last_modified)
# add content type # add content type
(content_type, encoding) = mimetypes.guess_type(filename, strict=True) (content_type, encoding) = mimetypes.guess_type(filename, strict=True)
if content_type and encoding: if content_type and encoding:
res.write_header(b'Content-Type', '%s; %s' % (content_type, encoding)) res.write_header(b"Content-Type", "%s; %s" % (content_type, encoding))
elif content_type: elif content_type:
res.write_header(b'Content-Type', content_type) res.write_header(b"Content-Type", content_type)
async with aiofiles.open(filename, "rb") as fd: async with aiofiles.open(filename, "rb") as fd:
# check range and support it # check range and support it
@ -78,9 +80,10 @@ async def sendfile(res, req, filename):
except Exception as error: except Exception as error:
res.write_status(500).end("Internal Error") res.write_status(500).end("Internal Error")
def in_directory(file, directory): def in_directory(file, directory):
# make both absolute # make both absolute
directory = path.join(path.realpath(directory), '') directory = path.join(path.realpath(directory), "")
file = path.realpath(file) file = path.realpath(file)
# return true, if the common prefix of both is equal to directory # return true, if the common prefix of both is equal to directory
# e.g. /a/b/c/d.rst and directory is /a/b, the common prefix is /a/b # e.g. /a/b/c/d.rst and directory is /a/b, the common prefix is /a/b
@ -100,6 +103,7 @@ def static_route(app, route, directory):
res.write_status(404).end_without_body() res.write_status(404).end_without_body()
return return
res.run_async(sendfile(res, req, filename)) res.run_async(sendfile(res, req, filename))
if route.startswith("/"): if route.startswith("/"):
route = route[1::] route = route[1::]
app.get("%s/*" % route, route_handler) app.get("%s/*" % route, route_handler)

Wyświetl plik

@ -6,9 +6,12 @@ from mako import exceptions
from jinja2 import Environment, FileSystemLoader from jinja2 import Environment, FileSystemLoader
class Jinja2Template: class Jinja2Template:
def __init__(self, searchpath, encoding='utf-8', followlinks=False): def __init__(self, searchpath, encoding="utf-8", followlinks=False):
self.env = Environment(loader=FileSystemLoader(searchpath, encoding, followlinks)) self.env = Environment(
loader=FileSystemLoader(searchpath, encoding, followlinks)
)
# You can also add caching and logging strategy here if you want ;) # You can also add caching and logging strategy here if you want ;)
def render(self, templatename, **kwargs): def render(self, templatename, **kwargs):
@ -18,6 +21,7 @@ class Jinja2Template:
except Exception as err: except Exception as err:
return str(err) return str(err)
class MakoTemplate: class MakoTemplate:
def __init__(self, **options): def __init__(self, **options):
self.lookup = TemplateLookup(**options) self.lookup = TemplateLookup(**options)

Wyświetl plik

@ -3,7 +3,9 @@ from .memory_cache import MemoryCache
# 2 LEVEL CACHE (Redis to share amoung worker, Memory to be much faster) # 2 LEVEL CACHE (Redis to share amoung worker, Memory to be much faster)
class TwoLevelCache: class TwoLevelCache:
def __init__(self, redis_conection, memory_expiration_time=3, redis_expiration_time=10): def __init__(
self, redis_conection, memory_expiration_time=3, redis_expiration_time=10
):
self.memory_cache = MemoryCache() self.memory_cache = MemoryCache()
self.redis_conection = redis_conection self.redis_conection = redis_conection
self.memory_expiration_time = memory_expiration_time self.memory_expiration_time = memory_expiration_time

Wyświetl plik

@ -5,7 +5,7 @@ import asyncio
from helpers.twolevel_cache import TwoLevelCache from helpers.twolevel_cache import TwoLevelCache
# create redis poll + connections # create redis poll + connections
redis_pool = redis.ConnectionPool(host='localhost', port=6379, db=0) redis_pool = redis.ConnectionPool(host="localhost", port=6379, db=0)
redis_conection = redis.Redis(connection_pool=redis_pool) redis_conection = redis.Redis(connection_pool=redis_pool)
# 2 LEVEL CACHE (Redis to share amoung workers, Memory to be much faster) # 2 LEVEL CACHE (Redis to share amoung workers, Memory to be much faster)
# cache in memory is 30s, cache in redis is 60s duration # cache in memory is 30s, cache in redis is 60s duration
@ -15,17 +15,23 @@ cache = TwoLevelCache(redis_conection, 30, 60)
# Model # Model
### ###
async def get_pokemon(number): async def get_pokemon(number):
async with aiohttp.ClientSession() as session: async with aiohttp.ClientSession() as session:
async with session.get(f'https://pokeapi.co/api/v2/pokemon/{number}') as response: async with session.get(
f"https://pokeapi.co/api/v2/pokemon/{number}"
) as response:
pokemon = await response.text() pokemon = await response.text()
# cache only works with strings/bytes # cache only works with strings/bytes
# we will not change nothing here so no needs to parse json # we will not change nothing here so no needs to parse json
return pokemon.encode("utf-8") return pokemon.encode("utf-8")
async def get_original_pokemons(): async def get_original_pokemons():
async with aiohttp.ClientSession() as session: async with aiohttp.ClientSession() as session:
async with session.get(f'https://pokeapi.co/api/v2/pokemon?limit=151') as response: async with session.get(
f"https://pokeapi.co/api/v2/pokemon?limit=151"
) as response:
# cache only works with strings/bytes # cache only works with strings/bytes
# we will not change nothing here so no needs to parse json # we will not change nothing here so no needs to parse json
pokemons = await response.text() pokemons = await response.text()
@ -74,6 +80,7 @@ def list_pokemon(res, req):
res.run_async(find_pokemon(number, res)) res.run_async(find_pokemon(number, res))
### ###
# Here i decided to use an sync first and async only if needs, but you can use async directly see ./async.py # Here i decided to use an sync first and async only if needs, but you can use async directly see ./async.py
### ###
@ -81,5 +88,8 @@ app = App()
app.get("/", list_original_pokemons) app.get("/", list_original_pokemons)
app.get("/:number", list_pokemon) app.get("/:number", list_pokemon)
app.any("/*", lambda res, _: res.write_status(404).end("Not Found")) app.any("/*", lambda res, _: res.write_status(404).end("Not Found"))
app.listen(3000, lambda config: print("Listening on port http://localhost:%d now\n" % config.port)) app.listen(
3000,
lambda config: print("Listening on port http://localhost:%d now\n" % config.port),
)
app.run() app.run()

Wyświetl plik

@ -1,8 +1,17 @@
from socketify import App, AppOptions from socketify import App, AppOptions
app = App(AppOptions(key_file_name="./misc/key.pem", cert_file_name="./misc/cert.pem", passphrase="1234")) app = App(
AppOptions(
key_file_name="./misc/key.pem",
cert_file_name="./misc/cert.pem",
passphrase="1234",
)
)
app.get("/", lambda res, req: res.end("Hello World socketify from Python!")) app.get("/", lambda res, req: res.end("Hello World socketify from Python!"))
app.listen(3000, lambda config: print("Listening on port https://localhost:%d now\n" % config.port)) app.listen(
3000,
lambda config: print("Listening on port https://localhost:%d now\n" % config.port),
)
app.run() app.run()
# openssl req -newkey rsa:2048 -new -nodes -x509 -days 3650 -passout pass:1234 -keyout ./misc/key.pem -out ./misc/cert.pem # openssl req -newkey rsa:2048 -new -nodes -x509 -days 3650 -passout pass:1234 -keyout ./misc/key.pem -out ./misc/cert.pem

Wyświetl plik

@ -2,5 +2,10 @@ from socketify import App, AppListenOptions
app = App() app = App()
app.get("/", lambda res, req: res.end("Hello World socketify from Python!")) app.get("/", lambda res, req: res.end("Hello World socketify from Python!"))
app.listen(AppListenOptions(port=3000, host="0.0.0.0"), lambda config: print("Listening on port http://%s:%d now\n" % (config.host, config.port))) app.listen(
AppListenOptions(port=3000, host="0.0.0.0"),
lambda config: print(
"Listening on port http://%s:%d now\n" % (config.host, config.port)
),
)
app.run() app.run()

Wyświetl plik

@ -1,13 +1,15 @@
from socketify import App, middleware from socketify import App, middleware
async def get_user(authorization): async def get_user(authorization):
if authorization: if authorization:
# you can do something async here # you can do something async here
return { 'greeting': 'Hello, World' } return {"greeting": "Hello, World"}
return None return None
async def auth(res, req, data=None): async def auth(res, req, data=None):
user = await get_user(req.get_header('authorization')) user = await get_user(req.get_header("authorization"))
if not user: if not user:
res.write_status(403).end("not authorized") res.write_status(403).end("not authorized")
# returning Falsy in middlewares just stop the execution of the next middleware # returning Falsy in middlewares just stop the execution of the next middleware
@ -16,19 +18,25 @@ async def auth(res, req, data=None):
# returns extra data # returns extra data
return user return user
def another_middie(res, req, data=None): def another_middie(res, req, data=None):
# now we can mix sync and async and change the data here # now we can mix sync and async and change the data here
if isinstance(data, dict): if isinstance(data, dict):
gretting = data.get('greeting', '') gretting = data.get("greeting", "")
data['greeting'] = f"{gretting} from another middie ;)" data["greeting"] = f"{gretting} from another middie ;)"
return data return data
def home(res, req, user=None): def home(res, req, user=None):
res.cork_end(user.get('greeting', None)) res.cork_end(user.get("greeting", None))
app = App() app = App()
app.get("/", middleware(auth, another_middie, home)) app.get("/", middleware(auth, another_middie, home))
app.listen(3000, lambda config: print("Listening on port http://localhost:%d now\n" % config.port)) app.listen(
3000,
lambda config: print("Listening on port http://localhost:%d now\n" % config.port),
)
app.run() app.run()
# You can also take a loop on MiddlewareRouter in middleware_router.py ;) # You can also take a loop on MiddlewareRouter in middleware_router.py ;)

Wyświetl plik

@ -2,12 +2,14 @@ from socketify import App
# this is just an example of implementation you can just import using from socketify import middleware for an more complete version # this is just an example of implementation you can just import using from socketify import middleware for an more complete version
async def get_user(authorization): async def get_user(authorization):
if authorization: if authorization:
# do actually something async here # do actually something async here
return { 'greeting': 'Hello, World' } return {"greeting": "Hello, World"}
return None return None
def auth(route): def auth(route):
# in async query string, arguments and headers are only valid until the first await # in async query string, arguments and headers are only valid until the first await
async def auth_middleware(res, req): async def auth_middleware(res, req):
@ -18,7 +20,7 @@ def auth(route):
# get queries will preserve all queries inside req after await # get queries will preserve all queries inside req after await
queries = req.get_queries() queries = req.get_queries()
user = await get_user(headers.get('authorization', None)) user = await get_user(headers.get("authorization", None))
if user: if user:
return route(res, req, user) return route(res, req, user)
@ -30,13 +32,17 @@ def auth(route):
def home(res, req, user=None): def home(res, req, user=None):
theme = req.get_query("theme_color") theme = req.get_query("theme_color")
theme = theme if theme else "light" theme = theme if theme else "light"
greeting = user.get('greeting', None) greeting = user.get("greeting", None)
user_id = req.get_parameter(0) user_id = req.get_parameter(0)
res.cork_end(f"{greeting} <br/> theme: {theme} <br/> id: {user_id}") res.cork_end(f"{greeting} <br/> theme: {theme} <br/> id: {user_id}")
app = App() app = App()
app.get("/user/:id", auth(home)) app.get("/user/:id", auth(home))
app.listen(3000, lambda config: print("Listening on port http://localhost:%d now\n" % config.port)) app.listen(
3000,
lambda config: print("Listening on port http://localhost:%d now\n" % config.port),
)
app.run() app.run()

Wyświetl plik

@ -4,11 +4,12 @@ from socketify import App, MiddlewareRouter, middleware
async def get_user(authorization): async def get_user(authorization):
if authorization: if authorization:
# you can do something async here # you can do something async here
return { 'greeting': 'Hello, World' } return {"greeting": "Hello, World"}
return None return None
async def auth(res, req, data=None): async def auth(res, req, data=None):
user = await get_user(req.get_header('authorization')) user = await get_user(req.get_header("authorization"))
if not user: if not user:
res.write_status(403).end("not authorized") res.write_status(403).end("not authorized")
# returning Falsy in middlewares just stop the execution of the next middleware # returning Falsy in middlewares just stop the execution of the next middleware
@ -17,16 +18,17 @@ async def auth(res, req, data=None):
# returns extra data # returns extra data
return user return user
def another_middie(res, req, data=None): def another_middie(res, req, data=None):
# now we can mix sync and async and change the data here # now we can mix sync and async and change the data here
if isinstance(data, dict): if isinstance(data, dict):
gretting = data.get('greeting', '') gretting = data.get("greeting", "")
data['greeting'] = f"{gretting} from another middie ;)" data["greeting"] = f"{gretting} from another middie ;)"
return data return data
def home(res, req, user=None):
res.cork_end(user.get('greeting', None))
def home(res, req, user=None):
res.cork_end(user.get("greeting", None))
app = App() app = App()
@ -42,5 +44,8 @@ other_router = MiddlewareRouter(app, auth, another_middie)
other_router.get("/another_way", home) other_router.get("/another_way", home)
app.listen(3000, lambda config: print("Listening on port http://localhost:%d now\n" % config.port)) app.listen(
3000,
lambda config: print("Listening on port http://localhost:%d now\n" % config.port),
)
app.run() app.run()

Wyświetl plik

@ -2,6 +2,7 @@ from socketify import App
# this is just an example of implementation you can just import using from socketify import middleware for an more complete version # this is just an example of implementation you can just import using from socketify import middleware for an more complete version
def middleware(*functions): def middleware(*functions):
def middleware_route(res, req): def middleware_route(res, req):
data = None data = None
@ -15,13 +16,15 @@ def middleware(*functions):
return middleware_route return middleware_route
def get_user(authorization_header): def get_user(authorization_header):
if authorization_header: if authorization_header:
return { 'greeting': 'Hello, World' } return {"greeting": "Hello, World"}
return None return None
def auth(res, req, data=None): def auth(res, req, data=None):
user = get_user(req.get_header('authorization')) user = get_user(req.get_header("authorization"))
if not user: if not user:
res.write_status(403).end("not authorized") res.write_status(403).end("not authorized")
return False return False
@ -29,10 +32,15 @@ def auth(res, req, data=None):
# returns extra data # returns extra data
return user return user
def home(res, req, user=None): def home(res, req, user=None):
res.end(user.get('greeting', None)) res.end(user.get("greeting", None))
app = App() app = App()
app.get("/", middleware(auth, home)) app.get("/", middleware(auth, home))
app.listen(3000, lambda config: print("Listening on port http://localhost:%d now\n" % config.port)) app.listen(
3000,
lambda config: print("Listening on port http://localhost:%d now\n" % config.port),
)
app.run() app.run()

Wyświetl plik

@ -2,9 +2,11 @@ from socketify import App, AppOptions, AppListenOptions
app = App() app = App()
async def home(res, req): async def home(res, req):
res.end("Hello, World!") res.end("Hello, World!")
def user(res, req): def user(res, req):
try: try:
if int(req.get_parameter(0)) == 1: if int(req.get_parameter(0)) == 1:
@ -13,12 +15,19 @@ def user(res, req):
# invalid user tells to go, to the next route valid route (not found) # invalid user tells to go, to the next route valid route (not found)
req.set_yield(1) req.set_yield(1)
def not_found(res, req): def not_found(res, req):
res.write_status(404).end("Not Found") res.write_status(404).end("Not Found")
app.get("/", home) app.get("/", home)
app.get("/user/:user_id", user) app.get("/user/:user_id", user)
app.any("/*", not_found) app.any("/*", not_found)
app.listen(3000, lambda config: print("Listening on port http://localhost:%s now\n" % str(config.port))) app.listen(
3000,
lambda config: print(
"Listening on port http://localhost:%s now\n" % str(config.port)
),
)
app.run() app.run()

Wyświetl plik

@ -1,13 +1,18 @@
from socketify import App from socketify import App
def home(res, req): def home(res, req):
res.write('<html><h1>') res.write("<html><h1>")
res.write('Your proxied IP is: %s' % res.get_proxied_remote_address()) res.write("Your proxied IP is: %s" % res.get_proxied_remote_address())
res.write('</h1><h1>') res.write("</h1><h1>")
res.write('Your IP as seen by the origin server is: %s' % res.get_remote_address()) res.write("Your IP as seen by the origin server is: %s" % res.get_remote_address())
res.end('</h1></html>') res.end("</h1></html>")
app = App() app = App()
app.get("/*", home) app.get("/*", home)
app.listen(3000, lambda config: print("Listening on port http://localhost:%d now\n" % config.port)) app.listen(
3000,
lambda config: print("Listening on port http://localhost:%d now\n" % config.port),
)
app.run() app.run()

Wyświetl plik

@ -4,4 +4,4 @@ aiofile
redis redis
strawberry-graphql strawberry-graphql
mako mako
git+https://github.com/cirospaciari/socketify.py.git@main#socketify --global-option="build_ext" git+https://github.com/cirospaciari/socketify.py.git@main#socketify

Wyświetl plik

@ -1,19 +1,25 @@
from socketify import App, AppOptions, AppListenOptions from socketify import App, AppOptions, AppListenOptions
import asyncio import asyncio
from datetime import datetime from datetime import datetime
from datetime import timedelta from datetime import timedelta
app = App() app = App()
def home(res, req): def home(res, req):
res.end("Hello :)") res.end("Hello :)")
def anything(res, req): def anything(res, req):
res.end("Any route with method: %s" % req.get_method()) res.end("Any route with method: %s" % req.get_method())
def cookies(res, req): def cookies(res, req):
# cookies are writen after end # cookies are writen after end
res.set_cookie("spaciari", "1234567890",{ res.set_cookie(
"spaciari",
"1234567890",
{
# expires # expires
# path # path
# comment # comment
@ -28,12 +34,15 @@ def cookies(res, req):
"httponly": True, "httponly": True,
"samesite": "None", "samesite": "None",
"secure": True, "secure": True,
"expires": datetime.utcnow() + timedelta(minutes=30) "expires": datetime.utcnow() + timedelta(minutes=30),
}) },
res.end("Your session_id cookie is: %s" % req.get_cookie('session_id')); )
res.end("Your session_id cookie is: %s" % req.get_cookie("session_id"))
def useragent(res, req): def useragent(res, req):
res.end("Your user agent is: %s" % req.get_header('user-agent')); res.end("Your user agent is: %s" % req.get_header("user-agent"))
def user(res, req): def user(res, req):
try: try:
@ -46,6 +55,7 @@ def user(res, req):
# invalid user tells to go, to the next route valid route (not found) # invalid user tells to go, to the next route valid route (not found)
req.set_yield(1) req.set_yield(1)
async def delayed_hello(delay, res): async def delayed_hello(delay, res):
await asyncio.sleep(delay) # do something async await asyncio.sleep(delay) # do something async
res.cork_end("Hello sorry for the delay!") res.cork_end("Hello sorry for the delay!")
@ -66,10 +76,12 @@ def delayed(res, req):
# abort handler is grabed here, so responses only will be send if res.aborted == False # abort handler is grabed here, so responses only will be send if res.aborted == False
res.run_async(delayed_hello(delay, res)) res.run_async(delayed_hello(delay, res))
def json(res, req): def json(res, req):
# if you pass an object will auto write an header with application/json # if you pass an object will auto write an header with application/json
res.end({"message": "I'm an application/json!"}) res.end({"message": "I'm an application/json!"})
async def sleepy_json(res, req): async def sleepy_json(res, req):
# get parameters, query, headers anything you need here before first await :) # get parameters, query, headers anything you need here before first await :)
user_agent = req.get_header("user-agent") user_agent = req.get_header("user-agent")
@ -83,11 +95,13 @@ async def sleepy_json(res, req):
await asyncio.sleep(2) # do something async await asyncio.sleep(2) # do something async
res.cork_end({"message": "I'm delayed!", "user-agent": user_agent}) res.cork_end({"message": "I'm delayed!", "user-agent": user_agent})
def custom_header(res, req): def custom_header(res, req):
res.write_header("Content-Type", "application/octet-stream") res.write_header("Content-Type", "application/octet-stream")
res.write_header("Content-Disposition", "attachment; filename=\"message.txt\"") res.write_header("Content-Disposition", 'attachment; filename="message.txt"')
res.end("Downloaded this ;)") res.end("Downloaded this ;)")
def send_in_parts(res, req): def send_in_parts(res, req):
# write and end accepts bytes and str or its try to dumps to an json # write and end accepts bytes and str or its try to dumps to an json
res.write("I can") res.write("I can")
@ -95,16 +109,20 @@ def send_in_parts(res, req):
res.write("messages") res.write("messages")
res.end(" in parts!") res.end(" in parts!")
def redirect(res, req): def redirect(res, req):
# status code is optional default is 302 # status code is optional default is 302
res.redirect("/redirected", 302) res.redirect("/redirected", 302)
def redirected(res, req): def redirected(res, req):
res.end("You got redirected to here :D") res.end("You got redirected to here :D")
def not_found(res, req): def not_found(res, req):
res.write_status(404).end("Not Found") res.write_status(404).end("Not Found")
# app.any, app.get, app.put, app.post, app.head, app.options, app.delete, app.patch, app.connect and app.trace are available # app.any, app.get, app.put, app.post, app.head, app.options, app.delete, app.patch, app.connect and app.trace are available
app.get("/", home) app.get("/", home)
app.any("/anything", anything) app.any("/anything", anything)
@ -122,5 +140,10 @@ app.get("/redirected", redirected)
# Wildcard at last always :) # Wildcard at last always :)
app.any("/*", not_found) app.any("/*", not_found)
app.listen(3000, lambda config: print("Listening on port http://localhost:%s now\n" % str(config.port))) app.listen(
3000,
lambda config: print(
"Listening on port http://localhost:%s now\n" % str(config.port)
),
)
app.run() app.run()

Wyświetl plik

@ -40,11 +40,14 @@ async def home(res, req):
# sends the whole file with 304 and bytes range support # sends the whole file with 304 and bytes range support
await sendfile(res, req, "./public/index.html") await sendfile(res, req, "./public/index.html")
app.get("/", home) app.get("/", home)
# serve all files in public folder under /* route (you can use any route like /assets) # serve all files in public folder under /* route (you can use any route like /assets)
app.static("/", "./public") app.static("/", "./public")
app.listen(3000, lambda config: print("Listening on port http://localhost:%d now\n" % config.port)) app.listen(
3000,
lambda config: print("Listening on port http://localhost:%d now\n" % config.port),
)
app.run() app.run()

Wyświetl plik

@ -1,14 +1,22 @@
from socketify import App from socketify import App
# see helper/templates.py for plugin implementation # see helper/templates.py for plugin implementation
from helpers.templates import Jinja2Template from helpers.templates import Jinja2Template
app = App() app = App()
app.template(Jinja2Template("./templates", encoding='utf-8', followlinks=False)) app.template(Jinja2Template("./templates", encoding="utf-8", followlinks=False))
def home(res, req): def home(res, req):
res.render("jinja2_home.html", title="Hello", message="Hello, World") res.render("jinja2_home.html", title="Hello", message="Hello, World")
app.get("/", home) app.get("/", home)
app.listen(3000, lambda config: print("Listening on port http://localhost:%s now\n" % str(config.port))) app.listen(
3000,
lambda config: print(
"Listening on port http://localhost:%s now\n" % str(config.port)
),
)
app.run() app.run()

Wyświetl plik

@ -1,14 +1,26 @@
from socketify import App from socketify import App
# see helper/templates.py for plugin implementation # see helper/templates.py for plugin implementation
from helpers.templates import MakoTemplate from helpers.templates import MakoTemplate
app = App() app = App()
app.template(MakoTemplate(directories=['./templates'], output_encoding='utf-8', encoding_errors='replace')) app.template(
MakoTemplate(
directories=["./templates"], output_encoding="utf-8", encoding_errors="replace"
)
)
def home(res, req): def home(res, req):
res.render("mako_home.html", message="Hello, World") res.render("mako_home.html", message="Hello, World")
app.get("/", home) app.get("/", home)
app.listen(3000, lambda config: print("Listening on port http://localhost:%s now\n" % str(config.port))) app.listen(
3000,
lambda config: print(
"Listening on port http://localhost:%s now\n" % str(config.port)
),
)
app.run() app.run()

Wyświetl plik

@ -1,31 +1,43 @@
from socketify import App, AppOptions, OpCode, CompressOptions from socketify import App, AppOptions, OpCode, CompressOptions
def ws_open(ws): def ws_open(ws):
print('A WebSocket got connected!') print("A WebSocket got connected!")
ws.send("Hello World!", OpCode.TEXT) ws.send("Hello World!", OpCode.TEXT)
def ws_message(ws, message, opcode): def ws_message(ws, message, opcode):
print(message, opcode) print(message, opcode)
# Ok is false if backpressure was built up, wait for drain # Ok is false if backpressure was built up, wait for drain
ok = ws.send(message, opcode) ok = ws.send(message, opcode)
def ws_upgrade(res, req, socket_context): def ws_upgrade(res, req, socket_context):
key = req.get_header("sec-websocket-key") key = req.get_header("sec-websocket-key")
protocol = req.get_header("sec-websocket-protocol") protocol = req.get_header("sec-websocket-protocol")
extensions = req.get_header("sec-websocket-extensions") extensions = req.get_header("sec-websocket-extensions")
res.upgrade(key, protocol, extensions, socket_context) res.upgrade(key, protocol, extensions, socket_context)
app = App() app = App()
app.ws("/*", { app.ws(
'compression': CompressOptions.SHARED_COMPRESSOR, "/*",
'max_payload_length': 16 * 1024 * 1024, {
'idle_timeout': 12, "compression": CompressOptions.SHARED_COMPRESSOR,
'open': ws_open, "max_payload_length": 16 * 1024 * 1024,
'message': ws_message, "idle_timeout": 12,
'upgrade': ws_upgrade, "open": ws_open,
'drain': lambda ws: print('WebSocket backpressure: %s', ws.get_buffered_amount()), "message": ws_message,
'close': lambda ws, code, message: print('WebSocket closed') "upgrade": ws_upgrade,
}) "drain": lambda ws: print(
"WebSocket backpressure: %s", ws.get_buffered_amount()
),
"close": lambda ws, code, message: print("WebSocket closed"),
},
)
app.any("/", lambda res, req: res.end("Nothing to see here!")) app.any("/", lambda res, req: res.end("Nothing to see here!"))
app.listen(3000, lambda config: print("Listening on port http://localhost:%d now\n" % (config.port))) app.listen(
3000,
lambda config: print("Listening on port http://localhost:%d now\n" % (config.port)),
)
app.run() app.run()

Wyświetl plik

@ -1,15 +1,18 @@
from socketify import App, AppOptions, OpCode, CompressOptions from socketify import App, AppOptions, OpCode, CompressOptions
import asyncio import asyncio
def ws_open(ws): def ws_open(ws):
print('A WebSocket got connected!') print("A WebSocket got connected!")
ws.send("Hello World!", OpCode.TEXT) ws.send("Hello World!", OpCode.TEXT)
def ws_message(ws, message, opcode): def ws_message(ws, message, opcode):
print(message, opcode) print(message, opcode)
# Ok is false if backpressure was built up, wait for drain # Ok is false if backpressure was built up, wait for drain
ok = ws.send(message, opcode) ok = ws.send(message, opcode)
async def ws_upgrade(res, req, socket_context): async def ws_upgrade(res, req, socket_context):
key = req.get_header("sec-websocket-key") key = req.get_header("sec-websocket-key")
protocol = req.get_header("sec-websocket-protocol") protocol = req.get_header("sec-websocket-protocol")
@ -17,17 +20,26 @@ async def ws_upgrade(res, req, socket_context):
await asyncio.sleep(2) await asyncio.sleep(2)
res.upgrade(key, protocol, extensions, socket_context) res.upgrade(key, protocol, extensions, socket_context)
app = App() app = App()
app.ws("/*", { app.ws(
'compression': CompressOptions.SHARED_COMPRESSOR, "/*",
'max_payload_length': 16 * 1024 * 1024, {
'idle_timeout': 12, "compression": CompressOptions.SHARED_COMPRESSOR,
'open': ws_open, "max_payload_length": 16 * 1024 * 1024,
'message': ws_message, "idle_timeout": 12,
'upgrade': ws_upgrade, "open": ws_open,
'drain': lambda ws: print('WebSocket backpressure: %s', ws.get_buffered_amount()), "message": ws_message,
'close': lambda ws, code, message: print('WebSocket closed') "upgrade": ws_upgrade,
}) "drain": lambda ws: print(
"WebSocket backpressure: %s", ws.get_buffered_amount()
),
"close": lambda ws, code, message: print("WebSocket closed"),
},
)
app.any("/", lambda res, req: res.end("Nothing to see here!")) app.any("/", lambda res, req: res.end("Nothing to see here!"))
app.listen(3000, lambda config: print("Listening on port http://localhost:%d now\n" % (config.port))) app.listen(
3000,
lambda config: print("Listening on port http://localhost:%d now\n" % (config.port)),
)
app.run() app.run()

Wyświetl plik

@ -4,16 +4,18 @@ from socketify import App
# We always recomend check res.aborted in async operations # We always recomend check res.aborted in async operations
### ###
def upload(res, req): def upload(res, req):
print(f"Posted to {req.get_url()}") print(f"Posted to {req.get_url()}")
def on_data(res, chunk, is_end): def on_data(res, chunk, is_end):
print(f"Got chunk of data with length {len(chunk)}, is_end: {is_end}") print(f"Got chunk of data with length {len(chunk)}, is_end: {is_end}")
if (is_end): if is_end:
res.cork_end("Thanks for the data!") res.cork_end("Thanks for the data!")
res.on_data(on_data) res.on_data(on_data)
async def upload_chunks(res, req): async def upload_chunks(res, req):
print(f"Posted to {req.get_url()}") print(f"Posted to {req.get_url()}")
# await all the data, returns received chunks if fail (most likely fail is aborted requests) # await all the data, returns received chunks if fail (most likely fail is aborted requests)
@ -26,6 +28,7 @@ async def upload_chunks(res, req):
# We respond when we are done # We respond when we are done
res.cork_end("Thanks for the data!") res.cork_end("Thanks for the data!")
async def upload_json(res, req): async def upload_json(res, req):
print(f"Posted to {req.get_url()}") print(f"Posted to {req.get_url()}")
# await all the data and parses as json, returns None if fail # await all the data and parses as json, returns None if fail
@ -37,6 +40,7 @@ async def upload_json(res, req):
# We respond when we are done # We respond when we are done
res.cork_end("Thanks for the data!") res.cork_end("Thanks for the data!")
async def upload_text(res, req): async def upload_text(res, req):
print(f"Posted to {req.get_url()}") print(f"Posted to {req.get_url()}")
# await all the data and decode as text, returns None if fail # await all the data and decode as text, returns None if fail
@ -47,10 +51,13 @@ async def upload_text(res, req):
# We respond when we are done # We respond when we are done
res.cork_end("Thanks for the data!") res.cork_end("Thanks for the data!")
async def upload_urlencoded(res, req): async def upload_urlencoded(res, req):
print(f"Posted to {req.get_url()}") print(f"Posted to {req.get_url()}")
# await all the data and decode as application/x-www-form-urlencoded, returns None if fails # await all the data and decode as application/x-www-form-urlencoded, returns None if fails
form = await res.get_form_urlencoded() #first parameter is the encoding (default utf-8) form = (
await res.get_form_urlencoded()
) # first parameter is the encoding (default utf-8)
print(f"Your form is ${form}") print(f"Your form is ${form}")
@ -84,5 +91,8 @@ app.post("/urlencoded", upload_urlencoded)
app.post("/multiple", upload_multiple) app.post("/multiple", upload_multiple)
app.any("/*", lambda res, _: res.write_status(404).end("Not Found")) app.any("/*", lambda res, _: res.write_status(404).end("Not Found"))
app.listen(3000, lambda config: print("Listening on port http://localhost:%d now\n" % config.port)) app.listen(
3000,
lambda config: print("Listening on port http://localhost:%d now\n" % config.port),
)
app.run() app.run()

Wyświetl plik

@ -1,24 +1,35 @@
from socketify import App, AppOptions, OpCode, CompressOptions from socketify import App, AppOptions, OpCode, CompressOptions
def ws_open(ws): def ws_open(ws):
print('A WebSocket got connected!') print("A WebSocket got connected!")
ws.send("Hello World!", OpCode.TEXT) ws.send("Hello World!", OpCode.TEXT)
def ws_message(ws, message, opcode): def ws_message(ws, message, opcode):
print(message, opcode) print(message, opcode)
# Ok is false if backpressure was built up, wait for drain # Ok is false if backpressure was built up, wait for drain
ok = ws.send(message, opcode) ok = ws.send(message, opcode)
app = App() app = App()
app.ws("/*", { app.ws(
'compression': CompressOptions.SHARED_COMPRESSOR, "/*",
'max_payload_length': 16 * 1024 * 1024, {
'idle_timeout': 12, "compression": CompressOptions.SHARED_COMPRESSOR,
'open': ws_open, "max_payload_length": 16 * 1024 * 1024,
'message': ws_message, "idle_timeout": 12,
'drain': lambda ws: print('WebSocket backpressure: %s', ws.get_buffered_amount()), "open": ws_open,
'close': lambda ws, code, message: print('WebSocket closed') "message": ws_message,
}) "drain": lambda ws: print(
"WebSocket backpressure: %s", ws.get_buffered_amount()
),
"close": lambda ws, code, message: print("WebSocket closed"),
},
)
app.any("/", lambda res, req: res.end("Nothing to see here!'")) app.any("/", lambda res, req: res.end("Nothing to see here!'"))
app.listen(3000, lambda config: print("Listening on port http://localhost:%d now\n" % (config.port))) app.listen(
3000,
lambda config: print("Listening on port http://localhost:%d now\n" % (config.port)),
)
app.run() app.run()

Wyświetl plik

@ -2,12 +2,13 @@ import sys
vi = sys.version_info vi = sys.version_info
if vi < (3, 7): if vi < (3, 7):
raise RuntimeError('socketify requires Python 3.7 or greater') raise RuntimeError("socketify requires Python 3.7 or greater")
# if sys.platform in ('win32', 'cygwin', 'cli'): # if sys.platform in ('win32', 'cygwin', 'cli'):
# raise RuntimeError('socketify does not support Windows at the moment') # raise RuntimeError('socketify does not support Windows at the moment')
import setuptools import setuptools
# from setuptools.command.sdist import sdist # from setuptools.command.sdist import sdist
# from setuptools.command.build_ext import build_ext # from setuptools.command.build_ext import build_ext
@ -28,8 +29,6 @@ import setuptools
# NATIVE_LIB_OUTPUT = str(_ROOT / "src" / "socketify" / "libsocketify.so") # NATIVE_LIB_OUTPUT = str(_ROOT / "src" / "socketify" / "libsocketify.so")
# class Prepare(sdist): # class Prepare(sdist):
# def run(self): # def run(self):
# super().run() # super().run()
@ -60,7 +59,7 @@ with open("README.md", "r", encoding="utf-8") as fh:
setuptools.setup( setuptools.setup(
name="socketify", name="socketify",
version="0.0.1", version="0.0.1",
platforms=['macOS', 'POSIX'], platforms=["macOS", "POSIX"],
author="Ciro Spaciari", author="Ciro Spaciari",
author_email="ciro.spaciari@gmail.com", author_email="ciro.spaciari@gmail.com",
description="Fast WebSocket and Http/Https server", description="Fast WebSocket and Http/Https server",
@ -77,11 +76,20 @@ setuptools.setup(
], ],
packages=["socketify"], packages=["socketify"],
package_dir={"": "src"}, package_dir={"": "src"},
package_data={"": ['./*.so', './uWebSockets/*','./uWebSockets/*/*','./uWebSockets/*/*/*', './native/*','./native/*/*','./native/*/*/*']}, package_data={
"": [
"./*.so",
"./uWebSockets/*",
"./uWebSockets/*/*",
"./uWebSockets/*/*/*",
"./native/*",
"./native/*/*",
"./native/*/*/*",
]
},
python_requires=">=3.7", python_requires=">=3.7",
install_requires=["cffi>=1.0.0", "setuptools>=58.1.0"], install_requires=["cffi>=1.0.0", "setuptools>=58.1.0"],
has_ext_modules=lambda: True, has_ext_modules=lambda: True,
cmdclass={}, # cmdclass={'sdist': Prepare, 'build_ext': Makefile}, cmdclass={}, # cmdclass={'sdist': Prepare, 'build_ext': Makefile},
include_package_data=True,
include_package_data=True
) )

Wyświetl plik

@ -1,2 +1,9 @@
from .socketify import App, AppOptions, AppListenOptions, OpCode, SendStatus, CompressOptions from .socketify import (
App,
AppOptions,
AppListenOptions,
OpCode,
SendStatus,
CompressOptions,
)
from .helpers import sendfile, middleware, MiddlewareRouter from .helpers import sendfile, middleware, MiddlewareRouter

Wyświetl plik

@ -11,14 +11,14 @@ mimetypes.init()
# In production we highly recomend to use CDN like CloudFlare or/and NGINX or similar for static files # In production we highly recomend to use CDN like CloudFlare or/and NGINX or similar for static files
async def sendfile(res, req, filename): async def sendfile(res, req, filename):
# read headers before the first await # read headers before the first await
if_modified_since = req.get_header('if-modified-since') if_modified_since = req.get_header("if-modified-since")
range_header = req.get_header('range') range_header = req.get_header("range")
bytes_range = None bytes_range = None
start = 0 start = 0
end = -1 end = -1
# parse range header # parse range header
if range_header: if range_header:
bytes_range = range_header.replace("bytes=", '').split('-') bytes_range = range_header.replace("bytes=", "").split("-")
start = int(bytes_range[0]) start = int(bytes_range[0])
if bytes_range[1]: if bytes_range[1]:
end = int(bytes_range[1]) end = int(bytes_range[1])
@ -26,26 +26,28 @@ async def sendfile(res, req, filename):
exists = path.exists(filename) exists = path.exists(filename)
# not found # not found
if not exists: if not exists:
return res.write_status(404).end(b'Not Found') return res.write_status(404).end(b"Not Found")
# get size and last modified date # get size and last modified date
stats = os.stat(filename) stats = os.stat(filename)
total_size = stats.st_size total_size = stats.st_size
size = total_size size = total_size
last_modified = time.strftime('%a, %d %b %Y %H:%M:%S GMT', time.gmtime(stats.st_mtime)) last_modified = time.strftime(
"%a, %d %b %Y %H:%M:%S GMT", time.gmtime(stats.st_mtime)
)
# check if modified since is provided # check if modified since is provided
if if_modified_since == last_modified: if if_modified_since == last_modified:
return res.write_status(304).end_without_body() return res.write_status(304).end_without_body()
# tells the broswer the last modified date # tells the broswer the last modified date
res.write_header(b'Last-Modified', last_modified) res.write_header(b"Last-Modified", last_modified)
# add content type # add content type
(content_type, encoding) = mimetypes.guess_type(filename, strict=True) (content_type, encoding) = mimetypes.guess_type(filename, strict=True)
if content_type and encoding: if content_type and encoding:
res.write_header(b'Content-Type', '%s; %s' % (content_type, encoding)) res.write_header(b"Content-Type", "%s; %s" % (content_type, encoding))
elif content_type: elif content_type:
res.write_header(b'Content-Type', content_type) res.write_header(b"Content-Type", content_type)
with open(filename, "rb") as fd: with open(filename, "rb") as fd:
# check range and support it # check range and support it
@ -62,8 +64,10 @@ async def sendfile(res, req, filename):
res.write_status(200) res.write_status(200)
# tells the browser that we support range # tells the browser that we support range
res.write_header(b'Accept-Ranges', b'bytes') res.write_header(b"Accept-Ranges", b"bytes")
res.write_header(b'Content-Range', 'bytes %d-%d/%d' % (start, end, total_size)) res.write_header(
b"Content-Range", "bytes %d-%d/%d" % (start, end, total_size)
)
pending_size = size pending_size = size
# keep sending until abort or done # keep sending until abort or done
while not res.aborted: while not res.aborted:
@ -82,7 +86,7 @@ async def sendfile(res, req, filename):
def in_directory(file, directory): def in_directory(file, directory):
# make both absolute # make both absolute
directory = path.join(path.realpath(directory), '') directory = path.join(path.realpath(directory), "")
file = path.realpath(file) file = path.realpath(file)
# return true, if the common prefix of both is equal to directory # return true, if the common prefix of both is equal to directory
# e.g. /a/b/c/d.rst and directory is /a/b, the common prefix is /a/b # e.g. /a/b/c/d.rst and directory is /a/b, the common prefix is /a/b
@ -102,12 +106,12 @@ def static_route(app, route, directory):
res.write_status(404).end_without_body() res.write_status(404).end_without_body()
return return
res.run_async(sendfile(res, req, filename)) res.run_async(sendfile(res, req, filename))
if route.startswith("/"): if route.startswith("/"):
route = route[1::] route = route[1::]
app.get("%s/*" % route, route_handler) app.get("%s/*" % route, route_handler)
def middleware(*functions): 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
async def middleware_route(res, req, data=None): async def middleware_route(res, req, data=None):
@ -133,7 +137,7 @@ def middleware(*functions):
return middleware_route return middleware_route
class MiddlewareRouter(): class MiddlewareRouter:
def __init__(self, app, *middlewares): def __init__(self, app, *middlewares):
self.app = app self.app = app
self.middlewares = middlewares self.middlewares = middlewares
@ -149,41 +153,49 @@ class MiddlewareRouter():
middies.append(handler) middies.append(handler)
self.app.post(path, middleware(*middies)) self.app.post(path, middleware(*middies))
return self return self
def options(self, path, handler): def options(self, path, handler):
middies = list(self.middlewares) middies = list(self.middlewares)
middies.append(handler) middies.append(handler)
self.app.options(path, middleware(*middies)) self.app.options(path, middleware(*middies))
return self return self
def delete(self, path, handler): def delete(self, path, handler):
middies = list(self.middlewares) middies = list(self.middlewares)
middies.append(handler) middies.append(handler)
self.app.delete(path, middleware(*middies)) self.app.delete(path, middleware(*middies))
return self return self
def patch(self, path, handler): def patch(self, path, handler):
middies = list(self.middlewares) middies = list(self.middlewares)
middies.append(handler) middies.append(handler)
self.app.patch(path, middleware(*middies)) self.app.patch(path, middleware(*middies))
return self return self
def put(self, path, handler): def put(self, path, handler):
middies = list(self.middlewares) middies = list(self.middlewares)
middies.append(handler) middies.append(handler)
self.app.put(path, middleware(*middies)) self.app.put(path, middleware(*middies))
return self return self
def head(self, path, handler): def head(self, path, handler):
middies = list(self.middlewares) middies = list(self.middlewares)
middies.append(handler) middies.append(handler)
self.app.head(path, middleware(*middies)) self.app.head(path, middleware(*middies))
return self return self
def connect(self, path, handler): def connect(self, path, handler):
middies = list(self.middlewares) middies = list(self.middlewares)
middies.append(handler) middies.append(handler)
self.app.connect(path, middleware(*middies)) self.app.connect(path, middleware(*middies))
return self return self
def trace(self, path, handler): def trace(self, path, handler):
middies = list(self.middlewares) middies = list(self.middlewares)
middies.append(handler) middies.append(handler)
self.app.trace(path, middleware(*middies)) self.app.trace(path, middleware(*middies))
return self return self
def any(self, path, handler): def any(self, path, handler):
middies = list(self.middlewares) middies = list(self.middlewares)
middies.append(handler) middies.append(handler)

Wyświetl plik

@ -1,4 +1,3 @@
import asyncio import asyncio
import threading import threading
import time import time
@ -13,7 +12,7 @@ def future_handler(future, loop, exception_handler, response):
future.result() future.result()
return None return None
except Exception as error: except Exception as error:
if hasattr(exception_handler, '__call__'): if hasattr(exception_handler, "__call__"):
exception_handler(loop, error, response) exception_handler(loop, error, response)
else: else:
try: try:
@ -25,14 +24,17 @@ def future_handler(future, loop, exception_handler, response):
return None return None
return None return None
class Loop: class Loop:
def __init__(self, exception_handler=None): def __init__(self, exception_handler=None):
self.loop = asyncio.new_event_loop() self.loop = asyncio.new_event_loop()
self.uv_loop = UVLoop() self.uv_loop = UVLoop()
if hasattr(exception_handler, '__call__'): if hasattr(exception_handler, "__call__"):
self.exception_handler = exception_handler self.exception_handler = exception_handler
self.loop.set_exception_handler(lambda loop, context: exception_handler(loop, context, None)) self.loop.set_exception_handler(
lambda loop, context: exception_handler(loop, context, None)
)
else: else:
self.exception_handler = None self.exception_handler = None
@ -43,7 +45,6 @@ class Loop:
def set_timeout(self, timeout, callback, user_data): def set_timeout(self, timeout, callback, user_data):
return self.uv_loop.create_timer(timeout, 0, callback, user_data) return self.uv_loop.create_timer(timeout, 0, callback, user_data)
def create_future(self): def create_future(self):
return self.loop.create_future() return self.loop.create_future()
@ -70,9 +71,8 @@ class Loop:
self.loop.call_soon(self.loop.stop) self.loop.call_soon(self.loop.stop)
self.loop.run_forever() self.loop.run_forever()
def stop(self): def stop(self):
if(self.started): if self.started:
self.timer.stop() self.timer.stop()
self.started = False self.started = False
# unbind run_once # unbind run_once
@ -95,7 +95,9 @@ class Loop:
future = asyncio.ensure_future(task, loop=self.loop) future = asyncio.ensure_future(task, loop=self.loop)
# with threads # with threads
future.add_done_callback(lambda f: future_handler(f, self.loop, self.exception_handler, response)) 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 # force asyncio run once to enable req in async functions before first await
self.run_once_asyncio() self.run_once_asyncio()
@ -104,7 +106,6 @@ class Loop:
return future return future
# if sys.version_info >= (3, 11) # if sys.version_info >= (3, 11)
# with asyncio.Runner(loop_factory=uvloop.new_event_loop) as runner: # with asyncio.Runner(loop_factory=uvloop.new_event_loop) as runner:
# runner.run(main()) # runner.run(main())

Wyświetl plik

@ -1,65 +1,65 @@
status_codes = { status_codes = {
100 : b'100 Continue', 100: b"100 Continue",
101 : b'101 Switching Protocols', 101: b"101 Switching Protocols",
102 : b'102 Processing', 102: b"102 Processing",
103 : b'103 Early Hints', 103: b"103 Early Hints",
200 : b'200 OK', 200: b"200 OK",
201 : b'201 Created', 201: b"201 Created",
202 : b'202 Accepted', 202: b"202 Accepted",
203 : b'203 Non-Authoritative Information', 203: b"203 Non-Authoritative Information",
204 : b'204 No Content', 204: b"204 No Content",
205 : b'205 Reset Content', 205: b"205 Reset Content",
206 : b'206 Partial Content', 206: b"206 Partial Content",
207 : b'207 Multi-Status', 207: b"207 Multi-Status",
208 : b'208 Already Reported', 208: b"208 Already Reported",
226 : b'226 IM Used (HTTP Delta encoding)', 226: b"226 IM Used (HTTP Delta encoding)",
300 : b'300 Multiple Choices', 300: b"300 Multiple Choices",
301 : b'301 Moved Permanently', 301: b"301 Moved Permanently",
302 : b'302 Found', 302: b"302 Found",
303 : b'303 See Other', 303: b"303 See Other",
304 : b'304 Not Modified', 304: b"304 Not Modified",
305 : b'305 Use Proxy Deprecated', 305: b"305 Use Proxy Deprecated",
306 : b'306 unused', 306: b"306 unused",
307 : b'307 Temporary Redirect', 307: b"307 Temporary Redirect",
308 : b'308 Permanent Redirect', 308: b"308 Permanent Redirect",
400 : b'400 Bad Request', 400: b"400 Bad Request",
401 : b'401 Unauthorized', 401: b"401 Unauthorized",
402 : b'402 Payment Required Experimental', 402: b"402 Payment Required Experimental",
403 : b'403 Forbidden', 403: b"403 Forbidden",
404 : b'404 Not Found', 404: b"404 Not Found",
405 : b'405 Method Not Allowed', 405: b"405 Method Not Allowed",
406 : b'406 Not Acceptable', 406: b"406 Not Acceptable",
407 : b'407 Proxy Authentication Required', 407: b"407 Proxy Authentication Required",
408 : b'408 Request Timeout', 408: b"408 Request Timeout",
409 : b'409 Conflict', 409: b"409 Conflict",
410 : b'410 Gone', 410: b"410 Gone",
411 : b'411 Length Required', 411: b"411 Length Required",
412 : b'412 Precondition Failed', 412: b"412 Precondition Failed",
413 : b'413 Payload Too Large', 413: b"413 Payload Too Large",
414 : b'414 URI Too Long', 414: b"414 URI Too Long",
415 : b'415 Unsupported Media Type', 415: b"415 Unsupported Media Type",
416 : b'416 Range Not Satisfiable', 416: b"416 Range Not Satisfiable",
417 : b'417 Expectation Failed', 417: b"417 Expectation Failed",
418 : b'418 I\'m a teapot', 418: b"418 I'm a teapot",
421 : b'421 Misdirected Request', 421: b"421 Misdirected Request",
422 : b'422 Unprocessable Entity', 422: b"422 Unprocessable Entity",
423 : b'423 Locked', 423: b"423 Locked",
424 : b'424 Failed Dependency', 424: b"424 Failed Dependency",
425 : b'425 Too Early Experimental', 425: b"425 Too Early Experimental",
426 : b'426 Upgrade Required', 426: b"426 Upgrade Required",
428 : b'428 Precondition Required', 428: b"428 Precondition Required",
429 : b'429 Too Many Requests', 429: b"429 Too Many Requests",
431 : b'431 Request Header Fields Too Large', 431: b"431 Request Header Fields Too Large",
451 : b'451 Unavailable For Legal Reasons', 451: b"451 Unavailable For Legal Reasons",
500 : b'500 Internal Server Error', 500: b"500 Internal Server Error",
501 : b'501 Not Implemented', 501: b"501 Not Implemented",
502 : b'502 Bad Gateway', 502: b"502 Bad Gateway",
503 : b'503 Service Unavailable', 503: b"503 Service Unavailable",
504 : b'504 Gateway Timeout', 504: b"504 Gateway Timeout",
505 : b'505 HTTP Version Not Supported', 505: b"505 HTTP Version Not Supported",
506 : b'506 Variant Also Negotiates', 506: b"506 Variant Also Negotiates",
507 : b'507 Insufficient Storage', 507: b"507 Insufficient Storage",
508 : b'508 Loop Detected', 508: b"508 Loop Detected",
510 : b'510 Not Extended', 510: b"510 Not Extended",
511 : b'511 Network Authentication Required' 511: b"511 Network Authentication Required",
} }

Wyświetl plik

@ -1,10 +1,10 @@
import cffi import cffi
import os import os
import platform import platform
ffi = cffi.FFI() ffi = cffi.FFI()
ffi.cdef(""" ffi.cdef(
"""
typedef void (*socketify_prepare_handler)(void* user_data); typedef void (*socketify_prepare_handler)(void* user_data);
@ -54,12 +54,22 @@ void socketify_timer_set_repeat(socketify_timer* timer, uint64_t repeat);
socketify_timer* socketify_create_check(socketify_loop* loop, socketify_timer_handler handler, void* user_data); socketify_timer* socketify_create_check(socketify_loop* loop, socketify_timer_handler handler, void* user_data);
void socketify_check_destroy(socketify_timer* timer); void socketify_check_destroy(socketify_timer* timer);
""") """
)
library_extension = "dll" if platform.system().lower() == "windows" else "so" library_extension = "dll" if platform.system().lower() == "windows" else "so"
library_path = os.path.join(os.path.dirname(__file__), "libsocketify_%s_%s.%s" % (platform.system().lower(), "arm64" if "arm" in platform.processor().lower() else "amd64", library_extension)) library_path = os.path.join(
os.path.dirname(__file__),
"libsocketify_%s_%s.%s"
% (
platform.system().lower(),
"arm64" if "arm" in platform.processor().lower() else "amd64",
library_extension,
),
)
lib = ffi.dlopen(library_path) lib = ffi.dlopen(library_path)
@ffi.callback("void(void *)") @ffi.callback("void(void *)")
def socketify_generic_handler(data): def socketify_generic_handler(data):
if not data == ffi.NULL: if not data == ffi.NULL:
@ -70,7 +80,10 @@ def socketify_generic_handler(data):
class UVCheck: class UVCheck:
def __init__(self, loop, handler, user_data): def __init__(self, loop, handler, user_data):
self._handler_data = ffi.new_handle((handler, user_data)) self._handler_data = ffi.new_handle((handler, user_data))
self._ptr = lib.socketify_create_check(loop, socketify_generic_handler, self._handler_data) self._ptr = lib.socketify_create_check(
loop, socketify_generic_handler, self._handler_data
)
def stop(self): def stop(self):
lib.socketify_check_destroy(self._ptr) lib.socketify_check_destroy(self._ptr)
self._handler_data = None self._handler_data = None
@ -81,10 +94,18 @@ class UVCheck:
lib.socketify_check_destroy(self._ptr) lib.socketify_check_destroy(self._ptr)
self._handler_data = None self._handler_data = None
class UVTimer: class UVTimer:
def __init__(self, loop, timeout, repeat, handler, user_data): def __init__(self, loop, timeout, repeat, handler, user_data):
self._handler_data = ffi.new_handle((handler, user_data)) self._handler_data = ffi.new_handle((handler, user_data))
self._ptr = lib.socketify_create_timer(loop, ffi.cast("uint64_t", timeout), ffi.cast("uint64_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): def stop(self):
lib.socketify_timer_destroy(self._ptr) lib.socketify_timer_destroy(self._ptr)
self._handler_data = None self._handler_data = None
@ -107,7 +128,9 @@ class UVLoop:
def on_prepare(self, handler, user_data): def on_prepare(self, handler, user_data):
self._handler_data = ffi.new_handle((handler, user_data)) self._handler_data = ffi.new_handle((handler, user_data))
lib.socketify_on_prepare(self._loop, socketify_generic_handler, self._handler_data) lib.socketify_on_prepare(
self._loop, socketify_generic_handler, self._handler_data
)
def create_timer(self, timeout, repeat, handler, user_data): def create_timer(self, timeout, repeat, handler, user_data):
return UVTimer(self._loop, timeout, repeat, handler, user_data) return UVTimer(self._loop, timeout, repeat, handler, user_data)

Wyświetl plik

@ -15,15 +15,18 @@
from socketify import App, AppOptions, OpCode, CompressOptions from socketify import App, AppOptions, OpCode, CompressOptions
import asyncio import asyncio
def ws_open(ws): def ws_open(ws):
print('A WebSocket got connected!') print("A WebSocket got connected!")
ws.send("Hello World!", OpCode.TEXT) ws.send("Hello World!", OpCode.TEXT)
def ws_message(ws, message, opcode): def ws_message(ws, message, opcode):
print(message, opcode) print(message, opcode)
# Ok is false if backpressure was built up, wait for drain # Ok is false if backpressure was built up, wait for drain
ok = ws.send(message, opcode) ok = ws.send(message, opcode)
async def ws_upgrade(res, req, socket_context): async def ws_upgrade(res, req, socket_context):
key = req.get_header("sec-websocket-key") key = req.get_header("sec-websocket-key")
protocol = req.get_header("sec-websocket-protocol") protocol = req.get_header("sec-websocket-protocol")
@ -31,15 +34,22 @@ async def ws_upgrade(res, req, socket_context):
await asyncio.sleep(2) await asyncio.sleep(2)
res.upgrade(key, protocol, extensions, socket_context) res.upgrade(key, protocol, extensions, socket_context)
app = App() app = App()
app.ws("/*", { app.ws(
'compression': CompressOptions.SHARED_COMPRESSOR, "/*",
'max_payload_length': 16 * 1024 * 1024, {
'idle_timeout': 12, "compression": CompressOptions.SHARED_COMPRESSOR,
'open': ws_open, "max_payload_length": 16 * 1024 * 1024,
'message': ws_message, "idle_timeout": 12,
'upgrade': ws_upgrade "open": ws_open,
}) "message": ws_message,
"upgrade": ws_upgrade,
},
)
app.any("/", lambda res, req: res.end("Nothing to see here!")) app.any("/", lambda res, req: res.end("Nothing to see here!"))
app.listen(3000, lambda config: print("Listening on port http://localhost:%d now\n" % (config.port))) app.listen(
3000,
lambda config: print("Listening on port http://localhost:%d now\n" % (config.port)),
)
app.run() app.run()