use axum::{Json, extract::Query, extract::State, http::StatusCode}; use metrics::counter; use serde::Deserialize; use tracing::{error, instrument}; use crate::{ handlers::{ErrorResponse, ErrorResponseStatus, RespExt}, router::{AppState, UserAuth}, }; use turtle_common::record::{EncryptedData, HostId, Record, RecordIdx, RecordStatus}; #[instrument(skip_all, fields(user.id = user.id.to_string()))] pub(crate) async fn post( UserAuth(user): UserAuth, state: State, Json(records): Json>>, ) -> Result<(), ErrorResponseStatus<'static>> { let State(AppState { database, settings }) = state; tracing::debug!( count = records.len(), user = user.id.to_string(), "request to add records" ); counter!("atuin_record_uploaded").increment(records.len() as u64); let keep = records .iter() .all(|r| r.data.data.len() <= settings.max_record_size || settings.max_record_size == 0); if !keep { counter!("atuin_record_too_large").increment(1); return Err( ErrorResponse::reply("could not add records; record too large") .with_status(StatusCode::BAD_REQUEST), ); } if let Err(e) = database.add_records(&user, &records).await { error!("failed to add record: {}", e); return Err(ErrorResponse::reply("failed to add record") .with_status(StatusCode::INTERNAL_SERVER_ERROR)); } Ok(()) } #[instrument(skip_all, fields(user.id = user.id.to_string()))] pub(crate) async fn index( UserAuth(user): UserAuth, state: State, ) -> Result, ErrorResponseStatus<'static>> { let State(AppState { database, settings: _, }) = state; let record_index = match database.status(&user).await { Ok(index) => index, Err(e) => { error!("failed to get record index: {}", e); return Err(ErrorResponse::reply("failed to calculate record index") .with_status(StatusCode::INTERNAL_SERVER_ERROR)); } }; tracing::debug!(user = user.id.to_string(), "record index request"); Ok(Json(record_index)) } #[derive(Deserialize)] pub(crate) struct NextParams { host: HostId, tag: String, start: Option, count: u64, } #[instrument(skip_all, fields(user.id = user.id.to_string()))] pub(crate) async fn next( params: Query, UserAuth(user): UserAuth, state: State, ) -> Result>>, ErrorResponseStatus<'static>> { let State(AppState { database, settings: _, }) = state; let params = params.0; let records = match database .next_records(&user, params.host, params.tag, params.start, params.count) .await { Ok(records) => records, Err(e) => { error!("failed to get record index: {}", e); return Err(ErrorResponse::reply("failed to calculate record index") .with_status(StatusCode::INTERNAL_SERVER_ERROR)); } }; counter!("atuin_record_downloaded").increment(records.len() as u64); Ok(Json(records)) }