Skip to content

Instantly share code, notes, and snippets.

@ryanmcgrath
Created October 30, 2023 23:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ryanmcgrath/51b813ece220fd33d337208697fa400b to your computer and use it in GitHub Desktop.
Save ryanmcgrath/51b813ece220fd33d337208697fa400b to your computer and use it in GitHub Desktop.
use std::collections::HashMap;
use std::future::Future;
use std::pin::Pin;
use std::sync::{Arc, Mutex};
use std::task::{Context, Poll};
// Just placeholders.
type CronetPtr = i32;
type CronetError = Box<dyn std::error::Error>;
type CronetResponse = String;
#[derive(Debug)]
pub enum HTTPMethod {
GET,
POST,
// etc..
}
#[derive(Debug)]
struct CronetEngineInner {
ptr: CronetPtr,
callbacks: Mutex<HashMap<CronetPtr, CronetPtr>>
}
#[derive(Clone, Debug)]
pub struct CronetEngine {
inner: Arc<CronetEngineInner>,
}
impl CronetEngine {
pub fn new() -> Self {
Self {
inner: Arc::new(CronetEngineInner {
ptr: 0,
callbacks: Mutex::new(HashMap::new())
}),
}
}
pub fn request<S>(&self, url: S) -> CronetRequestBuilder
where
S: Into<String>,
{
CronetRequestBuilder::new(self.clone(), url)
}
pub fn execute(
&self,
request: CronetRequestBuilderContext
) -> impl Future<Output = Result<CronetResponse, CronetError>> {
// File the request with the engine, setting any necessary ffi hooks for handling
// callbacks, set the necessary fields for Future checking on request, then just
// return it so the caller can await it
CronetRequest {
engine: self.clone(),
// Whatever is necessary to check for request state
}
}
}
#[derive(Debug)]
pub struct CronetRequest {
engine: CronetEngine,
// Any other necessary pieces~
}
impl Future for CronetRequest {
type Output = Result<CronetResponse, CronetError>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
println!("Checking request status...");
// Check the status of this request - maybe each request gets tagged in `execute`?
//
// let this = unsafe { self.get_unchecked_mut() };
//
// if let Some(request) = this.engine.get(...) {
// // Check request state, return Ready (w/ Response) or Pending
// } else {
// cx.waker().wake_by_ref();
// Poll::Pending
// }
cx.waker().wake_by_ref();
Poll::Pending
}
}
#[derive(Debug)]
pub struct CronetRequestBuilderContext {
pub url: String,
pub http_method: HTTPMethod
}
#[derive(Debug)]
pub struct CronetRequestBuilder {
engine: CronetEngine,
context: CronetRequestBuilderContext
}
impl CronetRequestBuilder {
pub fn new<S>(engine: CronetEngine, url: S) -> Self
where
S: Into<String>,
{
let context = CronetRequestBuilderContext {
url: url.into(),
http_method: HTTPMethod::GET
};
Self {
engine,
context
}
}
pub fn method(mut self, method: HTTPMethod) -> Self {
self.context.http_method = method;
self
}
pub fn send(self) -> impl Future<Output = Result<CronetResponse, CronetError>> {
self.engine.execute(self.context)
}
}
#[tokio::main(flavor = "current_thread")]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let engine = CronetEngine::new();
let request = engine.request("https://rymc.io/")
.method(HTTPMethod::POST)
.send().await?;
Ok(())
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment