From 88fd9dfbe8c6bc4745f04c12a7225c25182a1d2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9B=A7-440729=20=5Bsophie=5D?= Date: Fri, 16 Aug 2024 11:57:19 +0200 Subject: [PATCH] add option to define application name/version and put these into the user agent string this is similar to what the official C# API bindings do, see https://github.com/OpenShock/SDK.CSharp/blob/b1bbabcbe31c684f75aa83bb619423d23fa637cc/SDK.CSharp/OpenShockApiClient.cs#L40 --- src/api.rs | 34 +++++++++++++++++++++++++++++++++- src/error.rs | 4 ++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/src/api.rs b/src/api.rs index 43d1cc8..cd11a25 100644 --- a/src/api.rs +++ b/src/api.rs @@ -8,6 +8,8 @@ use strum_macros::EnumString; pub struct OpenShockAPIBuilder { base_url: Option, default_key: Option, + app_name: Option, + app_version: Option, } impl OpenShockAPIBuilder { @@ -33,6 +35,17 @@ impl OpenShockAPIBuilder { self } + /// set the name and optionally version of the app using this crate + /// + /// this is optional. if provided, the information will be added to the user agent string for + /// all OpenShock API requests and also sent in [`OpenShockAPI::post_control`] so the app name + /// shows up in the OpenShock log. + pub fn with_app(mut self, app_name: String, app_version: Option) -> Self { + self.app_name = Some(app_name); + self.app_version = app_version; + self + } + /// check parameters and build an instance of [`OpenShockAPI`] pub fn build(self) -> Result { let base_url = self @@ -42,6 +55,19 @@ impl OpenShockAPIBuilder { return Err(Error::MissingApiToken); }; + let mut user_agent = format!("rzap/{}", env!("CARGO_PKG_VERSION")); + // maybe add platform information as well? + let app_name = if let Some(app_name) = self.app_name { + if let Some(app_version) = self.app_version { + user_agent += &format!(" ({} {})", app_name, app_version); + } else { + user_agent += &format!(" ({})", app_name); + } + app_name + } else { + "rusty".to_string() + }; + let mut headers = header::HeaderMap::new(); headers.insert( "Content-type", @@ -51,6 +77,10 @@ impl OpenShockAPIBuilder { "accept", header::HeaderValue::from_static("application/json"), ); + headers.insert( + header::USER_AGENT, + header::HeaderValue::from_str(&user_agent).map_err(|e| Error::InvalidHeaderValue(e))?, + ); let client = reqwest::Client::builder() .default_headers(headers) .build() @@ -60,6 +90,7 @@ impl OpenShockAPIBuilder { client, base_url, default_key, + app_name, }) } } @@ -69,6 +100,7 @@ pub struct OpenShockAPI { client: reqwest::Client, base_url: String, default_key: String, + app_name: String, } /// Which list of shockers to return @@ -162,7 +194,7 @@ impl OpenShockAPI { duration: duration, exclusive: true, }], - custom_name: "rusty".to_string(), + custom_name: self.app_name.clone(), })?; let resp = self diff --git a/src/error.rs b/src/error.rs index dbb74a1..f35bb5b 100644 --- a/src/error.rs +++ b/src/error.rs @@ -7,6 +7,8 @@ pub enum Error { Serde(serde_json::Error), /// no API token was provided to the API interface MissingApiToken, + /// invalid header value when building the API interface + InvalidHeaderValue(reqwest::header::InvalidHeaderValue), } impl From for Error { @@ -27,6 +29,7 @@ impl std::fmt::Display for Error { Self::Reqwest(e) => e.fmt(f), Self::Serde(e) => e.fmt(f), Self::MissingApiToken => write!(f, "no API token was provided"), + Self::InvalidHeaderValue(e) => write!(f, "invalid header value for user agent: {}", e), } } } @@ -37,6 +40,7 @@ impl std::error::Error for Error { Self::Reqwest(e) => e.source(), Self::Serde(e) => e.source(), Self::MissingApiToken => None, + Self::InvalidHeaderValue(e) => e.source(), } } }