Add openapi docs

This commit is contained in:
Oystein Kristoffer Tveit 2024-10-30 01:29:09 +01:00
parent 9934b11766
commit e79775608f
Signed by: oysteikt
GPG Key ID: 9F2F7D8250F35146
5 changed files with 695 additions and 70 deletions

504
Cargo.lock generated
View File

@ -96,6 +96,15 @@ version = "1.0.90"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37bf3594c4c988a53154954629820791dde498571819ae4ca50ca811e060cc95" checksum = "37bf3594c4c988a53154954629820791dde498571819ae4ca50ca811e060cc95"
[[package]]
name = "arbitrary"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110"
dependencies = [
"derive_arbitrary",
]
[[package]] [[package]]
name = "async-compression" name = "async-compression"
version = "0.4.17" version = "0.4.17"
@ -131,19 +140,20 @@ checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
[[package]] [[package]]
name = "axum" name = "axum"
version = "0.6.20" version = "0.7.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf" checksum = "504e3947307ac8326a5437504c517c4b56716c9d98fac0028c2acc7ca47d70ae"
dependencies = [ dependencies = [
"async-trait", "async-trait",
"axum-core", "axum-core",
"axum-macros", "axum-macros",
"bitflags 1.3.2",
"bytes", "bytes",
"futures-util", "futures-util",
"http", "http 1.1.0",
"http-body", "http-body 1.0.1",
"http-body-util",
"hyper", "hyper",
"hyper-util",
"itoa", "itoa",
"matchit", "matchit",
"memchr", "memchr",
@ -155,37 +165,41 @@ dependencies = [
"serde_json", "serde_json",
"serde_path_to_error", "serde_path_to_error",
"serde_urlencoded", "serde_urlencoded",
"sync_wrapper", "sync_wrapper 1.0.1",
"tokio", "tokio",
"tower", "tower 0.5.1",
"tower-layer", "tower-layer",
"tower-service", "tower-service",
"tracing",
] ]
[[package]] [[package]]
name = "axum-core" name = "axum-core"
version = "0.3.4" version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "759fa577a247914fd3f7f76d62972792636412fbfd634cd452f6a385a74d2d2c" checksum = "09f2bd6146b97ae3359fa0cc6d6b376d9539582c7b4220f041a33ec24c226199"
dependencies = [ dependencies = [
"async-trait", "async-trait",
"bytes", "bytes",
"futures-util", "futures-util",
"http", "http 1.1.0",
"http-body", "http-body 1.0.1",
"http-body-util",
"mime", "mime",
"pin-project-lite",
"rustversion", "rustversion",
"sync_wrapper 1.0.1",
"tower-layer", "tower-layer",
"tower-service", "tower-service",
"tracing",
] ]
[[package]] [[package]]
name = "axum-macros" name = "axum-macros"
version = "0.3.8" version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdca6a10ecad987bda04e95606ef85a5417dcaac1a78455242d72e031e2b6b62" checksum = "57d123550fa8d071b7255cb0cc04dc302baa6c8c4a79f55701552684d8399bce"
dependencies = [ dependencies = [
"heck 0.4.1",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn",
@ -212,18 +226,21 @@ version = "0.21.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567"
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]] [[package]]
name = "bitflags" name = "bitflags"
version = "2.6.0" version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
[[package]]
name = "block-buffer"
version = "0.10.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
dependencies = [
"generic-array",
]
[[package]] [[package]]
name = "brotli" name = "brotli"
version = "7.0.0" version = "7.0.0"
@ -245,6 +262,12 @@ dependencies = [
"alloc-stdlib", "alloc-stdlib",
] ]
[[package]]
name = "bumpalo"
version = "3.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
[[package]] [[package]]
name = "byteorder" name = "byteorder"
version = "1.5.0" version = "1.5.0"
@ -312,7 +335,7 @@ version = "4.5.18"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab"
dependencies = [ dependencies = [
"heck 0.5.0", "heck",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn",
@ -330,6 +353,15 @@ version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0"
[[package]]
name = "cpufeatures"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0"
dependencies = [
"libc",
]
[[package]] [[package]]
name = "crc32fast" name = "crc32fast"
version = "1.4.2" version = "1.4.2"
@ -339,6 +371,54 @@ dependencies = [
"cfg-if", "cfg-if",
] ]
[[package]]
name = "crossbeam-utils"
version = "0.8.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80"
[[package]]
name = "crypto-common"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
dependencies = [
"generic-array",
"typenum",
]
[[package]]
name = "derive_arbitrary"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611"
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 = "displaydoc"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]] [[package]]
name = "env_logger" name = "env_logger"
version = "0.10.2" version = "0.10.2"
@ -352,6 +432,12 @@ dependencies = [
"termcolor", "termcolor",
] ]
[[package]]
name = "equivalent"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
[[package]] [[package]]
name = "errno" name = "errno"
version = "0.3.9" version = "0.3.9"
@ -482,6 +568,16 @@ dependencies = [
"slab", "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]] [[package]]
name = "getrandom" name = "getrandom"
version = "0.2.15" version = "0.2.15"
@ -516,8 +612,11 @@ dependencies = [
"systemd-journal-logger", "systemd-journal-logger",
"tempfile", "tempfile",
"tokio", "tokio",
"tower", "tower 0.4.13",
"tower-http", "tower-http",
"utoipa",
"utoipa-axum",
"utoipa-swagger-ui",
] ]
[[package]] [[package]]
@ -526,6 +625,12 @@ version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
[[package]]
name = "hashbrown"
version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb"
[[package]] [[package]]
name = "hdrhistogram" name = "hdrhistogram"
version = "7.5.4" version = "7.5.4"
@ -536,12 +641,6 @@ dependencies = [
"num-traits", "num-traits",
] ]
[[package]]
name = "heck"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
[[package]] [[package]]
name = "heck" name = "heck"
version = "0.5.0" version = "0.5.0"
@ -571,6 +670,17 @@ dependencies = [
"itoa", "itoa",
] ]
[[package]]
name = "http"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258"
dependencies = [
"bytes",
"fnv",
"itoa",
]
[[package]] [[package]]
name = "http-body" name = "http-body"
version = "0.4.6" version = "0.4.6"
@ -578,7 +688,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2"
dependencies = [ dependencies = [
"bytes", "bytes",
"http", "http 0.2.12",
"pin-project-lite",
]
[[package]]
name = "http-body"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184"
dependencies = [
"bytes",
"http 1.1.0",
]
[[package]]
name = "http-body-util"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f"
dependencies = [
"bytes",
"futures-util",
"http 1.1.0",
"http-body 1.0.1",
"pin-project-lite", "pin-project-lite",
] ]
@ -608,25 +741,47 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
[[package]] [[package]]
name = "hyper" name = "hyper"
version = "0.14.31" version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c08302e8fa335b151b788c775ff56e7a03ae64ff85c548ee820fecb70356e85" checksum = "bbbff0a806a4728c99295b254c8838933b5b082d75e3cb70c8dab21fdfbcfa9a"
dependencies = [ dependencies = [
"bytes", "bytes",
"futures-channel", "futures-channel",
"futures-core",
"futures-util", "futures-util",
"http", "http 1.1.0",
"http-body", "http-body 1.0.1",
"httparse", "httparse",
"httpdate", "httpdate",
"itoa", "itoa",
"pin-project-lite", "pin-project-lite",
"socket2", "smallvec",
"tokio",
]
[[package]]
name = "hyper-util"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41296eb09f183ac68eec06e03cdbea2e759633d4067b2f6552fc2e009bcad08b"
dependencies = [
"bytes",
"futures-util",
"http 1.1.0",
"http-body 1.0.1",
"hyper",
"pin-project-lite",
"tokio", "tokio",
"tower-service", "tower-service",
"tracing", ]
"want",
[[package]]
name = "idna"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6"
dependencies = [
"unicode-bidi",
"unicode-normalization",
] ]
[[package]] [[package]]
@ -636,7 +791,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
dependencies = [ dependencies = [
"autocfg", "autocfg",
"hashbrown", "hashbrown 0.12.3",
]
[[package]]
name = "indexmap"
version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da"
dependencies = [
"equivalent",
"hashbrown 0.15.0",
"serde",
] ]
[[package]] [[package]]
@ -703,6 +869,12 @@ dependencies = [
"scopeguard", "scopeguard",
] ]
[[package]]
name = "lockfree-object-pool"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9374ef4228402d4b7e403e5838cb880d9ee663314b0a900d5a6aabf0c213552e"
[[package]] [[package]]
name = "log" name = "log"
version = "0.4.22" version = "0.4.22"
@ -820,6 +992,12 @@ dependencies = [
"windows-targets", "windows-targets",
] ]
[[package]]
name = "paste"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
[[package]] [[package]]
name = "percent-encoding" name = "percent-encoding"
version = "2.3.1" version = "2.3.1"
@ -927,7 +1105,7 @@ version = "0.5.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f"
dependencies = [ dependencies = [
"bitflags 2.6.0", "bitflags",
] ]
[[package]] [[package]]
@ -959,6 +1137,40 @@ version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
[[package]]
name = "rust-embed"
version = "8.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa66af4a4fdd5e7ebc276f115e895611a34739a9c1c01028383d612d550953c0"
dependencies = [
"rust-embed-impl",
"rust-embed-utils",
"walkdir",
]
[[package]]
name = "rust-embed-impl"
version = "8.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6125dbc8867951125eec87294137f4e9c2c96566e61bf72c45095a7c77761478"
dependencies = [
"proc-macro2",
"quote",
"rust-embed-utils",
"syn",
"walkdir",
]
[[package]]
name = "rust-embed-utils"
version = "8.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2e5347777e9aacb56039b0e1f28785929a8a3b709e87482e7442c72e7c12529d"
dependencies = [
"sha2",
"walkdir",
]
[[package]] [[package]]
name = "rustc-demangle" name = "rustc-demangle"
version = "0.1.24" version = "0.1.24"
@ -971,7 +1183,7 @@ version = "0.38.37"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811" checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811"
dependencies = [ dependencies = [
"bitflags 2.6.0", "bitflags",
"errno", "errno",
"libc", "libc",
"linux-raw-sys", "linux-raw-sys",
@ -990,6 +1202,15 @@ version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
[[package]]
name = "same-file"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
dependencies = [
"winapi-util",
]
[[package]] [[package]]
name = "scopeguard" name = "scopeguard"
version = "1.2.0" version = "1.2.0"
@ -1056,6 +1277,17 @@ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "sha2"
version = "0.10.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8"
dependencies = [
"cfg-if",
"cpufeatures",
"digest",
]
[[package]] [[package]]
name = "shlex" name = "shlex"
version = "1.3.0" version = "1.3.0"
@ -1071,6 +1303,12 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "simd-adler32"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe"
[[package]] [[package]]
name = "slab" name = "slab"
version = "0.4.9" version = "0.4.9"
@ -1119,6 +1357,12 @@ version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160"
[[package]]
name = "sync_wrapper"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394"
[[package]] [[package]]
name = "systemd-journal-logger" name = "systemd-journal-logger"
version = "2.2.0" version = "2.2.0"
@ -1171,6 +1415,21 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "tinyvec"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938"
dependencies = [
"tinyvec_macros",
]
[[package]]
name = "tinyvec_macros"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]] [[package]]
name = "tokio" name = "tokio"
version = "1.40.0" version = "1.40.0"
@ -1234,7 +1493,7 @@ dependencies = [
"futures-core", "futures-core",
"futures-util", "futures-util",
"hdrhistogram", "hdrhistogram",
"indexmap", "indexmap 1.9.3",
"pin-project", "pin-project",
"pin-project-lite", "pin-project-lite",
"rand", "rand",
@ -1246,6 +1505,22 @@ dependencies = [
"tracing", "tracing",
] ]
[[package]]
name = "tower"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2873938d487c3cfb9aed7546dc9f2711d867c9f90c46b889989a2cb84eba6b4f"
dependencies = [
"futures-core",
"futures-util",
"pin-project-lite",
"sync_wrapper 0.1.2",
"tokio",
"tower-layer",
"tower-service",
"tracing",
]
[[package]] [[package]]
name = "tower-http" name = "tower-http"
version = "0.4.4" version = "0.4.4"
@ -1254,12 +1529,12 @@ checksum = "61c5bb1d698276a2443e5ecfabc1008bf15a36c12e6a7176e7bf089ea9131140"
dependencies = [ dependencies = [
"async-compression", "async-compression",
"base64", "base64",
"bitflags 2.6.0", "bitflags",
"bytes", "bytes",
"futures-core", "futures-core",
"futures-util", "futures-util",
"http", "http 0.2.12",
"http-body", "http-body 0.4.6",
"http-range-header", "http-range-header",
"httpdate", "httpdate",
"iri-string", "iri-string",
@ -1269,7 +1544,7 @@ dependencies = [
"pin-project-lite", "pin-project-lite",
"tokio", "tokio",
"tokio-util", "tokio-util",
"tower", "tower 0.4.13",
"tower-layer", "tower-layer",
"tower-service", "tower-service",
"tracing", "tracing",
@ -1309,10 +1584,10 @@ dependencies = [
] ]
[[package]] [[package]]
name = "try-lock" name = "typenum"
version = "0.2.5" version = "1.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
[[package]] [[package]]
name = "unicase" name = "unicase"
@ -1320,18 +1595,105 @@ version = "2.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e51b68083f157f853b6379db119d1c1be0e6e4dec98101079dec41f6f5cf6df" checksum = "7e51b68083f157f853b6379db119d1c1be0e6e4dec98101079dec41f6f5cf6df"
[[package]]
name = "unicode-bidi"
version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ab17db44d7388991a428b2ee655ce0c212e862eff1768a455c58f9aad6e7893"
[[package]] [[package]]
name = "unicode-ident" name = "unicode-ident"
version = "1.0.13" version = "1.0.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"
[[package]]
name = "unicode-normalization"
version = "0.1.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956"
dependencies = [
"tinyvec",
]
[[package]]
name = "url"
version = "2.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c"
dependencies = [
"form_urlencoded",
"idna",
"percent-encoding",
]
[[package]] [[package]]
name = "utf8parse" name = "utf8parse"
version = "0.2.2" version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]]
name = "utoipa"
version = "5.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d9ba0ade4e2f024cd1842dfbaf9dbc540639fc082299acf7649d71bd14eaca3"
dependencies = [
"indexmap 2.6.0",
"serde",
"serde_json",
"utoipa-gen",
]
[[package]]
name = "utoipa-axum"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1370cc4a8eee751c4d2a729566d83d1568212320a20581c7c72c2d76ab80ed37"
dependencies = [
"axum",
"paste",
"tower-layer",
"tower-service",
"utoipa",
]
[[package]]
name = "utoipa-gen"
version = "5.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4cf390d6503c9c9eac988447c38ba934a707b0b768b14511a493b4fc0e8ecb00"
dependencies = [
"proc-macro2",
"quote",
"regex",
"syn",
]
[[package]]
name = "utoipa-swagger-ui"
version = "8.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a5c80b4dd79ea382e8374d67dcce22b5c6663fa13a82ad3886441d1bbede5e35"
dependencies = [
"axum",
"mime_guess",
"regex",
"rust-embed",
"serde",
"serde_json",
"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]] [[package]]
name = "uuid" name = "uuid"
version = "1.11.0" version = "1.11.0"
@ -1342,12 +1704,19 @@ dependencies = [
] ]
[[package]] [[package]]
name = "want" name = "version_check"
version = "0.3.1" version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
[[package]]
name = "walkdir"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
dependencies = [ dependencies = [
"try-lock", "same-file",
"winapi-util",
] ]
[[package]] [[package]]
@ -1468,6 +1837,37 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "zip"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc5e4288ea4057ae23afc69a4472434a87a2495cafce6632fd1c4ec9f5cf3494"
dependencies = [
"arbitrary",
"crc32fast",
"crossbeam-utils",
"displaydoc",
"flate2",
"indexmap 2.6.0",
"memchr",
"thiserror",
"zopfli",
]
[[package]]
name = "zopfli"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5019f391bac5cf252e93bbcc53d039ffd62c7bfb7c150414d61369afe57e946"
dependencies = [
"bumpalo",
"crc32fast",
"lockfree-object-pool",
"log",
"once_cell",
"simd-adler32",
]
[[package]] [[package]]
name = "zstd" name = "zstd"
version = "0.13.2" version = "0.13.2"

