WIP: working on OpenAPI docs

This commit is contained in:
Qyriad 2026-04-01 22:59:49 +02:00
parent b0fc0debc9
commit cfbe772b33
7 changed files with 536 additions and 39 deletions

345
Cargo.lock generated
View file

@ -82,6 +82,15 @@ dependencies = [
"windows-sys 0.61.2",
]
[[package]]
name = "arbitrary"
version = "1.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1"
dependencies = [
"derive_arbitrary",
]
[[package]]
name = "atomic-waker"
version = "1.1.2"
@ -173,6 +182,12 @@ dependencies = [
"windows-link 0.2.1",
]
[[package]]
name = "base64"
version = "0.22.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
[[package]]
name = "bimap"
version = "0.6.3"
@ -185,6 +200,15 @@ version = "2.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af"
[[package]]
name = "block-buffer"
version = "0.10.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
dependencies = [
"generic-array",
]
[[package]]
name = "bstr"
version = "1.12.1"
@ -196,6 +220,12 @@ dependencies = [
"serde",
]
[[package]]
name = "bumpalo"
version = "3.20.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb"
[[package]]
name = "bytes"
version = "1.11.1"
@ -305,6 +335,76 @@ dependencies = [
"unicode-xid",
]
[[package]]
name = "cpufeatures"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
dependencies = [
"libc",
]
[[package]]
name = "crc32fast"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511"
dependencies = [
"cfg-if",
]
[[package]]
name = "crypto-common"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a"
dependencies = [
"generic-array",
"typenum",
]
[[package]]
name = "derive_arbitrary"
version = "1.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "digest"
version = "0.10.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
dependencies = [
"block-buffer",
"crypto-common",
]
[[package]]
name = "dirs"
version = "6.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e"
dependencies = [
"dirs-sys",
]
[[package]]
name = "dirs-sys"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab"
dependencies = [
"libc",
"option-ext",
"redox_users",
"windows-sys 0.60.2",
]
[[package]]
name = "displaydoc"
version = "0.2.5"
@ -357,6 +457,7 @@ dependencies = [
"tracing-subscriber",
"utoipa",
"utoipa-axum",
"utoipa-swagger-ui",
"which",
]
@ -388,6 +489,16 @@ version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
[[package]]
name = "flate2"
version = "1.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c"
dependencies = [
"miniz_oxide",
"zlib-rs",
]
[[package]]
name = "foldhash"
version = "0.2.0"
@ -445,6 +556,27 @@ dependencies = [
"slab",
]
[[package]]
name = "generic-array"
version = "0.14.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
dependencies = [
"typenum",
"version_check",
]
[[package]]
name = "getrandom"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0"
dependencies = [
"cfg-if",
"libc",
"wasi",
]
[[package]]
name = "gimli"
version = "0.32.3"
@ -760,6 +892,15 @@ version = "0.2.183"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d"
[[package]]
name = "libredox"
version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1744e39d1d6a9948f4f388969627434e31128196de472883b39f148769bfe30a"
dependencies = [
"libc",
]
[[package]]
name = "linux-raw-sys"
version = "0.12.1"
@ -815,6 +956,16 @@ version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
[[package]]
name = "mime_guess"
version = "2.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e"
dependencies = [
"mime",
"unicase",
]
[[package]]
name = "miniz_oxide"
version = "0.8.9"
@ -822,6 +973,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316"
dependencies = [
"adler2",
"simd-adler32",
]
[[package]]
@ -878,6 +1030,12 @@ version = "1.70.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
[[package]]
name = "option-ext"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
[[package]]
name = "owo-colors"
version = "4.3.0"
@ -995,6 +1153,17 @@ dependencies = [
"bitflags",
]
[[package]]
name = "redox_users"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac"
dependencies = [
"getrandom",
"libredox",
"thiserror",
]
[[package]]
name = "regex"
version = "1.12.3"
@ -1030,6 +1199,40 @@ version = "0.8.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a"
[[package]]
name = "rust-embed"
version = "8.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04113cb9355a377d83f06ef1f0a45b8ab8cd7d8b1288160717d66df5c7988d27"
dependencies = [
"rust-embed-impl",
"rust-embed-utils",
"walkdir",
]
[[package]]
name = "rust-embed-impl"
version = "8.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da0902e4c7c8e997159ab384e6d0fc91c221375f6894346ae107f47dd0f3ccaa"
dependencies = [
"proc-macro2",
"quote",
"rust-embed-utils",
"syn",
"walkdir",
]
[[package]]
name = "rust-embed-utils"
version = "8.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5bcdef0be6fe7f6fa333b1073c949729274b05f123a0ad7efcb8efd878e5c3b1"
dependencies = [
"sha2",
"walkdir",
]
[[package]]
name = "rustc-demangle"
version = "0.1.27"
@ -1067,6 +1270,15 @@ version = "1.0.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f"
[[package]]
name = "same-file"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
dependencies = [
"winapi-util",
]
[[package]]
name = "scopeguard"
version = "1.2.0"
@ -1139,6 +1351,17 @@ dependencies = [
"serde",
]
[[package]]
name = "sha2"
version = "0.10.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
dependencies = [
"cfg-if",
"cpufeatures",
"digest",
]
[[package]]
name = "sharded-slab"
version = "0.1.7"
@ -1164,6 +1387,12 @@ dependencies = [
"libc",
]
[[package]]
name = "simd-adler32"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214"
[[package]]
name = "slab"
version = "0.4.12"
@ -1288,6 +1517,26 @@ dependencies = [
"unicode-width",
]
[[package]]
name = "thiserror"
version = "2.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "2.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "thread_local"
version = "1.1.9"
@ -1441,6 +1690,18 @@ dependencies = [
"tracing-log",
]
[[package]]
name = "typenum"
version = "1.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb"
[[package]]
name = "unicase"
version = "2.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142"
[[package]]
name = "unicode-ident"
version = "1.0.24"
@ -1545,12 +1806,55 @@ dependencies = [
"utoipa-config",
]
[[package]]
name = "utoipa-swagger-ui"
version = "9.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d047458f1b5b65237c2f6dc6db136945667f40a7668627b3490b9513a3d43a55"
dependencies = [
"axum",
"base64",
"dirs",
"mime_guess",
"regex",
"rust-embed",
"serde",
"serde_json",
"sha2",
"url",
"utoipa",
"utoipa-swagger-ui-vendored",
"zip",
]
[[package]]
name = "utoipa-swagger-ui-vendored"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2eebbbfe4093922c2b6734d7c679ebfebd704a0d7e56dfcb0d05818ce28977d"
[[package]]
name = "valuable"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65"
[[package]]
name = "version_check"
version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
[[package]]
name = "walkdir"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
dependencies = [
"same-file",
"winapi-util",
]
[[package]]
name = "wasi"
version = "0.11.1+wasi-snapshot-preview1"
@ -1566,6 +1870,15 @@ dependencies = [
"libc",
]
[[package]]
name = "winapi-util"
version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
dependencies = [
"windows-sys 0.61.2",
]
[[package]]
name = "windows"
version = "0.61.3"
@ -1849,8 +2162,40 @@ dependencies = [
"syn",
]
[[package]]
name = "zip"
version = "3.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12598812502ed0105f607f941c386f43d441e00148fce9dec3ca5ffb0bde9308"
dependencies = [
"arbitrary",
"crc32fast",
"flate2",
"indexmap",
"memchr",
"zopfli",
]
[[package]]
name = "zlib-rs"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3be3d40e40a133f9c916ee3f9f4fa2d9d63435b5fbe1bfc6d9dae0aa0ada1513"
[[package]]
name = "zmij"
version = "1.0.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa"
[[package]]
name = "zopfli"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f05cd8797d63865425ff89b5c4a48804f35ba0ce8d125800027ad6017d2b5249"
dependencies = [
"bumpalo",
"crc32fast",
"log",
"simd-adler32",
]

