Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tower Service Trait implementation #659

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion worker/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,15 @@ version = "0.7"
optional = true
default-features = false

[dependencies.tower]
version = "0.5.1"
optional = true
default-features = false
features = ["util", "buffer"]

[features]
queue = ["worker-macros/queue", "worker-sys/queue"]
d1 = ["worker-sys/d1"]
http = ["worker-macros/http"]
http = ["worker-macros/http", "dep:tower"]
axum = ["dep:axum"]
timezone = ["dep:chrono-tz"]
10 changes: 5 additions & 5 deletions worker/src/global.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,18 @@ pub enum Fetch {

impl Fetch {
/// Execute a Fetch call and receive a Response.
pub async fn send(&self) -> Result<Response> {
pub async fn send(self) -> Result<Response> {
match self {
Fetch::Url(url) => fetch_with_str(url.as_ref(), None).await,
Fetch::Request(req) => fetch_with_request(req, None).await,
Fetch::Request(req) => fetch_with_request(req.to_owned(), None).await,
}
}

/// Execute a Fetch call and receive a Response.
pub async fn send_with_signal(&self, signal: &AbortSignal) -> Result<Response> {
pub async fn send_with_signal(self, signal: &AbortSignal) -> Result<Response> {
match self {
Fetch::Url(url) => fetch_with_str(url.as_ref(), Some(signal)).await,
Fetch::Request(req) => fetch_with_request(req, Some(signal)).await,
Fetch::Request(req) => fetch_with_request(req.to_owned(), Some(signal)).await,
}
}
}
Expand All @@ -41,7 +41,7 @@ async fn fetch_with_str(url: &str, signal: Option<&AbortSignal>) -> Result<Respo
Ok(resp.into())
}

async fn fetch_with_request(request: &Request, signal: Option<&AbortSignal>) -> Result<Response> {
async fn fetch_with_request(request: Request, signal: Option<&AbortSignal>) -> Result<Response> {
let init = web_sys::RequestInit::new();
init.set_signal(signal.map(|x| x.deref()));

Expand Down
2 changes: 2 additions & 0 deletions worker/src/http.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ mod redirect;
pub mod request;
#[cfg(feature = "http")]
pub mod response;
#[cfg(feature = "http")]
pub mod service;

/// A [`Method`](https://developer.mozilla.org/en-US/docs/Web/API/Request/method) representation
/// used on Request objects.
Expand Down
43 changes: 43 additions & 0 deletions worker/src/http/service.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
use std::convert::TryInto;
use std::task::Context;
use std::{future::Future, pin::Pin, task::Poll};

use crate::send::SendFuture;
use crate::{Body, Error, Fetch, HttpResponse, Request};

/// A Tower-compatible Service implementation for Cloudflare Workers.
///
/// This struct implements the `tower::Service` trait, allowing it to be used
/// as a service in the Tower middleware ecosystem.
#[derive(Debug, Default, Clone, Copy)]
pub struct Service;

impl<B: http_body::Body<Data = bytes::Bytes> + Clone + 'static> tower::Service<http::Request<B>>
for Service
{
type Response = http::Response<Body>;
type Error = Error;
type Future =
Pin<Box<dyn Future<Output = std::result::Result<Self::Response, Self::Error>> + Send>>;

fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<std::result::Result<(), Self::Error>> {
Poll::Ready(Ok(()))
}

fn call(&mut self, req: http::Request<B>) -> Self::Future {
// Convert a http Request to a worker Request
let worker_request: Request = req.try_into().unwrap();

// Send the request with Fetch and receive a Future
let fut = Fetch::Request(worker_request).send();

// Convert the Future output to a HttpResponse
let http_response =
async { Ok(TryInto::<HttpResponse>::try_into(fut.await.unwrap()).unwrap()) };

// Wrap the Future in a SendFuture to make it Send
let wrapped = SendFuture::new(http_response);

Box::pin(wrapped)
}
}
2 changes: 2 additions & 0 deletions worker/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -248,3 +248,5 @@ pub type HttpRequest = ::http::Request<http::body::Body>;
#[cfg(feature = "http")]
/// **Requires** `http` feature. Type alias for `http::Response<worker::Body>`.
pub type HttpResponse = ::http::Response<http::body::Body>;
#[cfg(feature = "http")]
pub use http::service::Service;
2 changes: 1 addition & 1 deletion worker/src/request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use worker_sys::ext::RequestExt;

/// A [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) representation for
/// handling incoming and creating outbound HTTP requests.
#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct Request {
method: Method,
path: String,
Expand Down