View File

@ -10,7 +10,7 @@ readme = "README.md"
[dependencies] [dependencies]
anyhow = "1.0.82" anyhow = "1.0.82"
axum = { version = "0.6.20", features = ["macros"] } axum = { version = "0.7.7", features = ["macros"] }
clap = { version = "4.4.1", features = ["derive"] } clap = { version = "4.4.1", features = ["derive"] }
clap-verbosity-flag = "2.2.2" clap-verbosity-flag = "2.2.2"
env_logger = "0.10.0" env_logger = "0.10.0"
@ -24,6 +24,9 @@ tempfile = "3.11.0"
tokio = { version = "1.32.0", features = ["full"] } tokio = { version = "1.32.0", features = ["full"] }
tower = { version = "0.4.13", features = ["full"] } tower = { version = "0.4.13", features = ["full"] }
tower-http = { version = "0.4.3", features = ["full"] } tower-http = { version = "0.4.3", features = ["full"] }
utoipa = { version = "5.1.3", features = ["axum_extras"] }
utoipa-axum = "0.1.2"
utoipa-swagger-ui = { version = "8.0.3", features = ["axum", "vendored"] }
[profile.release] [profile.release]
strip = true strip = true

View File

@ -1,4 +1,4 @@
mod base; mod base;
mod rest_wrapper_v1; mod rest_wrapper_v1;
pub use rest_wrapper_v1::rest_api_routes; pub use rest_wrapper_v1::{rest_api_routes, rest_api_docs};

