pull/39/head
Ciro 2022-05-28 10:47:26 -03:00
rodzic 17c1b5b46b
commit b6f2572372
7 zmienionych plików z 326 dodań i 52 usunięć

1
.gitignore vendored 100644
Wyświetl plik

@ -0,0 +1 @@
__pycache__

Wyświetl plik

@ -1,14 +1,14 @@
# uWebSockets.py
# socketify.py
Fast WebSocket and Http/Https server using CFFI with C API from [uNetworking/uWebSockets](https://github.com/uNetworking/uWebSockets)
> This project will adapt the full capi from uNetworking/uWebSockets but for now it's just this.
### Overly simple hello world app
```python
from "uws" import App
from socketify import App
app = App()
app.get("/", lambda res, req: res.end("Hello World uWS from Python!"))
app.get("/", lambda res, req: res.end("Hello World socketify from Python!"))
app.listen(3000, lambda socket, config: print("Listening on port http://localhost:%d now\n" % config.port))
app.run()
```
@ -16,7 +16,7 @@ app.run()
### pip (working progress)
```bash
pip install git+https://github.com/cirospaciari/uWebSockets.py.git
pip install git+https://github.com/cirospaciari/socketify.py.git
```
### Run
@ -26,10 +26,10 @@ pypy3 ./hello_world.py
### SSL version sample
``` python
from "uws" 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.get("/", plaintext)
app.get("/", lambda res, req: res.end("Hello World socketify from Python!"))
app.listen(3000, lambda socket, config: print("Listening on port http://localhost:%d now\n" % config.port))
app.run()
```

57
libuv.py 100644
Wyświetl plik

@ -0,0 +1,57 @@
import cffi
import os
# from ctypes.util import find_library
# print("libuv1: %s" % find_library('uv'))
ffi = cffi.FFI()
ffi.cdef("""
typedef struct uv_handle_t uv_handle_t;
typedef struct uv_timer_s uv_timer_t;
typedef void(*uv_timer_cb)(uv_timer_t* handle);
struct uv_timer_s {
uv_handle_t* next_closing; \
unsigned int flags;
uv_timer_cb timer_cb; \
void* heap_node[3]; \
uint64_t timeout; \
uint64_t repeat; \
uint64_t start_id;
};
typedef struct uv_poll_t uv_poll_t;
typedef struct uv_loop_t uv_loop_t;
typedef struct uv_os_sock_t uv_os_sock_t;
typedef struct uv_poll_cb uv_poll_cb;
typedef void (*uv_close_cb)(uv_handle_t* handle);
typedef enum {
UV_RUN_DEFAULT = 0,
UV_RUN_ONCE,
UV_RUN_NOWAIT
} uv_run_mode;
int uv_run(uv_loop_t*, uv_run_mode mode);
void uv_stop(uv_loop_t*);
int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd);
int uv_poll_init_socket(uv_loop_t* loop, uv_poll_t* handle, uv_os_sock_t socket);
int uv_poll_start(uv_poll_t* handle, int events, uv_poll_cb cb);
int uv_poll_stop(uv_poll_t* handle);
void uv_close(uv_handle_t* handle, uv_close_cb close_cb);
uv_loop_t* uv_handle_get_loop(const uv_handle_t* handle);
int uv_timer_init(uv_loop_t*, uv_timer_t* handle);
int uv_timer_start(uv_timer_t* handle,
uv_timer_cb cb,
uint64_t timeout,
uint64_t repeat);
int uv_timer_stop(uv_timer_t* handle);
uv_loop_t* uv_default_loop(void);
""")
lib = ffi.dlopen("uv")

20
original.py 100644
Wyświetl plik

@ -0,0 +1,20 @@
import uws
import asyncio
# Integrate with asyncio
# asyncio.set_event_loop(uws.Loop())
app = uws.App()
def getHandler(res, req):
res.end("Hello Python!")
app.get("/*", getHandler)
def listenHandler():
print("Listening to port 3000")
app.listen(3000, listenHandler)
app.run()
# Run asyncio event loop
# asyncio.get_event_loop().run_forever()

119
selector.py 100644
Wyświetl plik

@ -0,0 +1,119 @@
from libuv import lib, ffi
import signal
import asyncio
import selectors
# loop = lib.uv_default_loop()
# print(loop)
# lib.uv_run(loop, lib.UV_RUN_ONCE)
@ffi.callback("void(uv_timer_t*)")
def selector_timer_handler(timer):
global selector
selector.tick = True
class Selector(selectors.BaseSelector):
def __init__(self):
self.tick = False
self.list = []
self.pools = dict()
self.loop = lib.uv_default_loop()
self.timer = ffi.new("uv_timer_t *")
lib.uv_timer_init(self.loop, self.timer)
signal.signal(signal.SIGINT, lambda sig,frame: self.sigint())
# super().__init__(self)
def sigint(self):
self.interrupted = True
pass
def register(self, fileobj, events, data=None):
fd = -1
if isinstance(fileobj, int):
fd = fileobj
else:
fd = fileobj.fileno()
pass
def unregister(self, fileobj):
fd = -1
if isinstance(fileobj, int):
fd = fileobj
else:
fd = fileobj.fileno()
try:
pool = self.pools[fd]
lib.uv_poll_stop(pool)
del self.pools[fd]
except:
pass
None
def modify(self, fileobj, events, data=None):
# fd = -1
# if isinstance(fileobj, int):
# fd = fileobj
# else:
# fd = fileobj.fileno()
# try:
# del self.pools[fd]
# except:
# pass
None
def select(timeout=None):
self.interrupted = False
if timeout != None:
lib.uv_timer_stop(self.timer)
lib.uv_timer_start(self.timer, selector_timer_handler, ffi.cast("uint64_t", int(timeout)), ffi.cast("uint64_t", 0))
while True:
if timeout != None and timeout <= 0:
lib.uv_run(self.loop, lib.UV_RUN_NOWAIT)
break
keep_going = int(lib.uv_run(self.loop, lib.UV_RUN_ONCE))
if not keep_going:
break
if self.interrupted:
raise KeyboardInterrupt
if self.tick:
self.tick = False
break
if len(self.list):
break
return slice(self.list, 0 , len(self.list))
def get_key(self, fileobj):
fd = -1
if isinstance(fileobj, int):
fd = fileobj
else:
fd = fileobj.fileno()
try:
pool = self.pools[fd]
return fd
except:
return None
def get_map(self):
None
def close(self):
None
def tick(self):
self.tick = True
# def call_soon(self, *args, **kwargs):
# self.tick()
# return super().call_soon(*args, **kwargs)
# def call_at(self, *args, **kwargs):
# self.tick()
# return super().call_at(*args, **kwargs)
selector = Selector()
# loop = asyncio.SelectorEventLoop(selector)
# asyncio.set_event_loop(loop)
print(selector.loop, selector.timer)

Wyświetl plik

@ -1,9 +1,4 @@
import cffi
import threading
from datetime import datetime
import time
import os
ffi = cffi.FFI()
ffi.cdef("""
@ -56,6 +51,7 @@ struct us_listen_socket_t {
unsigned int socket_ext_size;
};
void us_listen_socket_close(int ssl, struct us_listen_socket_t *ls);
struct us_loop_t *uws_get_loop();
typedef enum
{
@ -107,8 +103,6 @@ typedef struct
int options;
} uws_app_listen_config_t;
struct uws_app_s;
struct uws_req_s;
struct uws_res_s;
@ -499,42 +493,4 @@ class AppOptions:
self.dh_params_file_name = dh_params_file_name
self.ca_file_name = ca_file_name
self.ssl_ciphers = ssl_ciphers
self.ssl_prefer_low_memory_usage = ssl_prefer_low_memory_usage
current_http_date = datetime.utcnow().isoformat() + "Z"
stopped = False
def time_thread():
while not stopped:
global current_http_date
current_http_date = datetime.utcnow().isoformat() + "Z"
time.sleep(1)
def plaintext(res, req):
res.write_header("Date", current_http_date)
res.write_header("Server", "uws.py")
res.write_header("Content-Type", "text/plain")
res.end("Hello, World!")
def run_app():
timing = threading.Thread(target=time_thread, args=())
timing.start()
app = App(AppOptions(key_file_name="./misc/key.pem", cert_file_name="./misc/cert.pem", passphrase="1234"))
app.get("/", plaintext)
# app.listen(3000, lambda config: print("Listening on port http://localhost:%s now\n" % str(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()
def create_fork():
n = os.fork()
# n greater than 0 means parent process
if not n > 0:
run_app()
for index in range(1):
create_fork()
run_app()
#pip install git+https://github.com/inducer/pycuda.git (submodules are cloned recursively)
#https://stackoverflow.com/questions/1754966/how-can-i-run-a-makefile-in-setup-py
#https://packaging.python.org/en/latest/tutorials/packaging-projects/
self.ssl_prefer_low_memory_usage = ssl_prefer_low_memory_usage

121
tests.py 100644
Wyświetl plik

@ -0,0 +1,121 @@
import threading
from datetime import datetime
import time
import os
import asyncio
#import uvloop
from json import dumps as json
from socketify import App, AppOptions, AppListenOptions
# from ujson import dumps as json
# from zzzjson import stringify as json #is too slow with CFFI
# from orjson import dumps
# def json(data):
# return dumps(data).decode("utf-8")
# from rapidjson import dumps as json
# import cysimdjson
# parser = cysimdjson.JSONParser()
# def parse(value):
# return parser.loads(value)
# def json(value):
# if isinstance(value, dict):
# for key in value:
# return "{\"%s\":\"%s\"}" % (key, value[key])
#only supports dict
# return None
current_http_date = datetime.utcnow().isoformat() + "Z"
stopped = False
def time_thread():
while not stopped:
global current_http_date
current_http_date = datetime.utcnow().isoformat() + "Z"
time.sleep(1)
def plaintext(res, req):
res.write_header("Date", current_http_date)
res.write_header("Server", "socketify")
res.write_header("Content-Type", "text/plain")
res.end("Hello, World!")
def applicationjson(res, req):
res.write_header("Date", current_http_date)
res.write_header("Server", "socketify")
res.write_header("Content-Type", "application/json")
res.end(json({"message":"Hello, World!"}))
def async_route(handler):
return lambda res,req: asyncio.run(handler(res, req))
async def plaintext_async(res, req):
# await asyncio.sleep(1)
res.write_header("Date", current_http_date)
res.write_header("Server", "socketify")
res.write_header("Content-Type", "text/plain")
res.end("Hello, World!")
async def test():
await asyncio.sleep(1)
print("Hello!")
def run_app():
timing = threading.Thread(target=time_thread, args=())
timing.start()
app = App(AppOptions(key_file_name="./misc/key.pem", cert_file_name="./misc/cert.pem", passphrase="1234"))
app.get("/", plaintext)
# app.get("/json", applicationjson)
# app.get("/plaintext", plaintext)
# app.get("/", async_route(plaintext_async))
app.listen(3000, lambda config: print("Listening on port http://localhost:%s now\n" % str(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)))
# loop = uvloop.new_event_loop()
# asyncio.set_event_loop(loop)
# print(loop)
# asyncio.run(test())
app.run()
# app.run()
# asyncio.get_event_loop().run_forever()
def create_fork():
n = os.fork()
# n greater than 0 means parent process
if not n > 0:
run_app()
# for index in range(3):
# create_fork()
# async def main():
# print('Hello ...')
# await asyncio.sleep(1)
# print('... World!')
# asyncio.run(main())
# asyncio.get_event_loop().run_forever()
run_app()
# print(parse("{\"message\":\"Hello, World\"}")["message"])
# print(json({ "array": [1, 5.5, True, False, None, "{\"message\":\"Hello, World\"}"], "yes": True, "nop": False, "none": None, "int": 1, "float": 5.5, "e": 1.2123123123123124e+37, "string": "{\"message\":\"Hello, World\"}" }))
# print(json(AppOptions(key_file_name="./misc/key.pem", cert_file_name="./misc/cert.pem", passphrase="1234").__dict__))
#pip install git+https://github.com/inducer/pycuda.git (submodules are cloned recursively)
#https://stackoverflow.com/questions/1754966/how-can-i-run-a-makefile-in-setup-py
#https://packaging.python.org/en/latest/tutorials/packaging-projects/
#pypy3 -m pip install uvloop (not working with pypy)
#apt install pypy3-dev
#pypy3 -m pip install ujson (its slow D=)
#pypy3 -m pip install orjson (dont support pypy)
#pypy3 -m pip install cysimdjson (uses simdjson) is parse only
#pypy3 -m pip install rapidjson (not working with pypy)
#https://github.com/MagicStack/uvloop/issues/380
#https://foss.heptapod.net/pypy/pypy/-/issues/3740