#![allow(unused)]
use std::{error::Error, marker::PhantomData};
use async_trait::async_trait;
use serde::{de::DeserializeOwned, Serialize};
use worker::{Env, State, Stub};
use crate::transport::{RequestTransport, ResponseTransport};
pub enum ProxiedRequest<R> {
Fetch(R),
Alarm,
}
#[async_trait(?Send)]
pub trait DoProxy
where
Self: Sized,
{
const BINDING: &'static str;
type Init: Serialize + DeserializeOwned + 'static;
type Request: Serialize + DeserializeOwned + 'static;
type Response: Serialize + DeserializeOwned + 'static;
type Error: Serialize + DeserializeOwned + Error;
async fn init(ctx: &mut Ctx, init: Self::Init) -> Result<(), Self::Error> {
Ok(())
}
async fn load_from_storage(ctx: &mut Ctx) -> Result<Self, Self::Error>;
async fn handle(
&mut self,
ctx: &mut Ctx,
req: ProxiedRequest<Self::Request>,
) -> Result<Self::Response, Self::Error>;
async fn run_request(
cached_proxy: &mut Option<Self>,
ctx: &mut Ctx,
req: Option<worker::Request>,
) -> worker::Result<worker::Response> {
enum TransportOrAlarm<Init, Request> {
Transport(RequestTransport<Init, Request>),
Alarm,
}
let mut transport_or_alarm: TransportOrAlarm<Self::Init, Self::Request> = match req {
Some(mut req) => TransportOrAlarm::Transport(req.json().await?),
None => TransportOrAlarm::Alarm,
};
let mut proxy = match cached_proxy.take() {
Some(proxy) => proxy,
None => {
if let Some(init) = match transport_or_alarm {
TransportOrAlarm::Transport(ref mut transport) => transport.take_init(),
TransportOrAlarm::Alarm => None,
} {
Self::init(ctx, init).await.map_err(|e| e.to_string())?;
Self::load_from_storage(ctx)
.await
.map_err(|e| e.to_string())?
} else {
Self::load_from_storage(ctx)
.await
.map_err(|e| e.to_string())?
}
}
};
let response = match transport_or_alarm {
TransportOrAlarm::Transport(RequestTransport::Request { request }) => {
match proxy.handle(ctx, ProxiedRequest::Fetch(request)).await {
Ok(response) => ResponseTransport::Response { response },
Err(error) => ResponseTransport::Error { error },
}
}
TransportOrAlarm::Alarm => match proxy.handle(ctx, ProxiedRequest::Alarm).await {
Ok(response) => ResponseTransport::Response { response },
Err(error) => ResponseTransport::Error { error },
},
TransportOrAlarm::Transport(RequestTransport::Empty) => ResponseTransport::Initialized,
_ => {
unreachable!("RequestTransport::Init and RequestTransport::InitWithRequest should have been handled by the match arm above");
}
};
*cached_proxy = Some(proxy);
worker::Response::from_json(&response)
}
}
pub struct Ctx<'s> {
pub state: &'s State,
pub env: &'s Env,
}
impl<'s> Ctx<'s> {
pub fn new(state: &'s State, env: &'s Env) -> Self {
Self { state, env }
}
}