View File

@ -8,6 +8,10 @@ use axum::{
use mpvipc_async::Mpv; use mpvipc_async::Mpv;
use serde_json::{json, Value}; use serde_json::{json, Value};
use utoipa::OpenApi;
use utoipa_axum::{router::OpenApiRouter, routes};
use utoipa_swagger_ui::SwaggerUi;
use super::base; use super::base;
pub fn rest_api_routes(mpv: Mpv) -> Router { pub fn rest_api_routes(mpv: Mpv) -> Router {
@ -31,6 +35,63 @@ pub fn rest_api_routes(mpv: Mpv) -> Router {
.with_state(mpv) .with_state(mpv)
} }
pub fn rest_api_docs(mpv: Mpv) -> Router {
let (router, api) = OpenApiRouter::with_openapi(ApiDoc::openapi())
.routes(routes!(loadfile))
.routes(routes!(play_get, play_set))
.routes(routes!(volume_get, volume_set))
.routes(routes!(time_get, time_set))
.routes(routes!(
playlist_get,
playlist_remove_or_clear
))
.routes(routes!(playlist_next))
.routes(routes!(playlist_previous))
.routes(routes!(playlist_goto))
.routes(routes!(playlist_move))
.routes(routes!(playlist_get_looping, playlist_set_looping))
.routes(routes!(shuffle))
.with_state(mpv)
.split_for_parts();
router.merge(SwaggerUi::new("/docs").url("/docs/openapi.json", api))
}
#[derive(OpenApi)]
#[openapi(
info(
description = "The legacy Grzegorz Brzeczyszczykiewicz API, used to control a running mpv instance",
version = "1.0.0",
),
)]
struct ApiDoc;
#[derive(serde::Serialize, utoipa::ToSchema)]
struct EmptySuccessResponse {
success: bool,
error: bool,
}
#[derive(serde::Serialize, utoipa::ToSchema)]
struct SuccessResponse {
#[schema(example = true)]
success: bool,
#[schema(example = false)]
error: bool,
#[schema(example = json!({ some: "arbitrary json value" }))]
value: Value,
}
#[derive(serde::Serialize, utoipa::ToSchema)]
struct ErrorResponse {
#[schema(example = "error....")]
error: String,
#[schema(example = "error....")]
errortext: String,
#[schema(example = false)]
success: bool,
}
pub struct RestResponse(anyhow::Result<Value>); pub struct RestResponse(anyhow::Result<Value>);
impl From<anyhow::Result<Value>> for RestResponse { impl From<anyhow::Result<Value>> for RestResponse {
@ -64,73 +125,178 @@ impl IntoResponse for RestResponse {
// TODO: These could possibly be generated with a proc macro // TODO: These could possibly be generated with a proc macro
#[derive(serde::Deserialize)] #[derive(serde::Deserialize, utoipa::IntoParams)]
struct LoadFileArgs { struct LoadFileArgs {
path: String, path: String,
} }
/// Add item to playlist
#[utoipa::path(
post,
path = "/load",
params(LoadFileArgs),
responses(
(status = 200, description = "Success", body = EmptySuccessResponse),
(status = 500, description = "Internal server error", body = ErrorResponse),
)
)]
async fn loadfile(State(mpv): State<Mpv>, Query(query): Query<LoadFileArgs>) -> RestResponse { async fn loadfile(State(mpv): State<Mpv>, Query(query): Query<LoadFileArgs>) -> RestResponse {
base::loadfile(mpv, &query.path).await.into() base::loadfile(mpv, &query.path).await.into()
} }
/// Check whether the player is paused or playing
#[utoipa::path(
get,
path = "/play",
responses(
(status = 200, description = "Success", body = SuccessResponse),
(status = 500, description = "Internal server error", body = ErrorResponse),
)
)]
async fn play_get(State(mpv): State<Mpv>) -> RestResponse { async fn play_get(State(mpv): State<Mpv>) -> RestResponse {
base::play_get(mpv).await.into() base::play_get(mpv).await.into()
} }
#[derive(serde::Deserialize)] #[derive(serde::Deserialize, utoipa::IntoParams)]
struct PlaySetArgs { struct PlaySetArgs {
play: String, play: String,
} }
/// Set whether the player is paused or playing
#[utoipa::path(
post,
path = "/play",
params(PlaySetArgs),
responses(
(status = 200, description = "Success", body = Value, content_type = "application/json"),
(status = 500, description = "Internal server error", body = Value, content_type = "application/json"),
)
)]
async fn play_set(State(mpv): State<Mpv>, Query(query): Query<PlaySetArgs>) -> RestResponse { async fn play_set(State(mpv): State<Mpv>, Query(query): Query<PlaySetArgs>) -> RestResponse {
let play = query.play.to_lowercase() == "true"; let play = query.play.to_lowercase() == "true";
base::play_set(mpv, play).await.into() base::play_set(mpv, play).await.into()
} }
/// Get the current player volume
#[utoipa::path(
get,
path = "/volume",
responses(
(status = 200, description = "Success", body = Value, content_type = "application/json"),
(status = 500, description = "Internal server error", body = Value, content_type = "application/json"),
)
)]
async fn volume_get(State(mpv): State<Mpv>) -> RestResponse { async fn volume_get(State(mpv): State<Mpv>) -> RestResponse {
base::volume_get(mpv).await.into() base::volume_get(mpv).await.into()
} }
#[derive(serde::Deserialize)] #[derive(serde::Deserialize, utoipa::IntoParams)]
struct VolumeSetArgs { struct VolumeSetArgs {
volume: f64, volume: f64,
} }
/// Set the player volume
#[utoipa::path(
post,
path = "/volume",
params(VolumeSetArgs),
responses(
(status = 200, description = "Success", body = Value, content_type = "application/json"),
(status = 500, description = "Internal server error", body = Value, content_type = "application/json"),
)
)]
async fn volume_set(State(mpv): State<Mpv>, Query(query): Query<VolumeSetArgs>) -> RestResponse { async fn volume_set(State(mpv): State<Mpv>, Query(query): Query<VolumeSetArgs>) -> RestResponse {
base::volume_set(mpv, query.volume).await.into() base::volume_set(mpv, query.volume).await.into()
} }
/// Get current playback position
#[utoipa::path(
get,
path = "/time",
responses(
(status = 200, description = "Success", body = Value, content_type = "application/json"),
(status = 500, description = "Internal server error", body = Value, content_type = "application/json"),
)
)]
async fn time_get(State(mpv): State<Mpv>) -> RestResponse { async fn time_get(State(mpv): State<Mpv>) -> RestResponse {
base::time_get(mpv).await.into() base::time_get(mpv).await.into()
} }
#[derive(serde::Deserialize)] #[derive(serde::Deserialize, utoipa::IntoParams)]
struct TimeSetArgs { struct TimeSetArgs {
pos: Option<f64>, pos: Option<f64>,
percent: Option<f64>, percent: Option<f64>,
} }
/// Set playback position
#[utoipa::path(
post,
path = "/time",
params(TimeSetArgs),
responses(
(status = 200, description = "Success", body = Value, content_type = "application/json"),
(status = 500, description = "Internal server error", body = Value, content_type = "application/json"),
)
)]
async fn time_set(State(mpv): State<Mpv>, Query(query): Query<TimeSetArgs>) -> RestResponse { async fn time_set(State(mpv): State<Mpv>, Query(query): Query<TimeSetArgs>) -> RestResponse {
base::time_set(mpv, query.pos, query.percent).await.into() base::time_set(mpv, query.pos, query.percent).await.into()
} }
/// Get the current playlist
#[utoipa::path(
get,
path = "/playlist",
responses(
(status = 200, description = "Success", body = Value, content_type = "application/json"),
(status = 500, description = "Internal server error", body = Value, content_type = "application/json"),
)
)]
async fn playlist_get(State(mpv): State<Mpv>) -> RestResponse { async fn playlist_get(State(mpv): State<Mpv>) -> RestResponse {
base::playlist_get(mpv).await.into() base::playlist_get(mpv).await.into()
} }
/// Go to the next item in the playlist
#[utoipa::path(
post,
path = "/playlist/next",
responses(
(status = 200, description = "Success", body = Value, content_type = "application/json"),
(status = 500, description = "Internal server error", body = Value, content_type = "application/json"),
)
)]
async fn playlist_next(State(mpv): State<Mpv>) -> RestResponse { async fn playlist_next(State(mpv): State<Mpv>) -> RestResponse {
base::playlist_next(mpv).await.into() base::playlist_next(mpv).await.into()
} }
/// Go back to the previous item in the playlist
#[utoipa::path(
post,
path = "/playlist/previous",
responses(
(status = 200, description = "Success", body = Value, content_type = "application/json"),
(status = 500, description = "Internal server error", body = Value, content_type = "application/json"),
)
)]
async fn playlist_previous(State(mpv): State<Mpv>) -> RestResponse { async fn playlist_previous(State(mpv): State<Mpv>) -> RestResponse {
base::playlist_previous(mpv).await.into() base::playlist_previous(mpv).await.into()
} }
#[derive(serde::Deserialize)] #[derive(serde::Deserialize, utoipa::IntoParams)]
struct PlaylistGotoArgs { struct PlaylistGotoArgs {
index: usize, index: usize,
} }
/// Go to a specific item in the playlist
#[utoipa::path(
post,
path = "/playlist/goto",
params(PlaylistGotoArgs),
responses(
(status = 200, description = "Success", body = Value, content_type = "application/json"),
(status = 500, description = "Internal server error", body = Value, content_type = "application/json"),
)
)]
async fn playlist_goto( async fn playlist_goto(
State(mpv): State<Mpv>, State(mpv): State<Mpv>,
Query(query): Query<PlaylistGotoArgs>, Query(query): Query<PlaylistGotoArgs>,
@ -138,11 +304,21 @@ async fn playlist_goto(
base::playlist_goto(mpv, query.index).await.into() base::playlist_goto(mpv, query.index).await.into()
} }
#[derive(serde::Deserialize)] #[derive(serde::Deserialize, utoipa::IntoParams)]
struct PlaylistRemoveOrClearArgs { struct PlaylistRemoveOrClearArgs {
index: Option<usize>, index: Option<usize>,
} }
/// Clears a single item or the entire playlist
#[utoipa::path(
delete,
path = "/playlist",
params(PlaylistRemoveOrClearArgs),
responses(
(status = 200, description = "Success", body = Value, content_type = "application/json"),
(status = 500, description = "Internal server error", body = Value, content_type = "application/json"),
)
)]
async fn playlist_remove_or_clear( async fn playlist_remove_or_clear(
State(mpv): State<Mpv>, State(mpv): State<Mpv>,
Query(query): Query<PlaylistRemoveOrClearArgs>, Query(query): Query<PlaylistRemoveOrClearArgs>,
@ -153,12 +329,22 @@ async fn playlist_remove_or_clear(
} }
} }
#[derive(serde::Deserialize)] #[derive(serde::Deserialize, utoipa::IntoParams)]
struct PlaylistMoveArgs { struct PlaylistMoveArgs {
index1: usize, index1: usize,
index2: usize, index2: usize,
} }
/// Move a playlist item to a different position
#[utoipa::path(
post,
path = "/playlist/move",
params(PlaylistMoveArgs),
responses(
(status = 200, description = "Success", body = Value, content_type = "application/json"),
(status = 500, description = "Internal server error", body = Value, content_type = "application/json"),
)
)]
async fn playlist_move( async fn playlist_move(
State(mpv): State<Mpv>, State(mpv): State<Mpv>,
Query(query): Query<PlaylistMoveArgs>, Query(query): Query<PlaylistMoveArgs>,
@ -168,19 +354,47 @@ async fn playlist_move(
.into() .into()
} }
/// Shuffle the playlist
#[utoipa::path(
post,
path = "/playlist/shuffle",
responses(
(status = 200, description = "Success", body = Value, content_type = "application/json"),
(status = 500, description = "Internal server error", body = Value, content_type = "application/json"),
)
)]
async fn shuffle(State(mpv): State<Mpv>) -> RestResponse { async fn shuffle(State(mpv): State<Mpv>) -> RestResponse {
base::shuffle(mpv).await.into() base::shuffle(mpv).await.into()
} }
/// Check whether the playlist is looping
#[utoipa::path(
get,
path = "/playlist/loop",
responses(
(status = 200, description = "Success", body = Value, content_type = "application/json"),
(status = 500, description = "Internal server error", body = Value, content_type = "application/json"),
)
)]
async fn playlist_get_looping(State(mpv): State<Mpv>) -> RestResponse { async fn playlist_get_looping(State(mpv): State<Mpv>) -> RestResponse {
base::playlist_get_looping(mpv).await.into() base::playlist_get_looping(mpv).await.into()
} }
#[derive(serde::Deserialize)] #[derive(serde::Deserialize, utoipa::IntoParams)]
struct PlaylistSetLoopingArgs { struct PlaylistSetLoopingArgs {
r#loop: bool, r#loop: bool,
} }
/// Set whether the playlist should loop
#[utoipa::path(
post,
path = "/playlist/loop",
params(PlaylistSetLoopingArgs),
responses(
(status = 200, description = "Success", body = Value, content_type = "application/json"),
(status = 500, description = "Internal server error", body = Value, content_type = "application/json"),
)
)]
async fn playlist_set_looping( async fn playlist_set_looping(
State(mpv): State<Mpv>, State(mpv): State<Mpv>,
Query(query): Query<PlaylistSetLoopingArgs>, Query(query): Query<PlaylistSetLoopingArgs>,

View File

@ -1,5 +1,5 @@
use anyhow::Context; use anyhow::Context;
use axum::{Router, Server}; use axum::Router;
use clap::Parser; use clap::Parser;
use clap_verbosity_flag::Verbosity; use clap_verbosity_flag::Verbosity;
use mpv_setup::{connect_to_mpv, create_mpv_config_file, show_grzegorz_image}; use mpv_setup::{connect_to_mpv, create_mpv_config_file, show_grzegorz_image};
@ -89,8 +89,12 @@ async fn setup_systemd_watchdog_thread() -> anyhow::Result<()> {
async fn shutdown(mpv: Mpv, proc: Option<tokio::process::Child>) { async fn shutdown(mpv: Mpv, proc: Option<tokio::process::Child>) {
log::info!("Shutting down"); log::info!("Shutting down");
sd_notify::notify(false, &[sd_notify::NotifyState::Stopping]) sd_notify::notify(false, &[sd_notify::NotifyState::Stopping]).unwrap_or_else(|e| {
.unwrap_or_else(|e| log::warn!("Failed to notify systemd that the service is stopping: {}", e)); log::warn!(
"Failed to notify systemd that the service is stopping: {}",
e
)
});
mpv.disconnect() mpv.disconnect()
.await .await
@ -156,11 +160,15 @@ async fn main() -> anyhow::Result<()> {
let socket_addr = SocketAddr::new(addr, args.port); let socket_addr = SocketAddr::new(addr, args.port);
log::info!("Starting API on {}", socket_addr); log::info!("Starting API on {}", socket_addr);
let app = Router::new().nest("/api", api::rest_api_routes(mpv.clone())); let app = Router::new()
let server = match Server::try_bind(&socket_addr.clone()) .nest("/api", api::rest_api_routes(mpv.clone()))
.merge(api::rest_api_docs(mpv.clone()));
let listener = match tokio::net::TcpListener::bind(&socket_addr)
.await
.context(format!("Failed to bind API server to '{}'", &socket_addr)) .context(format!("Failed to bind API server to '{}'", &socket_addr))
{ {
Ok(server) => server, Ok(listener) => listener,
Err(e) => { Err(e) => {
log::error!("{}", e); log::error!("{}", e);
shutdown(mpv, proc).await; shutdown(mpv, proc).await;
@ -191,7 +199,7 @@ async fn main() -> anyhow::Result<()> {
log::info!("Received Ctrl-C, exiting"); log::info!("Received Ctrl-C, exiting");
shutdown(mpv, Some(proc)).await; shutdown(mpv, Some(proc)).await;
} }
result = server.serve(app.into_make_service()) => { result = axum::serve(listener, app.into_make_service()) => {
log::info!("API server exited"); log::info!("API server exited");
shutdown(mpv, Some(proc)).await; shutdown(mpv, Some(proc)).await;
result?; result?;
@ -203,7 +211,7 @@ async fn main() -> anyhow::Result<()> {
log::info!("Received Ctrl-C, exiting"); log::info!("Received Ctrl-C, exiting");
shutdown(mpv.clone(), None).await; shutdown(mpv.clone(), None).await;
} }
result = server.serve(app.into_make_service()) => { result = axum::serve(listener, app.into_make_service()) => {
log::info!("API server exited"); log::info!("API server exited");
shutdown(mpv.clone(), None).await; shutdown(mpv.clone(), None).await;
result?; result?;