View file

@ -17,9 +17,10 @@ name = "dynix"
path = "src/lib.rs"
[features]
default = ["regex-full"]
default = ["regex-full", "vendored-swagger"]
regex-full = ["dep:regex"]
regex-lite = ["dep:regex-lite"]
vendored-swagger = ["utoipa-swagger-ui/vendored"]
[dependencies]
axum = { version = "0.8.8", features = ["macros"] }
@ -54,11 +55,12 @@ tracing-human-layer = "0.2.1"
tracing-subscriber = { version = "0.3.22", default-features = false, features = ["std", "env-filter", "fmt", "ansi", "registry", "parking_lot"] }
utoipa = { version = "5.4.0", features = ["axum_extras", "config", "debug", "indexmap", "preserve_order", "preserve_path_order", "repr", "time", "url"] }
utoipa-axum = { version = "0.2.0", features = ["debug"] }
utoipa-swagger-ui = { version = "9.0.2", features = ["axum", "cache", "debug"] }
which = "8.0.2"
[profile.dev]
opt-level = 1
lto = "thin"
#lto = "thin"
[profile.release]
debug = true

View file

@ -9,7 +9,7 @@ use std::{
sync::{Arc, LazyLock},
};
use clap::ColorChoice;
use clap::{ArgAction, ColorChoice};
use crate::prelude::*;
@ -23,6 +23,49 @@ pub struct AppendCmd {
pub value: Arc<str>,
}
#[derive(Debug, Clone, PartialEq, Default)]
pub enum UnixPathOutput {
#[default]
Stdout,
Path(PathBuf),
}
impl UnixPathOutput {
pub fn is_stdout(&self) -> bool {
use UnixPathOutput::*;
match self {
Stdout => true,
Path(_) => false,
}
}
}
impl From<&OsStr> for UnixPathOutput {
fn from(other: &OsStr) -> UnixPathOutput {
use UnixPathOutput::*;
if other == OsStr::new("-") {
return Stdout;
}
Path(PathBuf::from(other))
}
}
impl Display for UnixPathOutput {
fn fmt(&self, f: &mut Formatter) -> FmtResult {
use UnixPathOutput::*;
match self {
Stdout => write!(f, "-")?,
Path(path) => {
if path.to_str().is_none() {
warn!(
"clap might complain that this path doesn't roundtrip through Display: {}",
path.display(),
);
}
write!(f, "{}", path.display())?
},
}
Ok(())
}
}
/// Accept commands over (default stdin).
#[derive(Debug, Clone, PartialEq, clap::Parser)]
#[command(long_about = None)]
@ -30,6 +73,20 @@ pub struct DaemonCmd {
/// Specify the bind address.
#[arg(long, default_value = "0.0.0.0:42420")]
pub bind: SocketAddr,
/// Output generated OpenAPI docs, and exit.
#[arg(long)]
#[arg(default_missing_value = "-")]
#[arg(value_name = "dest")]
//#[arg(default_value = None)]
#[arg(action = ArgAction::Set)]
#[arg(num_args = 0..=1)]
//#[arg(require_equals = true)]
pub apidocs: Option<UnixPathOutput>,
/// Host a swagger server at 0.0.0.0:42421.
#[arg(long)]
pub api_server: bool,
}
#[derive(Debug, Clone, PartialEq, clap::Parser)]
@ -45,7 +102,6 @@ pub enum Subcommand {
Append(AppendCmd),
Init(InitCmd),
Daemon(DaemonCmd),
OpenApiDocs,
}
pub static DEFAULT_PATH: LazyLock<Arc<Path>> = LazyLock::new(|| {

View file

@ -1,7 +1,7 @@
use std::{
net::SocketAddr,
process::{Output, Stdio},
sync::LazyLock,
sync::{Arc, LazyLock},
};
use axum::{
@ -11,8 +11,9 @@ use axum::{
routing::post,
};
use tokio::{net::TcpListener, process::Command};
//use utoipa::{OpenApi as _, ToSchema, openapi::OpenApi};
//use utoipa_axum::router::{OpenApiRouter, UtoipaMethodRouterExt};
use utoipa::{OpenApi as _, ToSchema, openapi::OpenApi};
use utoipa_axum::router::{OpenApiRouter, UtoipaMethodRouterExt};
use utoipa_swagger_ui::SwaggerUi;
use serde::{Deserialize, Serialize};
@ -46,17 +47,30 @@ pub static NIX: LazyLock<&'static Path> = LazyLock::new(|| {
.unwrap_or(Path::new("/run/current-system/sw/bin/nix"))
});
pub const API_JSON_EP: &str = "/api-docs/openapi.json";
pub async fn run(config: Config) {
let addr = config.addr.clone();
let router = Router::new()
.route("/set", post(ep_set_post))
// `.with_state()` has to be last for the type inference to work.
.with_state(config);
//let (router, api): (Router, OpenApi) = OpenApiRouter::with_openapi(ApiDoc::openapi())
// .routes(utoipa_axum::routes!(ep_set_post))
// // `.with_state()` has to be last for the type inference works.
// .with_state(config)
// .split_for_parts();
let (router, api): (Router, OpenApi) = OpenApiRouter::with_openapi(DaemonApiDocs::openapi())
.routes(utoipa_axum::routes!(ep_set_post))
// `.with_state()` has to be last for the type inference works.
.with_state(config)
.split_for_parts();
let swagger = SwaggerUi::new("/swagger-ui").url(API_JSON_EP, DaemonApiDocs::openapi());
let router = router.merge(Router::from(swagger));
//trace!("Router constructed; API is {api:?}");
debug!(
"Router constructed, OpenAPI has {} path(s)",
api.paths.paths.len(),
);
//let router = Router::new()
// .route("/set", post(ep_set_post))
// // `.with_state()` has to be last for the type inference to work.
// .with_state(config);
let listener = TcpListener::bind(addr).await.unwrap();
@ -67,36 +81,95 @@ pub async fn run(config: Config) {
pub struct Config {
pub config_file: SourceFile,
pub addr: SocketAddr,
pub token: Option<String>,
pub token: Arc<Option<String>>,
}
#[derive(Debug, Clone, PartialEq, PartialOrd)]
#[derive(Deserialize, Serialize)]
//#[derive(ToSchema)]
#[derive(ToSchema)]
pub struct SetParams {
/// The name of the NixOS option to set, either as a dotted string, or a list of attribute path parts.
pub name: ConvenientAttrPath,
pub value: NixLiteral,
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[derive(Deserialize, Serialize)]
//#[derive(ToSchema)]
#[derive(ToSchema)]
#[schema(examples(
json!({
"status": 0,
"msg": null,
}),
json!({
"status": -1,
"msg": "No such file or directory",
}),
))]
pub struct SetResponse {
/// Will be 0 if everything is okay.
/// The exit code of the `nix` command that applied the configuration,
/// or a negative errno value if there was an error elsewhere.
///
/// Will be -1 for an error with no code.
pub status: i64,
/// General remarks. If an error occurred, this field is used for the error message.
pub msg: Option<String>,
}
#[axum::debug_handler]
//#[utoipa::path(
// post,
// path = "/set",
// responses(
// (status = 200, description = "Request was valid", body = SetResponse)
// ),
//)]
#[utoipa::path(
post,
path = "/set",
request_body(
content = inline(SetParams),
examples(
("Gotoscial" = (
value = json!({
"name": "services.gotosocial.settings.application-name",
"value": "My awesome Fedi instance!",
}),
description = "Set's Gotosocial's ActivityPub instance name to \"My awesome Fedi instance!\"",
)),
("Harmonia" = (
value = json!({
"name": ["services", "harmonia", "settings", "workers"],
"value": 20,
}),
description = "Configures Harmonia to use 20 workers for building",
))
),
),
responses(
// This syntax is wild.
(
status = OK,
body = inline(SetResponse),
description = indoc::indoc!{"
Request processed successfully. Check `status` for if the *operation* as a whole succeeded.
"},
examples(
("1. Success" = (
value = json!({
"status": 0,
"msg": null,
}),
description = "What you should see for normal success",
)),
("2. Command failure" = (
value = json!({
"status": 1,
"msg": "Stderr: error: cannot add a string to an integer",
})
))
)
),
(status = UNAUTHORIZED, description = indoc::indoc!{"
Server configured a required Authorization `token` and you provided the wrong one (or none at all)
<li>NOTE: this is currently unimplemented</li>
"}),
),
)]
async fn ep_set_post(
State(config): State<Config>,
headers: HeaderMap,
@ -104,7 +177,7 @@ async fn ep_set_post(
) -> Result<Json<SetResponse>, StatusCode> {
debug!("POST /set with name={name:?}, value={value:?}");
if let Some(token) = &config.token {
if let Some(token) = config.token.as_deref() {
let Some(auth) = headers.get(http::header::AUTHORIZATION) else {
// FIXME: technically RFC9110 requires us to respond with a
// `WWW-Authenticate` header.
@ -224,8 +297,8 @@ async fn nix_run_apply(config: &Config) -> Result<Output, IoError> {
Ok(output)
}
//#[derive(Copy)]
//#[derive(Debug, Clone, PartialEq)]
//#[derive(utoipa::OpenApi)]
//#[openapi(paths(ep_set_post))]
//pub struct ApiDoc;
#[derive(Copy)]
#[derive(Debug, Clone, PartialEq)]
#[derive(utoipa::OpenApi)]
#[openapi(paths(ep_set_post))]
pub struct DaemonApiDocs;

View file

@ -12,10 +12,19 @@ mod impls;
/// This type does not provide a [`Default`] impl, however.
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[derive(Deserialize, Serialize)]
#[derive(ToSchema)]
#[serde(untagged)]
#[derive(ToSchema)]
#[schema(as = AttrPath, description = "Nix attribute path", title = "attrpath")]
pub enum ConvenientAttrPath {
#[schema(
title = "Dotted",
example = "services.gotosocial.settings.application-name"
)]
Dotted(Box<str>),
#[schema(
title = "Split",
example = json!(["services", "gotosocial", "settings", "application-name"]),
)]
Split(Box<[Box<str>]>),
}

View file

@ -139,6 +139,18 @@ pub fn do_append(args: Arc<Args>, append_args: AppendCmd) -> Result<(), BoxDynEr
//#[tracing::instrument(level = "debug")]
pub fn do_daemon(args: Arc<Args>, daemon_args: DaemonCmd) -> Result<(), BoxDynError> {
if let Some(dest) = daemon_args.apidocs {
let openapi = <daemon::DaemonApiDocs as utoipa::OpenApi>::openapi();
let as_json = openapi.to_pretty_json().unwrap();
if dest.is_stdout() {
println!("{}", as_json);
}
todo!("Generate API docs");
info!("Generated API docs");
return Ok(());
}
let config_file: Arc<Path> = Arc::clone(&args.file);
// FIXME: make configurable?
@ -150,7 +162,7 @@ pub fn do_daemon(args: Arc<Args>, daemon_args: DaemonCmd) -> Result<(), BoxDynEr
config_file: SourceFile::new(config_file).unwrap(),
addr: daemon_args.bind,
// FIXME
token: None,
token: Arc::new(None),
};
rt.block_on(async move {

View file

@ -45,10 +45,10 @@ fn main_wrapped() -> Result<(), Box<dyn StdError + Send + Sync + 'static>> {
Append(append_args) => dynix::do_append(args.clone(), append_args.clone())?,
Daemon(daemon_args) => dynix::do_daemon(args.clone(), daemon_args.clone())?,
Init(init_args) => dynix::do_init(args.clone(), init_args.clone())?,
OpenApiDocs => {
//let api = dynix::ApiDoc::openapi();
//dbg!(api);
},
//OpenApiDocs => {
// //let api = dynix::ApiDoc::openapi();
// //dbg!(api);
//},
};
}