pub mod ability;
pub mod account;
pub mod assets;
pub mod billing;
pub mod characters;
pub mod color_presets;
pub mod r#gen;
pub mod models;
pub mod pat;
pub mod projects;
pub mod skills;
pub mod status;
pub mod wait;
use crate::livejob::{self, LiveJob};
use crate::output::OutputFormat;
use nolgia_client::Client;
use reqwest::StatusCode;
use uuid::Uuid;
#[derive(serde::Deserialize)]
struct Problem {
title: Option<String>,
detail: Option<String>,
}
async fn problem_message(response: reqwest::Response) -> Option<String> {
let body = response.text().await.ok()?;
serde_json::from_str::<Problem>(&body)
.ok()
.and_then(|p| p.detail.or(p.title))
.or_else(|| {
let trimmed = body.trim();
(!trimmed.is_empty()).then(|| trimmed.to_string())
})
}
fn describe(action: &str, status: StatusCode, message: Option<String>) -> anyhow::Error {
match message {
Some(message) => anyhow::anyhow!("{action}: {status}: {message}"),
None => anyhow::anyhow!("{action}: {status}"),
}
}
pub(crate) async fn api_error(err: nolgia_client::ApiError<()>, action: &str) -> anyhow::Error {
if let nolgia_client::ApiError::UnexpectedResponse(response) = err {
let status = response.status();
let message = problem_message(response).await;
return describe(action, status, message);
}
anyhow::Error::new(err).context(action.to_string())
}
pub(crate) async fn submit_error(err: nolgia_client::ApiError<()>, action: &str) -> anyhow::Error {
if let nolgia_client::ApiError::UnexpectedResponse(response) = err {
let status = response.status();
let message = problem_message(response).await;
if status == StatusCode::CONFLICT
&& let Some(detail) = message.as_deref()
&& let Some(job_id) = livejob::find_job_id(detail)
{
return LiveJob::Duplicate {
job_id,
detail: detail.to_string(),
}
.into();
}
return describe(action, status, message);
}
anyhow::Error::new(err).context(action.to_string())
}
pub(crate) async fn wait_error(
err: nolgia_client::ApiError<()>,
action: &str,
job_id: Uuid,
waited_seconds: u64,
) -> anyhow::Error {
if let nolgia_client::ApiError::UnexpectedResponse(response) = err {
let status = response.status();
if status == StatusCode::REQUEST_TIMEOUT {
return LiveJob::StillRunning {
job_id,
waited_seconds,
}
.into();
}
let message = problem_message(response).await;
return describe(action, status, message);
}
anyhow::Error::new(err).context(action.to_string())
}
pub struct CommandContext {
client: Client,
format: OutputFormat,
}
impl CommandContext {
pub fn new(client: Client, format: OutputFormat) -> Self {
Self { client, format }
}
pub fn client(&self) -> &Client {
&self.client
}
pub fn format(&self) -> OutputFormat {
self.format
}
}