From 617b9a5589f3a71bdab99cddef758598e437232f Mon Sep 17 00:00:00 2001 From: umgefahren <55623006+umgefahren@users.noreply.github.com> Date: Fri, 10 Jan 2025 16:07:53 -0800 Subject: [PATCH] Add async functionality --- Cargo.toml | 5 +++-- src/lib.rs | 50 ++++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 47 insertions(+), 8 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 3d6372d..fa122f0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "posthog-rs" license = "MIT" -version = "0.2.6" +version = "0.3.0" authors = ["christos "] description = "An unofficial Rust client for Posthog (https://posthog.com/)." repository = "https://github.com/openquery-io/posthog-rs" @@ -10,7 +10,7 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -reqwest = { version = "0.11.3", default-features = false, features = ["blocking", "rustls-tls"] } +reqwest = { version = "0.11.3", default-features = false, features = ["rustls-tls"] } serde = { version = "1.0.125", features = ["derive"] } chrono = {version = "0.4.19", features = ["serde"] } serde_json = "1.0.64" @@ -21,4 +21,5 @@ dotenv = "0.15.0" ctor = "0.1.26" [features] +blocking = ["reqwest/blocking"] e2e-test = [] diff --git a/src/lib.rs b/src/lib.rs index 41bb4fd..9b1bdc0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,10 @@ +#![cfg_attr(docsrs, feature(doc_auto_cfg))] + use chrono::NaiveDateTime; -use reqwest::blocking::Client as HttpClient; +#[cfg(feature = "blocking")] +use reqwest::blocking::Client as BlockingHttpClient; use reqwest::header::CONTENT_TYPE; +use reqwest::Client as AsyncHttpClient; use semver::Version; use serde::Serialize; use std::collections::HashMap; @@ -13,13 +17,20 @@ const API_ENDPOINT: &str = "https://us.i.posthog.com/capture/"; const TIMEOUT: &Duration = &Duration::from_millis(800); // This should be specified by the user pub fn client>(options: C) -> Client { - let client = HttpClient::builder() + #[cfg(feature = "blocking")] + let blocking_client = BlockingHttpClient::builder() .timeout(Some(*TIMEOUT)) .build() .unwrap(); // Unwrap here is as safe as `HttpClient::new` + let async_client = AsyncHttpClient::builder() + .timeout(*TIMEOUT) + .build() + .unwrap(); // Unwrap here is as safe as `HttpClient::new` Client { options: options.into(), - client, + #[cfg(feature = "blocking")] + blocking_client, + async_client, } } @@ -56,14 +67,17 @@ impl From<&str> for ClientOptions { pub struct Client { options: ClientOptions, - client: HttpClient, + #[cfg(feature = "blocking")] + blocking_client: BlockingHttpClient, + async_client: AsyncHttpClient, } impl Client { + #[cfg(feature = "blocking")] pub fn capture(&self, event: Event) -> Result<(), Error> { let inner_event = InnerEvent::new(event, self.options.api_key.clone()); let _res = self - .client + .blocking_client .post(self.options.api_endpoint.clone()) .header(CONTENT_TYPE, "application/json") .body(serde_json::to_string(&inner_event).expect("unwrap here is safe")) @@ -72,12 +86,36 @@ impl Client { Ok(()) } - pub fn capture_batch(&self, events: Vec) -> Result<(), Error> { + pub async fn async_capture(&self, event: Event) -> Result<(), Error> { + let inner_event = InnerEvent::new(event, self.options.api_key.clone()); + let _res = self + .async_client + .post(self.options.api_endpoint.clone()) + .header(CONTENT_TYPE, "application/json") + .body(serde_json::to_string(&inner_event).expect("unwrap here is safe")) + .send() + .await + .map_err(|e| Error::Connection(e.to_string()))?; + Ok(()) + } + + #[cfg(feature = "blocking")] + pub fn capture_batch(&self, events: impl Iterator) -> Result<(), Error> { for event in events { self.capture(event)?; } Ok(()) } + + pub async fn async_capture_batch( + &self, + events: impl Iterator, + ) -> Result<(), Error> { + for event in events { + self.async_capture(event).await?; + } + Ok(()) + } } // This exists so that the client doesn't have to specify the API key over and over