Skip to main content

typesafe/
blocking.rs

1//! Synchronous client (feature `blocking`). Each client owns a private current-thread Tokio
2//! runtime; do not call it from inside an async context.
3
4use std::time::Duration;
5
6use http::header::{HeaderName, HeaderValue};
7use serde::Serialize;
8use serde_json::Value;
9
10use crate::error::{Error, Result};
11use crate::question::Questions;
12use crate::response::{ListModelsResponse, SystemOneResponse};
13use crate::retry::RetryPolicy;
14
15/// Blocking TypeSafe client.
16#[derive(Debug)]
17pub struct Client {
18    inner: crate::Client,
19    rt: tokio::runtime::Runtime,
20}
21
22impl Client {
23    /// Wrap an async client configured via [`crate::Client::builder`].
24    pub fn new(inner: crate::Client) -> Result<Self> {
25        let rt = tokio::runtime::Builder::new_current_thread()
26            .enable_all()
27            .build()
28            .map_err(|e| Error::Config(format!("could not start runtime: {e}")))?;
29        Ok(Self { inner, rt })
30    }
31
32    /// A client configured entirely from the environment.
33    pub fn from_env() -> Result<Self> {
34        Self::new(crate::Client::from_env()?)
35    }
36
37    /// See [`crate::Client::system_one`].
38    pub fn system_one<S: Serialize>(
39        &self,
40        state: S,
41        questions: impl Into<Questions>,
42    ) -> SystemOneRequest<'_> {
43        SystemOneRequest {
44            rt: &self.rt,
45            req: self.inner.system_one(state, questions),
46        }
47    }
48
49    /// `GET /v1/models`.
50    pub fn list_models(&self) -> ListModelsRequest<'_> {
51        ListModelsRequest {
52            rt: &self.rt,
53            req: self.inner.models().list(),
54        }
55    }
56}
57
58macro_rules! forward {
59    ($($name:ident($($arg:ident: $ty:ty),*)),* $(,)?) => {$(
60        #[doc = concat!("See the async request's `", stringify!($name), "`.")]
61        pub fn $name(mut self, $($arg: $ty),*) -> Self {
62            self.req = self.req.$name($($arg),*);
63            self
64        }
65    )*};
66}
67
68/// Blocking `POST /v1/systemone`.
69#[must_use = "call .send()"]
70#[derive(Debug)]
71pub struct SystemOneRequest<'a> {
72    rt: &'a tokio::runtime::Runtime,
73    req: crate::SystemOneRequest,
74}
75
76impl SystemOneRequest<'_> {
77    forward!(
78        retry(policy: RetryPolicy),
79        timeout(timeout: Duration),
80        header(name: HeaderName, value: HeaderValue),
81    );
82
83    /// Override the model for this call.
84    pub fn model(mut self, model: impl Into<String>) -> Self {
85        self.req = self.req.model(model);
86        self
87    }
88
89    /// Add a top-level body field.
90    pub fn extra_body(mut self, key: impl Into<String>, value: impl Into<Value>) -> Self {
91        self.req = self.req.extra_body(key, value);
92        self
93    }
94
95    /// Send and wait.
96    pub fn send(self) -> Result<SystemOneResponse> {
97        self.rt.block_on(self.req.send())
98    }
99}
100
101/// Blocking `GET /v1/models`.
102#[must_use = "call .send()"]
103#[derive(Debug)]
104pub struct ListModelsRequest<'a> {
105    rt: &'a tokio::runtime::Runtime,
106    req: crate::ListModelsRequest,
107}
108
109impl ListModelsRequest<'_> {
110    forward!(
111        retry(policy: RetryPolicy),
112        timeout(timeout: Duration),
113        header(name: HeaderName, value: HeaderValue),
114    );
115
116    /// Send and wait.
117    pub fn send(self) -> Result<ListModelsResponse> {
118        self.rt.block_on(self.req.send())
119    }
120}