ordinary-api 0.6.0-pre.13

API server for Ordinary
Documentation
// Copyright (C) 2026 Ordinary Labs, LLC.
//
// SPDX-License-Identifier: AGPL-3.0-only

use crate::server::OrdinaryApiServerState;
use axum::http::StatusCode;
use axum::response::IntoResponse;
use axum_extra::response::FileStream;
use ordinary_monitor::service::FileResult;
use serde::Deserialize;
use std::sync::Arc;
use tokio_util::io::ReaderStream;
use tracing::Instrument;
use utoipa::IntoParams;

pub mod accounts;
pub mod actions;
pub mod app;
pub mod assets;
pub mod content;
pub mod keys;
pub mod models;
pub mod root;
pub mod secrets;
pub mod templates;

#[derive(Deserialize, IntoParams)]
pub struct LogMetadataParams {
    /// project domain
    d: String,
}

pub async fn log_files_metadata_helper(
    state: &Arc<OrdinaryApiServerState>,
    query: &LogMetadataParams,
) -> impl IntoResponse {
    let monitor_span = tracing::info_span!("monitor");

    async {
        if let Some(monitor) = &*state.monitor {
            match monitor.metadata(&query.d).await {
                Ok(lfm) => match serde_json::to_string(&lfm) {
                    Ok(json) => (StatusCode::OK, [("content-type", "application/json")], json)
                        .into_response(),
                    Err(err) => {
                        tracing::error!(%err);
                        (StatusCode::INTERNAL_SERVER_ERROR, "failed to parse JSON").into_response()
                    }
                },
                Err(err) => {
                    tracing::error!(%err);
                    (StatusCode::INTERNAL_SERVER_ERROR, "failed to get metadata").into_response()
                }
            }
        } else {
            (StatusCode::NOT_FOUND, "no monitor set up").into_response()
        }
    }
    .instrument(monitor_span)
    .await
}

#[derive(Deserialize, IntoParams)]
pub struct LogFilesParams {
    /// project domain
    d: String,
    /// cursor (bytes)
    c: Option<usize>,
}

pub async fn log_files_helper(
    state: &Arc<OrdinaryApiServerState>,
    query: &LogFilesParams,
    file_name: &str,
) -> impl IntoResponse {
    let monitor_span = tracing::info_span!("monitor");

    async {
        if let Some(monitor) = &*state.monitor {
            match monitor.file(query.d.as_str(), file_name, &query.c).await {
                Ok(file_res) => match file_res {
                    FileResult::File(file, compressed) => {
                        let stream = ReaderStream::new(file);
                        let file_stream_resp = FileStream::new(stream).file_name("test.txt");

                        if compressed {
                            (
                                StatusCode::OK,
                                [
                                    ("content-type", "application/jsonl"),
                                    ("content-encoding", "zstd"),
                                ],
                                file_stream_resp,
                            )
                                .into_response()
                        } else {
                            (
                                StatusCode::OK,
                                [("content-type", "application/jsonl")],
                                file_stream_resp,
                            )
                                .into_response()
                        }
                    }
                    FileResult::Bytes(bytes) => (
                        StatusCode::OK,
                        [("content-type", "application/jsonl")],
                        bytes,
                    )
                        .into_response(),
                },
                Err(err) => {
                    tracing::error!(%err);
                    (StatusCode::INTERNAL_SERVER_ERROR, "failed to get file").into_response()
                }
            }
        } else {
            (StatusCode::NOT_FOUND, "no monitor set up").into_response()
        }
    }
    .instrument(monitor_span)
    .await
}