kopia lustrzana https://github.com/cirospaciari/socketify.py
rename
rodzic
17c1b5b46b
commit
b6f2572372
|
@ -0,0 +1 @@
|
|||
__pycache__
|
12
README.md
12
README.md
|
@ -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()
|
||||
```
|
|
@ -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")
|
|
@ -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()
|
|
@ -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)
|
|
@ -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
|
|
@ -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
|
Ładowanie…
Reference in New Issue