use std::collections::VecDeque;
use std::time::{Duration, Instant};
use futures_util::stream::BoxStream;
use futures_util::StreamExt;
use reqwest::Method;
use serde_json::{json, Value};
use crate::client::{Inner, SSE_TIMEOUT};
use crate::error::{Result, WritError};
use crate::models::{
AgentStatus, ApiKey, Automation, CancelOutcome, CrawlCancel, CrawlJob, CrawlList,
CrawlStartParams, DatasetFormat, DatasetList, DatasetMeta, DatasetSearchResult, Extractor,
Health, Monitor, MonitorHistory, Persona, RunCompleted, RunData, RunEvent, RunFeedItem,
RunOutcome, RunResults, RunStarted, SecretMeta, Selector, StoredFile, VaultStatus, Workflow,
};
use crate::page::Page;
use crate::sse::SseParser;
const DEFAULT_WAIT_TIMEOUT: Duration = Duration::from_secs(600);
const POLL_INTERVAL: Duration = Duration::from_secs(1);
pub type RunEventStream = BoxStream<'static, Result<RunEvent>>;
#[derive(Debug, Clone, Default)]
pub struct RunOptions {
pub inputs: Option<Value>,
pub persona_id: Option<i64>,
pub files: Option<Value>,
pub wait_timeout: Option<Duration>,
pub include_results: bool,
}
impl RunOptions {
fn body(&self, dry_run: bool) -> Value {
let mut body = serde_json::Map::new();
if let Some(inputs) = &self.inputs {
body.insert("inputs".into(), inputs.clone());
}
if let Some(persona_id) = self.persona_id {
body.insert("persona_id".into(), json!(persona_id));
}
if let Some(files) = &self.files {
body.insert("files".into(), files.clone());
}
if dry_run {
body.insert("dry_run".into(), json!(true));
}
Value::Object(body)
}
}
#[derive(Debug, Clone, Copy)]
pub struct Agent<'a> {
pub(crate) c: &'a Inner,
}
impl Agent<'_> {
pub async fn status(&self) -> Result<AgentStatus> {
self.c.get_json("/v1/agent", &[]).await
}
pub async fn health(&self) -> Result<Health> {
self.c.get_json("/v1/health", &[]).await
}
}
#[derive(Debug, Clone, Copy)]
pub struct Workflows<'a> {
pub(crate) c: &'a Inner,
}
impl Workflows<'_> {
pub async fn list(&self) -> Result<Page<Workflow>> {
self.list_with(&[]).await
}
pub async fn list_with(&self, query: &[(&str, &str)]) -> Result<Page<Workflow>> {
self.c.get_json("/v1/workflows", query).await
}
pub async fn create(&self, body: Value) -> Result<Workflow> {
self.c
.send_json(Method::POST, "/v1/workflows", &[], Some(&body))
.await
}
pub async fn get(&self, id: i64) -> Result<Workflow> {
self.c.get_json(&format!("/v1/workflows/{id}"), &[]).await
}
pub async fn update(&self, id: i64, patch: Value) -> Result<Workflow> {
self.c
.send_json(
Method::PATCH,
&format!("/v1/workflows/{id}"),
&[],
Some(&patch),
)
.await
}
pub async fn delete(&self, id: i64) -> Result<Value> {
self.c
.send_json(Method::DELETE, &format!("/v1/workflows/{id}"), &[], None)
.await
}
pub async fn run(&self, id: i64, opts: &RunOptions) -> Result<RunStarted> {
self.c
.send_json(
Method::POST,
&format!("/v1/workflows/{id}/run"),
&[],
Some(&opts.body(false)),
)
.await
}
pub async fn run_wait(
&self,
id: i64,
opts: &RunOptions,
timeout: Option<Duration>,
) -> Result<RunCompleted> {
let secs = timeout.map(|d| d.as_secs().max(1).to_string());
let mut query: Vec<(&str, &str)> = vec![("wait", "true")];
if let Some(secs) = secs.as_deref() {
query.push(("timeout", secs));
}
let out: RunCompleted = self
.c
.send_json_allowing(
Method::POST,
&format!("/v1/workflows/{id}/run"),
&query,
Some(&opts.body(false)),
&[504],
)
.await?;
if !out.done {
return Err(WritError::RunTimeout {
run_id: out.run_id,
status_url: out.status_url,
events_url: out.events_url,
});
}
Ok(out)
}
pub async fn dry_run(&self, id: i64, opts: &RunOptions) -> Result<Value> {
self.c
.send_json(
Method::POST,
&format!("/v1/workflows/{id}/run"),
&[],
Some(&opts.body(true)),
)
.await
}
pub async fn cancel(&self, id: i64) -> Result<CancelOutcome> {
self.c
.send_json_allowing(
Method::POST,
&format!("/v1/workflows/{id}/cancel"),
&[],
None,
&[409],
)
.await
}
pub async fn session(&self, id: i64) -> Result<Value> {
self.c
.get_json(&format!("/v1/workflows/{id}/session"), &[])
.await
}
pub async fn clear_session(&self, id: i64) -> Result<Value> {
self.c
.send_json(
Method::DELETE,
&format!("/v1/workflows/{id}/session"),
&[],
None,
)
.await
}
pub async fn run_and_wait(&self, id: i64, opts: &RunOptions) -> Result<RunOutcome> {
let started = self.run(id, opts).await?;
let run_id = started.run_id;
let wait = opts.wait_timeout.unwrap_or(DEFAULT_WAIT_TIMEOUT);
let deadline = Instant::now() + wait;
let runs = Runs { c: self.c };
let timeout_err = || {
WritError::Connection(format!(
"run_and_wait: run {run_id} not terminal after {}s — the run was NOT cancelled \
and continues on the daemon",
wait.as_secs()
))
};
let mut saw_terminal = false;
let remaining = deadline.saturating_duration_since(Instant::now());
if !remaining.is_zero() {
if let Ok(mut stream) = runs.events_with_timeout(run_id, remaining).await {
while let Some(item) = stream.next().await {
match item {
Ok(ev) if ev.is_terminal() => {
saw_terminal = true;
break;
}
Ok(_) => {
if Instant::now() >= deadline {
return Err(timeout_err());
}
}
Err(_) => break,
}
}
}
}
if !saw_terminal {
loop {
if Instant::now() >= deadline {
return Err(timeout_err());
}
let item = runs.get(run_id).await?;
if !item.is_running() {
break;
}
let nap = POLL_INTERVAL.min(deadline.saturating_duration_since(Instant::now()));
if nap.is_zero() {
return Err(timeout_err());
}
crate::util::sleep(nap).await;
}
}
let run = runs.get(run_id).await?;
let results = if opts.include_results {
Some(runs.results(run_id).await?)
} else {
None
};
Ok(RunOutcome { run, results })
}
}
#[derive(Debug, Clone, Copy)]
pub struct Runs<'a> {
pub(crate) c: &'a Inner,
}
impl Runs<'_> {
pub async fn list(&self) -> Result<Page<RunFeedItem>> {
self.list_with(&[]).await
}
pub async fn list_with(&self, query: &[(&str, &str)]) -> Result<Page<RunFeedItem>> {
self.c.get_json("/v1/runs", query).await
}
pub async fn get(&self, run_id: i64) -> Result<RunFeedItem> {
self.c.get_json(&format!("/v1/runs/{run_id}"), &[]).await
}
pub async fn results(&self, run_id: i64) -> Result<RunResults> {
self.c
.get_json(&format!("/v1/runs/{run_id}/results"), &[])
.await
}
pub async fn data(&self, run_id: i64) -> Result<RunData> {
self.c
.get_json(&format!("/v1/runs/{run_id}/data"), &[])
.await
}
pub async fn data_csv(&self, run_id: i64) -> Result<String> {
self.c
.get_text(&format!("/v1/runs/{run_id}/data"), &[("format", "csv")])
.await
}
pub async fn cancel(&self, run_id: i64) -> Result<CancelOutcome> {
self.c
.send_json_allowing(
Method::POST,
&format!("/v1/runs/{run_id}/cancel"),
&[],
None,
&[409],
)
.await
}
pub async fn events(&self, run_id: i64) -> Result<RunEventStream> {
self.events_with_timeout(run_id, SSE_TIMEOUT).await
}
pub(crate) async fn events_with_timeout(
&self,
run_id: i64,
timeout: Duration,
) -> Result<RunEventStream> {
let resp = self
.c
.get_stream(&format!("/v1/runs/{run_id}/events"), timeout)
.await?;
struct SseState {
body: BoxStream<'static, reqwest::Result<bytes::Bytes>>,
parser: SseParser,
pending: VecDeque<RunEvent>,
done: bool,
}
let state = SseState {
body: resp.bytes_stream().boxed(),
parser: SseParser::new(),
pending: VecDeque::new(),
done: false,
};
let stream = futures_util::stream::unfold(state, |mut st| async move {
loop {
if let Some(ev) = st.pending.pop_front() {
if ev.is_terminal() {
st.done = true;
st.pending.clear();
}
return Some((Ok(ev), st));
}
if st.done {
return None;
}
match st.body.next().await {
Some(Ok(chunk)) => {
let mut payloads = Vec::new();
st.parser.feed(&chunk, &mut payloads);
for p in payloads {
st.pending.push_back(RunEvent::parse(&p));
}
}
Some(Err(e)) => {
st.done = true;
return Some((Err(WritError::from(e)), st));
}
None => return None,
}
}
})
.boxed();
Ok(stream)
}
}
#[derive(Debug, Clone, Copy)]
pub struct Monitors<'a> {
pub(crate) c: &'a Inner,
}
impl Monitors<'_> {
pub async fn list(&self) -> Result<Page<Monitor>> {
self.list_with(&[]).await
}
pub async fn list_with(&self, query: &[(&str, &str)]) -> Result<Page<Monitor>> {
self.c.get_json("/v1/monitors", query).await
}
pub async fn create(&self, body: Value) -> Result<Monitor> {
self.c
.send_json(Method::POST, "/v1/monitors", &[], Some(&body))
.await
}
pub async fn get(&self, id: i64) -> Result<Monitor> {
self.c.get_json(&format!("/v1/monitors/{id}"), &[]).await
}
pub async fn update(&self, id: i64, patch: Value) -> Result<Monitor> {
self.c
.send_json(
Method::PATCH,
&format!("/v1/monitors/{id}"),
&[],
Some(&patch),
)
.await
}
pub async fn delete(&self, id: i64) -> Result<Value> {
self.c
.send_json(Method::DELETE, &format!("/v1/monitors/{id}"), &[], None)
.await
}
pub async fn run(&self, id: i64) -> Result<Value> {
self.c
.send_json(Method::POST, &format!("/v1/monitors/{id}/run"), &[], None)
.await
}
pub async fn changes(&self, id: i64) -> Result<MonitorHistory> {
self.changes_with(id, &[]).await
}
pub async fn changes_with(&self, id: i64, query: &[(&str, &str)]) -> Result<MonitorHistory> {
self.c
.get_json(&format!("/v1/monitors/{id}/changes"), query)
.await
}
pub async fn capacity(&self) -> Result<Value> {
self.c.get_json("/v1/monitors/capacity", &[]).await
}
pub async fn recent_changes(&self) -> Result<Page<Value>> {
self.recent_changes_with(&[]).await
}
pub async fn recent_changes_with(&self, query: &[(&str, &str)]) -> Result<Page<Value>> {
self.c.get_json("/v1/changes/recent", query).await
}
}
#[derive(Debug, Clone, Copy)]
pub struct Selectors<'a> {
pub(crate) c: &'a Inner,
}
impl Selectors<'_> {
pub async fn list(&self, monitor_id: i64) -> Result<Page<Selector>> {
self.c
.get_json(&format!("/v1/monitors/{monitor_id}/selectors"), &[])
.await
}
pub async fn create(&self, monitor_id: i64, body: Value) -> Result<Selector> {
self.c
.send_json(
Method::POST,
&format!("/v1/monitors/{monitor_id}/selectors"),
&[],
Some(&body),
)
.await
}
pub async fn get(&self, monitor_id: i64, selector_id: i64) -> Result<Selector> {
self.c
.get_json(
&format!("/v1/monitors/{monitor_id}/selectors/{selector_id}"),
&[],
)
.await
}
pub async fn update(
&self,
monitor_id: i64,
selector_id: i64,
patch: Value,
) -> Result<Selector> {
self.c
.send_json(
Method::PATCH,
&format!("/v1/monitors/{monitor_id}/selectors/{selector_id}"),
&[],
Some(&patch),
)
.await
}
pub async fn delete(&self, monitor_id: i64, selector_id: i64) -> Result<Value> {
self.c
.send_json(
Method::DELETE,
&format!("/v1/monitors/{monitor_id}/selectors/{selector_id}"),
&[],
None,
)
.await
}
pub async fn toggle(&self, monitor_id: i64, selector_id: i64) -> Result<Value> {
self.c
.send_json(
Method::POST,
&format!("/v1/monitors/{monitor_id}/selectors/{selector_id}/toggle"),
&[],
None,
)
.await
}
pub async fn test(&self, monitor_id: i64, selector_id: i64) -> Result<Value> {
self.c
.send_json(
Method::POST,
&format!("/v1/monitors/{monitor_id}/selectors/{selector_id}/test"),
&[],
None,
)
.await
}
pub async fn set_baseline(&self, monitor_id: i64, selector_id: i64) -> Result<Value> {
self.c
.send_json(
Method::POST,
&format!("/v1/monitors/{monitor_id}/selectors/{selector_id}/set-baseline"),
&[],
None,
)
.await
}
pub async fn clear_baseline(&self, monitor_id: i64, selector_id: i64) -> Result<Value> {
self.c
.send_json(
Method::POST,
&format!("/v1/monitors/{monitor_id}/selectors/{selector_id}/clear-baseline"),
&[],
None,
)
.await
}
}
#[derive(Debug, Clone, Copy)]
pub struct Extractors<'a> {
pub(crate) c: &'a Inner,
}
impl Extractors<'_> {
pub async fn list(&self, selector_id: i64) -> Result<Page<Extractor>> {
self.c
.get_json(&format!("/v1/selectors/{selector_id}/extractors"), &[])
.await
}
pub async fn create(&self, body: Value) -> Result<Extractor> {
self.c
.send_json(Method::POST, "/v1/extractors", &[], Some(&body))
.await
}
pub async fn get(&self, extractor_id: i64) -> Result<Extractor> {
self.c
.get_json(&format!("/v1/extractors/{extractor_id}"), &[])
.await
}
pub async fn update(&self, extractor_id: i64, patch: Value) -> Result<Extractor> {
self.c
.send_json(
Method::PATCH,
&format!("/v1/extractors/{extractor_id}"),
&[],
Some(&patch),
)
.await
}
pub async fn delete(&self, extractor_id: i64) -> Result<Value> {
self.c
.send_json(
Method::DELETE,
&format!("/v1/extractors/{extractor_id}"),
&[],
None,
)
.await
}
pub async fn toggle(&self, extractor_id: i64) -> Result<Value> {
self.c
.send_json(
Method::PATCH,
&format!("/v1/extractors/{extractor_id}/toggle"),
&[],
None,
)
.await
}
pub async fn test(&self, extractor_id: i64, body: Value) -> Result<Value> {
self.c
.send_json(
Method::POST,
&format!("/v1/extractors/{extractor_id}/test"),
&[],
Some(&body),
)
.await
}
}
#[derive(Debug, Clone, Copy)]
pub struct Automations<'a> {
pub(crate) c: &'a Inner,
}
impl Automations<'_> {
pub async fn list(&self) -> Result<Page<Automation>> {
self.list_with(&[]).await
}
pub async fn list_with(&self, query: &[(&str, &str)]) -> Result<Page<Automation>> {
self.c.get_json("/v1/automations", query).await
}
pub async fn create(&self, body: Value) -> Result<Automation> {
self.c
.send_json(Method::POST, "/v1/automations", &[], Some(&body))
.await
}
pub async fn get(&self, id: i64) -> Result<Automation> {
self.c.get_json(&format!("/v1/automations/{id}"), &[]).await
}
pub async fn update(&self, id: i64, patch: Value) -> Result<Automation> {
self.c
.send_json(
Method::PATCH,
&format!("/v1/automations/{id}"),
&[],
Some(&patch),
)
.await
}
pub async fn delete(&self, id: i64) -> Result<Value> {
self.c
.send_json(Method::DELETE, &format!("/v1/automations/{id}"), &[], None)
.await
}
pub async fn enable(&self, id: i64, enabled: bool) -> Result<Automation> {
self.c
.send_json(
Method::POST,
&format!("/v1/automations/{id}/enable"),
&[],
Some(&json!({ "enabled": enabled })),
)
.await
}
pub async fn run(&self, id: i64, inputs: Option<Value>) -> Result<Value> {
let body = json!({ "inputs": inputs });
self.c
.send_json(
Method::POST,
&format!("/v1/automations/{id}/run"),
&[],
Some(&body),
)
.await
}
}
#[derive(Debug, Clone, Copy)]
pub struct Personas<'a> {
pub(crate) c: &'a Inner,
}
impl Personas<'_> {
pub async fn list(&self) -> Result<Page<Persona>> {
self.list_with(&[]).await
}
pub async fn list_with(&self, query: &[(&str, &str)]) -> Result<Page<Persona>> {
self.c.get_json("/v1/personas", query).await
}
pub async fn create(&self, body: Value) -> Result<Persona> {
self.c
.send_json(Method::POST, "/v1/personas", &[], Some(&body))
.await
}
pub async fn get(&self, id: i64) -> Result<Persona> {
self.c.get_json(&format!("/v1/personas/{id}"), &[]).await
}
pub async fn update(&self, id: i64, patch: Value) -> Result<Persona> {
self.c
.send_json(
Method::PATCH,
&format!("/v1/personas/{id}"),
&[],
Some(&patch),
)
.await
}
pub async fn delete(&self, id: i64) -> Result<Value> {
self.c
.send_json(Method::DELETE, &format!("/v1/personas/{id}"), &[], None)
.await
}
pub async fn runs(&self, id: i64) -> Result<Page<Value>> {
self.c
.get_json(&format!("/v1/personas/{id}/runs"), &[])
.await
}
pub async fn validate_totp(&self, body: Value) -> Result<Value> {
self.c
.send_json(Method::POST, "/v1/personas/validate-totp", &[], Some(&body))
.await
}
pub async fn test_2fa(&self, id: i64) -> Result<Value> {
self.c
.send_json(
Method::POST,
&format!("/v1/personas/{id}/test-2fa"),
&[],
None,
)
.await
}
}
#[derive(Debug, Clone, Copy)]
pub struct Secrets<'a> {
pub(crate) c: &'a Inner,
}
impl Secrets<'_> {
pub async fn list(&self) -> Result<Page<SecretMeta>> {
self.list_with(&[]).await
}
pub async fn list_with(&self, query: &[(&str, &str)]) -> Result<Page<SecretMeta>> {
self.c.get_json("/v1/secrets", query).await
}
pub async fn set(&self, key: &str, value: &str) -> Result<SecretMeta> {
self.create(json!({ "name": key, "value": value })).await
}
pub async fn create(&self, body: Value) -> Result<SecretMeta> {
self.c
.send_json(Method::POST, "/v1/secrets", &[], Some(&body))
.await
}
pub async fn get(&self, key: &str) -> Result<SecretMeta> {
self.c.get_json(&format!("/v1/secrets/{key}"), &[]).await
}
pub async fn delete(&self, key: &str) -> Result<Value> {
self.c
.send_json(Method::DELETE, &format!("/v1/secrets/{key}"), &[], None)
.await
}
}
#[derive(Debug, Clone, Copy)]
pub struct Vault<'a> {
pub(crate) c: &'a Inner,
}
impl Vault<'_> {
pub async fn status(&self) -> Result<VaultStatus> {
self.c.get_json("/v1/vault/status", &[]).await
}
pub async fn lock(&self) -> Result<Value> {
self.c
.send_json(Method::POST, "/v1/vault/lock", &[], None)
.await
}
pub async fn unlock(&self, passphrase: &str) -> Result<Value> {
self.c
.send_json(
Method::POST,
"/v1/vault/unlock",
&[],
Some(&json!({ "passphrase": passphrase })),
)
.await
}
}
#[derive(Debug, Clone, Copy)]
pub struct Files<'a> {
pub(crate) c: &'a Inner,
}
impl Files<'_> {
pub async fn list(&self) -> Result<Page<StoredFile>> {
self.list_with(&[]).await
}
pub async fn list_with(&self, query: &[(&str, &str)]) -> Result<Page<StoredFile>> {
self.c.get_json("/v1/files", query).await
}
pub async fn upload(
&self,
filename: &str,
bytes: impl Into<Vec<u8>>,
content_type: Option<&str>,
source: Option<&str>,
) -> Result<StoredFile> {
let mut part =
reqwest::multipart::Part::bytes(bytes.into()).file_name(filename.to_string());
if let Some(ct) = content_type {
part = part
.mime_str(ct)
.map_err(|e| WritError::Connection(format!("invalid content type {ct:?}: {e}")))?;
}
let mut form = reqwest::multipart::Form::new().part("file", part);
if let Some(source) = source {
form = form.text("source", source.to_string());
}
self.c.post_multipart("/v1/files", form).await
}
pub async fn from_data(&self, body: Value) -> Result<StoredFile> {
self.c
.send_json(Method::POST, "/v1/files/from-data", &[], Some(&body))
.await
}
pub async fn get(&self, id: &str) -> Result<StoredFile> {
self.c.get_json(&format!("/v1/files/{id}"), &[]).await
}
pub async fn delete(&self, id: &str) -> Result<Value> {
self.c
.send_json(Method::DELETE, &format!("/v1/files/{id}"), &[], None)
.await
}
pub async fn content(&self, id: &str) -> Result<bytes::Bytes> {
self.c
.get_bytes(&format!("/v1/files/{id}/content"), &[])
.await
}
}
#[derive(Debug, Clone, Copy)]
pub struct Data<'a> {
pub(crate) c: &'a Inner,
}
impl Data<'_> {
pub async fn query(&self, query: &[(&str, &str)]) -> Result<Value> {
self.c.get_json("/v1/data", query).await
}
pub async fn workflow_data(&self, workflow_id: i64, query: &[(&str, &str)]) -> Result<Value> {
self.c
.get_json(&format!("/v1/workflows/{workflow_id}/data"), query)
.await
}
pub async fn delete_workflow_data(&self, workflow_id: i64) -> Result<Value> {
self.c
.send_json(
Method::DELETE,
&format!("/v1/workflows/{workflow_id}/data"),
&[],
None,
)
.await
}
pub async fn facets(&self, workflow_id: i64) -> Result<Value> {
self.c
.get_json(&format!("/v1/workflows/{workflow_id}/data/facets"), &[])
.await
}
pub async fn export(&self, workflow_id: i64, query: &[(&str, &str)]) -> Result<bytes::Bytes> {
self.c
.get_bytes(&format!("/v1/workflows/{workflow_id}/data/export"), query)
.await
}
pub async fn data_runs(&self, workflow_id: i64) -> Result<Value> {
self.c
.get_json(&format!("/v1/workflows/{workflow_id}/data/runs"), &[])
.await
}
}
#[derive(Debug, Clone, Copy)]
pub struct Keys<'a> {
pub(crate) c: &'a Inner,
}
impl Keys<'_> {
pub async fn list(&self) -> Result<Page<ApiKey>> {
self.c.get_json("/v1/keys", &[]).await
}
pub async fn create(&self, name: &str, scopes: Option<&str>) -> Result<ApiKey> {
let mut body = json!({ "name": name });
if let Some(scopes) = scopes {
body["scopes"] = Value::String(scopes.to_string());
}
self.c
.send_json(Method::POST, "/v1/keys", &[], Some(&body))
.await
}
pub async fn get(&self, id: i64) -> Result<ApiKey> {
self.c.get_json(&format!("/v1/keys/{id}"), &[]).await
}
pub async fn delete(&self, id: i64) -> Result<Value> {
self.c
.send_json(Method::DELETE, &format!("/v1/keys/{id}"), &[], None)
.await
}
}
#[derive(Debug, Clone, Copy)]
pub struct Crawl<'a> {
pub(crate) c: &'a Inner,
}
impl Crawl<'_> {
pub async fn list(&self, limit: Option<i64>) -> Result<CrawlList> {
let limit_str = limit.map(|n| n.to_string());
let mut query: Vec<(&str, &str)> = Vec::new();
if let Some(limit) = &limit_str {
query.push(("limit", limit.as_str()));
}
self.c.get_json("/v1/crawl", &query).await
}
pub async fn start(&self, params: CrawlStartParams) -> Result<CrawlJob> {
let body = serde_json::to_value(¶ms)
.map_err(|e| WritError::Connection(format!("serializing crawl params: {e}")))?;
self.c
.send_json(Method::POST, "/v1/crawl", &[], Some(&body))
.await
}
pub async fn get(&self, id: i64) -> Result<CrawlJob> {
self.c.get_json(&format!("/v1/crawl/{id}"), &[]).await
}
pub async fn cancel(&self, id: i64) -> Result<CrawlCancel> {
self.c
.send_json(Method::POST, &format!("/v1/crawl/{id}/cancel"), &[], None)
.await
}
}
#[derive(Debug, Clone, Copy)]
pub struct Datasets<'a> {
pub(crate) c: &'a Inner,
}
impl Datasets<'_> {
pub async fn list(&self) -> Result<DatasetList> {
self.c.get_json("/v1/datasets", &[]).await
}
pub async fn get(&self, id: i64) -> Result<DatasetMeta> {
self.c.get_json(&format!("/v1/datasets/{id}"), &[]).await
}
pub async fn records(&self, id: i64, query: &[(&str, &str)]) -> Result<Value> {
self.c
.get_json(&format!("/v1/datasets/{id}/records"), query)
.await
}
pub async fn export(&self, id: i64, query: &[(&str, &str)]) -> Result<String> {
self.c
.get_text(&format!("/v1/datasets/{id}/export"), query)
.await
}
pub async fn records_text(
&self,
id: i64,
format: DatasetFormat,
query: &[(&str, &str)],
) -> Result<String> {
let mut q: Vec<(&str, &str)> = vec![("format", format.as_str())];
q.extend_from_slice(query);
self.c
.get_text(&format!("/v1/datasets/{id}/records"), &q)
.await
}
pub async fn search_text(
&self,
q: &str,
format: DatasetFormat,
params: &[(&str, &str)],
) -> Result<String> {
let mut query: Vec<(&str, &str)> = vec![("q", q), ("format", format.as_str())];
query.extend_from_slice(params);
self.c.get_text("/v1/datasets/search", &query).await
}
pub async fn search_one_text(
&self,
id: i64,
q: &str,
format: DatasetFormat,
params: &[(&str, &str)],
) -> Result<String> {
let mut query: Vec<(&str, &str)> = vec![("q", q), ("format", format.as_str())];
query.extend_from_slice(params);
self.c
.get_text(&format!("/v1/datasets/{id}/search"), &query)
.await
}
pub async fn search(&self, q: &str, params: &[(&str, &str)]) -> Result<DatasetSearchResult> {
let mut query: Vec<(&str, &str)> = vec![("q", q)];
query.extend_from_slice(params);
self.c.get_json("/v1/datasets/search", &query).await
}
pub async fn search_one(
&self,
id: i64,
q: &str,
params: &[(&str, &str)],
) -> Result<DatasetSearchResult> {
let mut query: Vec<(&str, &str)> = vec![("q", q)];
query.extend_from_slice(params);
self.c
.get_json(&format!("/v1/datasets/{id}/search"), &query)
.await
}
}