2个版本

0.1.1 2023年2月2日
0.1.0 2022年10月7日

#2 in #twisted

每月 28 次下载
用于 pyo3-matrix-synapse-modul…

Apache-2.0

20KB
291

通过tower::Service处理Twisted请求

这个库帮助将Twisted的IRequest转换为http::Request,然后发送http::Response返回。

用法

通过Service处理Twisted请求

use std::convert::Infallible;

use bytes::Bytes;
use http::{Request, Response};
use http_body::Full;
use pyo3::prelude::*;
use tower::util::BoxCloneService;

use pyo3_twisted_web::handle_twisted_request_through_service;

#[pyclass]
struct Handler {
    service: BoxCloneService<Request<Full<Bytes>>, Response<String>, Infallible>,
}

#[pymethods]
impl Handler {
    #[new]
    fn new() -> Self {
        let service = tower::service_fn(|_request: Request<_>| async move {
            let response = Response::new(String::from("hello"));
            Ok(response)
        });

        Self {
            service: BoxCloneService::new(service),
        }
    }

    fn handle<'a>(&self, twisted_request: &'a PyAny) -> PyResult<&'a PyAny> {
        let service = self.service.clone();
        handle_twisted_request_through_service(service, twisted_request)
    }
}

#[pymodule]
fn my_handler(_py: Python, m: &PyModule) -> PyResult<()> {
    m.add_class::<Handler>()?;
    Ok(())
}

Python端

from twisted.internet import asyncioreactor
asyncioreactor.install()

import asyncio
from twisted.internet.defer import ensureDeferred, Deferred
from twisted.web.server import NOT_DONE_YET
from twisted.web import server, resource
from twisted.internet import endpoints, reactor

from my_handler import Handler

class MyResource(resource.Resource):
    isLeaf = True

    def __init__(self) -> None:
        super().__init__()
        self.handler = Handler()

    def render(self, request):
        f = self.handler.handle(request)
        ensureDeferred(Deferred.fromFuture(f))
        return NOT_DONE_YET

endpoints.serverFromString(reactor, "tcp:8888").listen(server.Site(MyResource()))
reactor.run()

在Service外部定义Twisted Resource

use std::convert::Infallible;

use bytes::Bytes;
use http::{Request, Response};
use pyo3::prelude::*;

use pyo3_twisted_web::Resource;

// Via a (sub)class
#[pyclass(extends=Resource)]
struct MyResource;

#[pymethods]
impl MyResource {
    #[new]
    fn new() -> (Self, Resource) {
        let service = tower::service_fn(|_request: Request<_>| async move {
            let response = Response::new(String::from("hello"));
            Ok(response)
        });

        let super_ = Resource::from_service::<_, _, Infallible>(service);
        (Self, super_)
    }
}

// Via a function
#[pyfunction]
fn get_resource(py: Python) -> PyResult<Py<Resource>> {
    let service = tower::service_fn(|_request: Request<_>| async move {
        let response = Response::new(String::from("hello"));
        Ok(response)
    });

    Py::new(py, Resource::from_service::<_, _, Infallible>(service))
}

#[pymodule]
fn my_handler(_py: Python, m: &PyModule) -> PyResult<()> {
    m.add_class::<MyResource>()?;
    m.add_function(wrap_pyfunction!(get_resource, m)?)?;
    Ok(())
}

Python端

from twisted.internet import asyncioreactor
asyncioreactor.install()

import asyncio
from twisted.web.server import Site
from twisted.internet import endpoints, reactor

from my_handler import MyResource, get_resource

endpoints.serverFromString(reactor, "tcp:8888").listen(Site(MyResource()))
# or
endpoints.serverFromString(reactor, "tcp:8888").listen(Site(get_resource()))

reactor.run()

限制

应安装Twisted asyncioreactor。通过pyo3-asyncio使用tokio运行时执行Future,这需要一个正在运行的asyncio事件循环。

Service必须接受一个http::Request<bytes::Bytes>,并返回一个http::Request<impl bytes::Buf>。必须将Service::Error转换为pyo3::PyErr(如果你不希望你的处理程序抛出Python异常,则std::convert::Infallible是一个很好的选择)。

依赖关系

~7–14MB
~154K SLoC