From a26841c30a0ec0d3f3ae4828fc7bc0045ce6b906 Mon Sep 17 00:00:00 2001 From: Ava Hahn Date: Mon, 22 Apr 2024 13:26:34 -0700 Subject: [PATCH 01/16] add CLI to unit repo * Pull in entire unit-rust-sdk project * Not included: CLA, COC, License * Not included: duplicate openapi spec * Not included: CI workflows Co-authored-by: Elijah Zupancic Signed-off-by: Ava Hahn --- cli/.cargo/config.toml | 2 + cli/.gitignore | 111 + cli/Cargo.lock | 1706 ++++++++ cli/Cargo.toml | 8 + cli/Containerfile.debian | 35 + cli/GNUmakefile | 140 + cli/HomebrewFormula | 1 + cli/README.md | 135 + cli/build/changelog.sh | 52 + cli/build/container.mk | 46 + cli/build/github.mk | 21 + cli/build/openapi-generator-cli.sh | 77 + cli/build/package.mk | 131 + cli/build/release.mk | 53 + cli/man/unitctl.1 | 30 + cli/openapi-config.json | 6 + cli/pkg/brew/unitctl.rb | 29 + cli/pkg/brew/unitctl.rb.template | 29 + cli/rustfmt.toml | 1 + cli/unit-client-rs/Cargo.toml | 32 + .../src/control_socket_address.rs | 571 +++ cli/unit-client-rs/src/lib.rs | 15 + cli/unit-client-rs/src/runtime_flags.rs | 90 + cli/unit-client-rs/src/unit_client.rs | 393 ++ cli/unit-client-rs/src/unitd_cmd.rs | 85 + .../src/unitd_configure_options.rs | 235 + cli/unit-client-rs/src/unitd_instance.rs | 360 ++ cli/unit-client-rs/src/unitd_process.rs | 170 + cli/unit-client-rs/src/unitd_process_user.rs | 36 + cli/unit-openapi/.gitignore | 3 + cli/unit-openapi/.openapi-generator-ignore | 27 + cli/unit-openapi/.openapi-generator/FILES | 161 + cli/unit-openapi/.openapi-generator/VERSION | 1 + cli/unit-openapi/Cargo.toml | 17 + cli/unit-openapi/README.md | 412 ++ .../openapi-templates/Cargo.mustache | 65 + cli/unit-openapi/openapi-templates/request.rs | 248 ++ cli/unit-openapi/src/apis/access_log_api.rs | 150 + cli/unit-openapi/src/apis/applications_api.rs | 139 + cli/unit-openapi/src/apis/apps_api.rs | 63 + cli/unit-openapi/src/apis/certificates_api.rs | 456 ++ cli/unit-openapi/src/apis/client.rs | 91 + cli/unit-openapi/src/apis/config_api.rs | 1782 ++++++++ cli/unit-openapi/src/apis/configuration.rs | 47 + cli/unit-openapi/src/apis/control_api.rs | 63 + cli/unit-openapi/src/apis/error.rs | 18 + cli/unit-openapi/src/apis/listeners_api.rs | 956 ++++ cli/unit-openapi/src/apis/mod.rs | 74 + cli/unit-openapi/src/apis/request.rs | 255 ++ cli/unit-openapi/src/apis/routes_api.rs | 80 + cli/unit-openapi/src/apis/settings_api.rs | 602 +++ cli/unit-openapi/src/apis/status_api.rs | 257 ++ cli/unit-openapi/src/apis/tls_api.rs | 500 +++ cli/unit-openapi/src/apis/xff_api.rs | 381 ++ cli/unit-openapi/src/lib.rs | 12 + cli/unit-openapi/src/models/cert_bundle.rs | 28 + .../src/models/cert_bundle_chain_cert.rs | 32 + .../models/cert_bundle_chain_cert_issuer.rs | 35 + .../src/models/cert_bundle_chain_cert_subj.rs | 39 + .../models/cert_bundle_chain_cert_validity.rs | 29 + cli/unit-openapi/src/models/config.rs | 40 + .../src/models/config_access_log.rs | 31 + .../src/models/config_access_log_object.rs | 31 + .../src/models/config_application.rs | 294 ++ .../src/models/config_application_common.rs | 83 + .../config_application_common_isolation.rs | 44 + ..._application_common_isolation_automount.rs | 35 + ...fig_application_common_isolation_cgroup.rs | 25 + ...plication_common_isolation_gidmap_inner.rs | 31 + ...application_common_isolation_namespaces.rs | 44 + ...plication_common_isolation_uidmap_inner.rs | 31 + .../config_application_common_limits.rs | 31 + .../config_application_common_processes.rs | 35 + ...fig_application_common_processes_any_of.rs | 32 + .../src/models/config_application_external.rs | 91 + .../config_application_external_all_of.rs | 28 + .../src/models/config_application_java.rs | 103 + .../models/config_application_java_all_of.rs | 40 + .../src/models/config_application_perl.rs | 95 + .../models/config_application_perl_all_of.rs | 32 + .../src/models/config_application_php.rs | 102 + .../models/config_application_php_all_of.rs | 39 + .../config_application_php_all_of_options.rs | 35 + .../config_application_php_all_of_targets.rs | 32 + .../src/models/config_application_python.rs | 132 + .../config_application_python_all_of.rs | 70 + .../config_application_python_all_of_path.rs | 21 + ...onfig_application_python_all_of_targets.rs | 32 + .../src/models/config_application_ruby.rs | 95 + .../models/config_application_ruby_all_of.rs | 32 + .../src/models/config_listener.rs | 33 + .../src/models/config_listener_forwarded.rs | 55 + .../config_listener_forwarded_source.rs | 21 + .../src/models/config_listener_tls.rs | 33 + .../models/config_listener_tls_certificate.rs | 21 + .../src/models/config_listener_tls_session.rs | 34 + .../config_listener_tls_session_tickets.rs | 21 + .../src/models/config_route_step.rs | 29 + .../src/models/config_route_step_action.rs | 78 + .../models/config_route_step_action_pass.rs | 35 + .../models/config_route_step_action_proxy.rs | 35 + .../models/config_route_step_action_return.rs | 39 + .../models/config_route_step_action_share.rs | 57 + .../src/models/config_route_step_match.rs | 69 + .../config_route_step_match_arguments.rs | 21 + .../models/config_route_step_match_cookies.rs | 21 + .../models/config_route_step_match_headers.rs | 21 + cli/unit-openapi/src/models/config_routes.rs | 21 + .../src/models/config_settings.rs | 24 + .../src/models/config_settings_http.rs | 58 + .../src/models/config_settings_http_static.rs | 25 + .../config_settings_http_static_mime_type.rs | 21 + cli/unit-openapi/src/models/mod.rs | 128 + cli/unit-openapi/src/models/status.rs | 33 + .../src/models/status_applications_app.rs | 29 + .../status_applications_app_processes.rs | 35 + .../status_applications_app_requests.rs | 25 + .../src/models/status_connections.rs | 39 + .../src/models/status_requests.rs | 25 + .../src/models/string_or_string_array.rs | 21 + cli/unitctl/Cargo.toml | 56 + cli/unitctl/src/cmd/edit.rs | 105 + cli/unitctl/src/cmd/execute.rs | 68 + cli/unitctl/src/cmd/import.rs | 124 + cli/unitctl/src/cmd/instances.rs | 16 + cli/unitctl/src/cmd/listeners.rs | 13 + cli/unitctl/src/cmd/mod.rs | 7 + cli/unitctl/src/cmd/status.rs | 13 + cli/unitctl/src/cmd/ui.rs | 215 + cli/unitctl/src/inputfile.rs | 289 ++ cli/unitctl/src/known_size.rs | 77 + cli/unitctl/src/main.rs | 107 + cli/unitctl/src/output_format.rs | 43 + cli/unitctl/src/requests.rs | 175 + cli/unitctl/src/unitctl.rs | 171 + cli/unitctl/src/unitctl_error.rs | 72 + cli/unitctl/src/wait.rs | 165 + cli/unitctl/www/index.html | 24 + cli/unitctl/www/rapidoc-min-9.3.4.js | 3895 +++++++++++++++++ cli/unitctl/www/rapidoc-min.js | 1 + cli/unitctl/www/rapidoc-min.js.LICENSE.txt | 67 + 141 files changed, 20199 insertions(+) create mode 100644 cli/.cargo/config.toml create mode 100644 cli/.gitignore create mode 100644 cli/Cargo.lock create mode 100644 cli/Cargo.toml create mode 100644 cli/Containerfile.debian create mode 100644 cli/GNUmakefile create mode 120000 cli/HomebrewFormula create mode 100644 cli/README.md create mode 100755 cli/build/changelog.sh create mode 100644 cli/build/container.mk create mode 100644 cli/build/github.mk create mode 100755 cli/build/openapi-generator-cli.sh create mode 100644 cli/build/package.mk create mode 100644 cli/build/release.mk create mode 100644 cli/man/unitctl.1 create mode 100644 cli/openapi-config.json create mode 100644 cli/pkg/brew/unitctl.rb create mode 100644 cli/pkg/brew/unitctl.rb.template create mode 100644 cli/rustfmt.toml create mode 100644 cli/unit-client-rs/Cargo.toml create mode 100644 cli/unit-client-rs/src/control_socket_address.rs create mode 100644 cli/unit-client-rs/src/lib.rs create mode 100644 cli/unit-client-rs/src/runtime_flags.rs create mode 100644 cli/unit-client-rs/src/unit_client.rs create mode 100644 cli/unit-client-rs/src/unitd_cmd.rs create mode 100644 cli/unit-client-rs/src/unitd_configure_options.rs create mode 100644 cli/unit-client-rs/src/unitd_instance.rs create mode 100644 cli/unit-client-rs/src/unitd_process.rs create mode 100644 cli/unit-client-rs/src/unitd_process_user.rs create mode 100644 cli/unit-openapi/.gitignore create mode 100644 cli/unit-openapi/.openapi-generator-ignore create mode 100644 cli/unit-openapi/.openapi-generator/FILES create mode 100644 cli/unit-openapi/.openapi-generator/VERSION create mode 100644 cli/unit-openapi/Cargo.toml create mode 100644 cli/unit-openapi/README.md create mode 100644 cli/unit-openapi/openapi-templates/Cargo.mustache create mode 100644 cli/unit-openapi/openapi-templates/request.rs create mode 100644 cli/unit-openapi/src/apis/access_log_api.rs create mode 100644 cli/unit-openapi/src/apis/applications_api.rs create mode 100644 cli/unit-openapi/src/apis/apps_api.rs create mode 100644 cli/unit-openapi/src/apis/certificates_api.rs create mode 100644 cli/unit-openapi/src/apis/client.rs create mode 100644 cli/unit-openapi/src/apis/config_api.rs create mode 100644 cli/unit-openapi/src/apis/configuration.rs create mode 100644 cli/unit-openapi/src/apis/control_api.rs create mode 100644 cli/unit-openapi/src/apis/error.rs create mode 100644 cli/unit-openapi/src/apis/listeners_api.rs create mode 100644 cli/unit-openapi/src/apis/mod.rs create mode 100644 cli/unit-openapi/src/apis/request.rs create mode 100644 cli/unit-openapi/src/apis/routes_api.rs create mode 100644 cli/unit-openapi/src/apis/settings_api.rs create mode 100644 cli/unit-openapi/src/apis/status_api.rs create mode 100644 cli/unit-openapi/src/apis/tls_api.rs create mode 100644 cli/unit-openapi/src/apis/xff_api.rs create mode 100644 cli/unit-openapi/src/lib.rs create mode 100644 cli/unit-openapi/src/models/cert_bundle.rs create mode 100644 cli/unit-openapi/src/models/cert_bundle_chain_cert.rs create mode 100644 cli/unit-openapi/src/models/cert_bundle_chain_cert_issuer.rs create mode 100644 cli/unit-openapi/src/models/cert_bundle_chain_cert_subj.rs create mode 100644 cli/unit-openapi/src/models/cert_bundle_chain_cert_validity.rs create mode 100644 cli/unit-openapi/src/models/config.rs create mode 100644 cli/unit-openapi/src/models/config_access_log.rs create mode 100644 cli/unit-openapi/src/models/config_access_log_object.rs create mode 100644 cli/unit-openapi/src/models/config_application.rs create mode 100644 cli/unit-openapi/src/models/config_application_common.rs create mode 100644 cli/unit-openapi/src/models/config_application_common_isolation.rs create mode 100644 cli/unit-openapi/src/models/config_application_common_isolation_automount.rs create mode 100644 cli/unit-openapi/src/models/config_application_common_isolation_cgroup.rs create mode 100644 cli/unit-openapi/src/models/config_application_common_isolation_gidmap_inner.rs create mode 100644 cli/unit-openapi/src/models/config_application_common_isolation_namespaces.rs create mode 100644 cli/unit-openapi/src/models/config_application_common_isolation_uidmap_inner.rs create mode 100644 cli/unit-openapi/src/models/config_application_common_limits.rs create mode 100644 cli/unit-openapi/src/models/config_application_common_processes.rs create mode 100644 cli/unit-openapi/src/models/config_application_common_processes_any_of.rs create mode 100644 cli/unit-openapi/src/models/config_application_external.rs create mode 100644 cli/unit-openapi/src/models/config_application_external_all_of.rs create mode 100644 cli/unit-openapi/src/models/config_application_java.rs create mode 100644 cli/unit-openapi/src/models/config_application_java_all_of.rs create mode 100644 cli/unit-openapi/src/models/config_application_perl.rs create mode 100644 cli/unit-openapi/src/models/config_application_perl_all_of.rs create mode 100644 cli/unit-openapi/src/models/config_application_php.rs create mode 100644 cli/unit-openapi/src/models/config_application_php_all_of.rs create mode 100644 cli/unit-openapi/src/models/config_application_php_all_of_options.rs create mode 100644 cli/unit-openapi/src/models/config_application_php_all_of_targets.rs create mode 100644 cli/unit-openapi/src/models/config_application_python.rs create mode 100644 cli/unit-openapi/src/models/config_application_python_all_of.rs create mode 100644 cli/unit-openapi/src/models/config_application_python_all_of_path.rs create mode 100644 cli/unit-openapi/src/models/config_application_python_all_of_targets.rs create mode 100644 cli/unit-openapi/src/models/config_application_ruby.rs create mode 100644 cli/unit-openapi/src/models/config_application_ruby_all_of.rs create mode 100644 cli/unit-openapi/src/models/config_listener.rs create mode 100644 cli/unit-openapi/src/models/config_listener_forwarded.rs create mode 100644 cli/unit-openapi/src/models/config_listener_forwarded_source.rs create mode 100644 cli/unit-openapi/src/models/config_listener_tls.rs create mode 100644 cli/unit-openapi/src/models/config_listener_tls_certificate.rs create mode 100644 cli/unit-openapi/src/models/config_listener_tls_session.rs create mode 100644 cli/unit-openapi/src/models/config_listener_tls_session_tickets.rs create mode 100644 cli/unit-openapi/src/models/config_route_step.rs create mode 100644 cli/unit-openapi/src/models/config_route_step_action.rs create mode 100644 cli/unit-openapi/src/models/config_route_step_action_pass.rs create mode 100644 cli/unit-openapi/src/models/config_route_step_action_proxy.rs create mode 100644 cli/unit-openapi/src/models/config_route_step_action_return.rs create mode 100644 cli/unit-openapi/src/models/config_route_step_action_share.rs create mode 100644 cli/unit-openapi/src/models/config_route_step_match.rs create mode 100644 cli/unit-openapi/src/models/config_route_step_match_arguments.rs create mode 100644 cli/unit-openapi/src/models/config_route_step_match_cookies.rs create mode 100644 cli/unit-openapi/src/models/config_route_step_match_headers.rs create mode 100644 cli/unit-openapi/src/models/config_routes.rs create mode 100644 cli/unit-openapi/src/models/config_settings.rs create mode 100644 cli/unit-openapi/src/models/config_settings_http.rs create mode 100644 cli/unit-openapi/src/models/config_settings_http_static.rs create mode 100644 cli/unit-openapi/src/models/config_settings_http_static_mime_type.rs create mode 100644 cli/unit-openapi/src/models/mod.rs create mode 100644 cli/unit-openapi/src/models/status.rs create mode 100644 cli/unit-openapi/src/models/status_applications_app.rs create mode 100644 cli/unit-openapi/src/models/status_applications_app_processes.rs create mode 100644 cli/unit-openapi/src/models/status_applications_app_requests.rs create mode 100644 cli/unit-openapi/src/models/status_connections.rs create mode 100644 cli/unit-openapi/src/models/status_requests.rs create mode 100644 cli/unit-openapi/src/models/string_or_string_array.rs create mode 100644 cli/unitctl/Cargo.toml create mode 100644 cli/unitctl/src/cmd/edit.rs create mode 100644 cli/unitctl/src/cmd/execute.rs create mode 100644 cli/unitctl/src/cmd/import.rs create mode 100644 cli/unitctl/src/cmd/instances.rs create mode 100644 cli/unitctl/src/cmd/listeners.rs create mode 100644 cli/unitctl/src/cmd/mod.rs create mode 100644 cli/unitctl/src/cmd/status.rs create mode 100644 cli/unitctl/src/cmd/ui.rs create mode 100644 cli/unitctl/src/inputfile.rs create mode 100644 cli/unitctl/src/known_size.rs create mode 100644 cli/unitctl/src/main.rs create mode 100644 cli/unitctl/src/output_format.rs create mode 100644 cli/unitctl/src/requests.rs create mode 100644 cli/unitctl/src/unitctl.rs create mode 100644 cli/unitctl/src/unitctl_error.rs create mode 100644 cli/unitctl/src/wait.rs create mode 100644 cli/unitctl/www/index.html create mode 100644 cli/unitctl/www/rapidoc-min-9.3.4.js create mode 120000 cli/unitctl/www/rapidoc-min.js create mode 100644 cli/unitctl/www/rapidoc-min.js.LICENSE.txt diff --git a/cli/.cargo/config.toml b/cli/.cargo/config.toml new file mode 100644 index 000000000..ff7f7580c --- /dev/null +++ b/cli/.cargo/config.toml @@ -0,0 +1,2 @@ +[target.aarch64-unknown-linux-gnu] +linker = "aarch64-linux-gnu-gcc" \ No newline at end of file diff --git a/cli/.gitignore b/cli/.gitignore new file mode 100644 index 000000000..36337d804 --- /dev/null +++ b/cli/.gitignore @@ -0,0 +1,111 @@ +# Created by https://www.toptal.com/developers/gitignore/api/rust,clion+all +# Edit at https://www.toptal.com/developers/gitignore?templates=rust,clion+all + +### CLion+all ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# AWS User-specific +.idea/**/aws.xml + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# SonarLint plugin +.idea/sonarlint/ + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +### CLion+all Patch ### +# Ignore everything but code style settings and run configurations +# that are supposed to be shared within teams. + +.idea/* + +!.idea/codeStyles +!.idea/runConfigurations + +### Rust ### +# Generated by Cargo +# will have compiled files and executables +debug/ +target/ + +# These are backup files generated by rustfmt +**/*.rs.bk + +# MSVC Windows builds of rustc generate these, which store debugging information +*.pdb + +# End of https://www.toptal.com/developers/gitignore/api/rust,clion+all + +# Ignore OpenAPI cache files +.openapi_cache +# Ignore generated OpenAPI documentation (for now) +unit-openapi/docs + +config \ No newline at end of file diff --git a/cli/Cargo.lock b/cli/Cargo.lock new file mode 100644 index 000000000..60a0280ed --- /dev/null +++ b/cli/Cargo.lock @@ -0,0 +1,1706 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "addr2line" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "anstream" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d664a92ecae85fd0a7392615844904654d1d5f5514837f471ddef4a057aba1b6" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41ed9a86bf92ae6580e0a31281f65a1b1d867c0cc68d5346e2ae128dddfa6a7d" + +[[package]] +name = "anstyle-parse" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e765fd216e48e067936442276d1d57399e37bce53c264d6fefbe298080cb57ee" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" +dependencies = [ + "windows-sys 0.48.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" +dependencies = [ + "anstyle", + "windows-sys 0.52.0", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "backtrace" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "base64" +version = "0.21.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" + +[[package]] +name = "block-buffer" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bytes" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec8a7b6a70fde80372154c65702f00a0f56f3e1c36abbc6c440484be248856db" + +[[package]] +name = "cc" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "clap" +version = "4.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52bdc885e4cacc7f7c9eedc1ef6da641603180c783c41a15c264944deeaab642" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb7fb5e4e979aec3be7791562fcba452f94ad85e954da024396433e0e25a79e9" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.16", +] + +[[package]] +name = "clap_lex" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" + +[[package]] +name = "colorchoice" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" + +[[package]] +name = "colored_json" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79cff32df5cfea75e6484eeff0b4e48ad3977fb6582676a7862b3590dddc7a87" +dependencies = [ + "serde", + "serde_json", + "yansi", +] + +[[package]] +name = "core-foundation" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" + +[[package]] +name = "cpufeatures" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" +dependencies = [ + "libc", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc" +dependencies = [ + "cfg-if", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f916dfc5d356b0ed9dae65f1db9fc9770aa2851d2662b988ccf4fe3516e86348" +dependencies = [ + "autocfg", + "cfg-if", + "crossbeam-utils", + "memoffset", + "scopeguard", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edbafec5fa1f196ca66527c1b12c2ec4745ca14b50f1ad8f9f6f720b55d11fac" +dependencies = [ + "cfg-if", +] + +[[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 = "custom_error" +version = "1.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f8a51dd197fa6ba5b4dc98a990a43cc13693c23eb0089ebb0fcc1f04152bca6" + +[[package]] +name = "digest" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "either" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" + +[[package]] +name = "errno" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" +dependencies = [ + "errno-dragonfly", + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "errno-dragonfly" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "fastrand" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futures" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" + +[[package]] +name = "futures-executor" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" + +[[package]] +name = "futures-macro" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.16", +] + +[[package]] +name = "futures-sink" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" + +[[package]] +name = "futures-task" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" + +[[package]] +name = "futures-util" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "gimli" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "heck" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "home" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb" +dependencies = [ + "windows-sys 0.48.0", +] + +[[package]] +name = "http" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" +dependencies = [ + "bytes", + "http", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" + +[[package]] +name = "httpdate" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" + +[[package]] +name = "hyper" +version = "0.14.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2 0.4.7", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper-tls" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +dependencies = [ + "bytes", + "hyper", + "native-tls", + "tokio", + "tokio-native-tls", +] + +[[package]] +name = "hyperlocal" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fafdf7b2b2de7c9784f76e02c0935e65a8117ec3b768644379983ab333ac98c" +dependencies = [ + "futures-util", + "hex", + "hyper", + "pin-project", + "tokio", +] + +[[package]] +name = "idna" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "indexmap" +version = "1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" +dependencies = [ + "autocfg", + "hashbrown", +] + +[[package]] +name = "itoa" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc" + +[[package]] +name = "json5" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96b0db21af676c1ce64250b5f40f3ce2cf27e4e47cb91ed91eb6fe9350b430c1" +dependencies = [ + "pest", + "pest_derive", + "serde", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.150" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" + +[[package]] +name = "linked-hash-map" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" +dependencies = [ + "serde", +] + +[[package]] +name = "linux-raw-sys" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "969488b55f8ac402214f3f5fd243ebb7206cf82de60d3172994707a4bcc2b829" + +[[package]] +name = "log" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "memchr" +version = "2.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" + +[[package]] +name = "memoffset" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" +dependencies = [ + "autocfg", +] + +[[package]] +name = "miniz_oxide" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +dependencies = [ + "adler", +] + +[[package]] +name = "mio" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3dce281c5e46beae905d4de1870d8b1509a9142b62eedf18b443b011ca8343d0" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.48.0", +] + +[[package]] +name = "native-tls" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" +dependencies = [ + "lazy_static", + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "ntapi" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc51db7b362b205941f71232e56c625156eb9a929f8cf74a428fd5bc094a4afc" +dependencies = [ + "winapi", +] + +[[package]] +name = "nu-json" +version = "0.89.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "563eff2fa513ceee37a147701a75e259b4514b31b0bac3496f16297851946caf" +dependencies = [ + "linked-hash-map", + "num-traits", + "serde", +] + +[[package]] +name = "num-traits" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6058e64324c71e02bc2b150e4f3bc8286db6c83092132ffa3f6b1eab0f9def5" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "object" +version = "0.32.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "openssl" +version = "0.10.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79a4c6c3a2b158f7f8f2a2fc5a969fa3a068df6fc9dbb4a43845436e3af7c800" +dependencies = [ + "bitflags 2.4.1", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b501e44f11665960c7e7fcf062c7d96a14ade4aa98116c004b2e37b5be7d736c" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.103", +] + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "openssl-src" +version = "300.2.1+3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fe476c29791a5ca0d1273c697e96085bbabbbea2ef7afd5617e78a4b40332d3" +dependencies = [ + "cc", +] + +[[package]] +name = "openssl-sys" +version = "0.9.98" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1665caf8ab2dc9aef43d1c0023bd904633a6a05cb30b0ad59bec2ae986e57a7" +dependencies = [ + "cc", + "libc", + "openssl-src", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "percent-encoding" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" + +[[package]] +name = "pest" +version = "2.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f6e86fb9e7026527a0d46bc308b841d73170ef8f443e1807f6ef88526a816d4" +dependencies = [ + "thiserror", + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96504449aa860c8dcde14f9fba5c58dc6658688ca1fe363589d6327b8662c603" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "798e0220d1111ae63d66cb66a5dcb3fc2d986d520b98e49e1852bfdb11d7c5e7" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn 1.0.103", +] + +[[package]] +name = "pest_meta" +version = "2.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "984298b75898e30a843e278a9f2452c31e349a073a0ce6fd950a12a74464e065" +dependencies = [ + "once_cell", + "pest", + "sha1", +] + +[[package]] +name = "pin-project" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad29a609b6bcd67fee905812e544992d216af9d755757c05ed2d0e15a74c6ecc" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.103", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkg-config" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "proc-macro2" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f4f29d145265ec1c483c7c654450edde0bfe043d3938d6972630663356d9500" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rayon" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "redox_syscall" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" + +[[package]] +name = "rustix" +version = "0.38.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc99bc2d4f1fed22595588a013687477aedf3cdcfb26558c559edb67b4d9b22e" +dependencies = [ + "bitflags 2.4.1", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.48.0", +] + +[[package]] +name = "rustls-pemfile" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35e4980fa29e4c4b212ffb3db068a564cbf560e51d3944b7c88bd8bf5bec64f4" +dependencies = [ + "base64", + "rustls-pki-types", +] + +[[package]] +name = "rustls-pki-types" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e9d979b3ce68192e42760c7810125eb6cf2ea10efae545a156063e61f314e2a" + +[[package]] +name = "ryu" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" + +[[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 = "schannel" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88d6731146462ea25d9244b2ed5fd1d716d25c52e4d54aa4fb0f3c4e9854dbe2" +dependencies = [ + "lazy_static", + "windows-sys 0.36.1", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "security-framework" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bc1bb97804af6631813c55739f771071e0f2ed33ee20b68c86ec505d906356c" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0160a13a177a45bfb43ce71c01580998474f556ad854dcbca936dd2841a5c556" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "serde" +version = "1.0.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d193d69bae983fc11a79df82342761dfbf28a99fc8d203dca4c3c1b590948965" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f1d362ca8fc9c3e3a7484440752472d68a6caa98f1ab81d99b5dfe517cec852" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.103", +] + +[[package]] +name = "serde_json" +version = "1.0.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce777b7b150d76b9cf60d28b55f5847135a003f7d7350c6be7a773508ce7d45" +dependencies = [ + "indexmap", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_yaml" +version = "0.9.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d232d893b10de3eb7258ff01974d6ee20663d8e833263c99409d4b13a0209da" +dependencies = [ + "indexmap", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", +] + +[[package]] +name = "sha1" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "slab" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" +dependencies = [ + "autocfg", +] + +[[package]] +name = "socket2" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02e2d2db9033d13a1567121ddd7a095ee144db4e1ca1b1bda3419bc0da294ebd" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "socket2" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" +dependencies = [ + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "syn" +version = "1.0.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a864042229133ada95abf3b54fdc62ef5ccabe9515b64717bcb9a1919e59445d" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6f671d4b5ffdb8eadec19c0ae67fe2639df8684bd7bc4b83d986b8db549cf01" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sysinfo" +version = "0.30.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fb4f3438c8f6389c864e61221cbc97e9bca98b4daf39a5beb7bea660f528bb2" +dependencies = [ + "cfg-if", + "core-foundation-sys", + "libc", + "ntapi", + "once_cell", + "rayon", + "windows", +] + +[[package]] +name = "tempfile" +version = "3.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" +dependencies = [ + "cfg-if", + "fastrand", + "redox_syscall", + "rustix", + "windows-sys 0.48.0", +] + +[[package]] +name = "thiserror" +version = "1.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.103", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" + +[[package]] +name = "tokio" +version = "1.35.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c89b4efa943be685f629b149f53829423f8f5531ea21249408e8e2f8671ec104" +dependencies = [ + "backtrace", + "libc", + "mio", + "num_cpus", + "pin-project-lite", + "socket2 0.5.5", + "tokio-macros", + "windows-sys 0.48.0", +] + +[[package]] +name = "tokio-macros" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.16", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d995660bd2b7f8c1568414c1126076c13fbb725c40112dc0120b78eb9b717b" +dependencies = [ + "native-tls", + "tokio", +] + +[[package]] +name = "tower-service" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" + +[[package]] +name = "tracing" +version = "0.1.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +dependencies = [ + "cfg-if", + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" +dependencies = [ + "once_cell", +] + +[[package]] +name = "try-lock" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" + +[[package]] +name = "typenum" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" + +[[package]] +name = "ucd-trie" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81" + +[[package]] +name = "unicode-bidi" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" + +[[package]] +name = "unicode-ident" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" + +[[package]] +name = "unicode-normalization" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unit-client-rs" +version = "0.4.0-beta" +dependencies = [ + "custom_error", + "futures", + "hex", + "hyper", + "hyper-tls", + "hyperlocal", + "openssl", + "rand", + "serde", + "serde_json", + "sysinfo", + "tokio", + "unit-openapi", + "which", +] + +[[package]] +name = "unit-openapi" +version = "0.4.0-beta" +dependencies = [ + "base64", + "futures", + "http", + "hyper", + "serde", + "serde_derive", + "serde_json", + "url", +] + +[[package]] +name = "unitctl" +version = "0.4.0-beta" +dependencies = [ + "clap", + "colored_json", + "custom_error", + "futures", + "hyper", + "hyper-tls", + "hyperlocal", + "json5", + "nu-json", + "rustls-pemfile", + "serde", + "serde_json", + "serde_yaml", + "tempfile", + "tokio", + "unit-client-rs", + "walkdir", + "which", +] + +[[package]] +name = "unsafe-libyaml" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab4c90930b95a82d00dc9e9ac071b4991924390d46cbd0dfe566148667605e4b" + +[[package]] +name = "url" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "walkdir" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "want" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" +dependencies = [ + "log", + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "which" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bf3ea8596f3a0dd5980b46430f2058dfe2c36a27ccfbb1845d6fbfcd9ba6e14" +dependencies = [ + "either", + "home", + "once_cell", + "rustix", + "windows-sys 0.48.0", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be" +dependencies = [ + "windows-core", + "windows-targets 0.52.0", +] + +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets 0.52.0", +] + +[[package]] +name = "windows-sys" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" +dependencies = [ + "windows_aarch64_msvc 0.36.1", + "windows_i686_gnu 0.36.1", + "windows_i686_msvc 0.36.1", + "windows_x86_64_gnu 0.36.1", + "windows_x86_64_msvc 0.36.1", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.0", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.0", +] + +[[package]] +name = "windows-targets" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" +dependencies = [ + "windows_aarch64_gnullvm 0.48.0", + "windows_aarch64_msvc 0.48.0", + "windows_i686_gnu 0.48.0", + "windows_i686_msvc 0.48.0", + "windows_x86_64_gnu 0.48.0", + "windows_x86_64_gnullvm 0.48.0", + "windows_x86_64_msvc 0.48.0", +] + +[[package]] +name = "windows-targets" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +dependencies = [ + "windows_aarch64_gnullvm 0.52.0", + "windows_aarch64_msvc 0.52.0", + "windows_i686_gnu 0.52.0", + "windows_i686_msvc 0.52.0", + "windows_x86_64_gnu 0.52.0", + "windows_x86_64_gnullvm 0.52.0", + "windows_x86_64_msvc 0.52.0", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" + +[[package]] +name = "windows_i686_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" + +[[package]] +name = "windows_i686_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" + +[[package]] +name = "yansi" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" diff --git a/cli/Cargo.toml b/cli/Cargo.toml new file mode 100644 index 000000000..c9c6a2725 --- /dev/null +++ b/cli/Cargo.toml @@ -0,0 +1,8 @@ +[workspace] +resolver = "2" + +members = [ + "unit-openapi", + "unit-client-rs", + "unitctl" +] \ No newline at end of file diff --git a/cli/Containerfile.debian b/cli/Containerfile.debian new file mode 100644 index 000000000..f1cffa7ac --- /dev/null +++ b/cli/Containerfile.debian @@ -0,0 +1,35 @@ +FROM rust:slim-bullseye + +ADD https://unit.nginx.org/keys/nginx-keyring.gpg /usr/share/keyrings/nginx-keyring.gpg + +RUN set -eux \ + export DEBIAN_FRONTEND=noninteractive; \ + echo 'fc27fd284cceb4bf6c8ac2118dbb5e834590836f8d6ba3944da0e0451cbadeca /usr/share/keyrings/nginx-keyring.gpg' | sha256sum --check -; \ + chmod 0644 /usr/share/keyrings/nginx-keyring.gpg; \ + echo "deb [signed-by=/usr/share/keyrings/nginx-keyring.gpg] https://packages.nginx.org/unit/debian/ bullseye unit" > /etc/apt/sources.list.d/unit.list; \ + apt-get -qq update; \ + apt-get -qq upgrade --yes; \ + apt-get -qq install --yes --no-install-recommends --no-install-suggests \ + bsdmainutils \ + ca-certificates \ + git \ + gzip \ + grep \ + gawk \ + sed \ + make \ + rpm \ + pkg-config \ + libssl-dev \ + dpkg-dev \ + musl-dev \ + musl-tools \ + unit \ + gcc-aarch64-linux-gnu \ + libc6-dev-arm64-cross \ + gcc-x86-64-linux-gnu \ + libc6-dev-amd64-cross; \ + rustup target install x86_64-unknown-linux-gnu aarch64-unknown-linux-gnu x86_64-unknown-linux-musl; \ + cargo install --quiet cargo-deb cargo-generate-rpm; \ + rm -rf /var/lib/apt/lists/* /var/tmp/* /tmp/*; \ + git config --global --add safe.directory /project \ No newline at end of file diff --git a/cli/GNUmakefile b/cli/GNUmakefile new file mode 100644 index 000000000..47f95c193 --- /dev/null +++ b/cli/GNUmakefile @@ -0,0 +1,140 @@ +MAKE_MAJOR_VER := $(shell echo $(MAKE_VERSION) | cut -d'.' -f1) + +ifneq ($(shell test $(MAKE_MAJOR_VER) -gt 3; echo $$?),0) +$(error Make version $(MAKE_VERSION) is not supported, please install GNU Make 4.x) +endif + +GREP ?= $(shell command -v ggrep 2> /dev/null || command -v grep 2> /dev/null) +SED ?= $(shell command -v gsed 2> /dev/null || command -v sed 2> /dev/null) +AWK ?= $(shell command -v gawk 2> /dev/null || command -v awk 2> /dev/null) +RUSTUP ?= $(shell command -v rustup 2> /dev/null) +RPM_ARCH := $(shell uname -m) +VERSION ?= $(shell $(GREP) -Po '^version\s+=\s+"\K.*?(?=")' $(CURDIR)/unitctl/Cargo.toml) +SRC_REPO := https://github.com/nginxinc/unit-rust-sdk +DEFAULT_TARGET ?= $(shell $(RUSTUP) toolchain list | $(GREP) '(default)' | cut -d' ' -f1 | cut -d- -f2-) +SHELL := /bin/bash +OUTPUT_BINARY ?= unitctl +PACKAGE_NAME ?= unitctl +CARGO ?= cargo +DOCKER ?= docker +DOCKER_BUILD_FLAGS ?= --load +CHECKSUM ?= sha256sum +OPENAPI_GENERATOR_VERSION ?= 6.6.0 +COMMITSAR_DOCKER := $(DOCKER) run --tty --rm --workdir /src -v "$(CURDIR):/src" aevea/commitsar +COMMITSAR ?= $(shell command -v commitsar 2> /dev/null) + +# Define platform targets based off of the current host OS +# If we are running MacOS, then we can build for MacOS platform targets that have been installed in rustup +# If we are running Linux, then we can build for Linux platform targets that have been installed in rustup +UNAME = $(shell uname | tr '[:upper:]' '[:lower:]') +ifeq ($(UNAME),darwin) + TARGETS := $(sort $(shell $(RUSTUP) target list | $(GREP) '(installed)' | $(GREP) 'apple' | cut -d' ' -f1)) +else ifeq ($(UNAME),linux) + TARGETS := $(sort $(shell $(RUSTUP) target list | $(GREP) '(installed)' | $(GREP) 'linux' | cut -d' ' -f1)) +else + TARGETS := $(DEFAULT_TARGET) +endif + +RELEASE_BUILD_FLAGS ?= --quiet --release --bin $(OUTPUT_BINARY) + +Q = $(if $(filter 1,$V),,@) +M = $(shell printf "\033[34;1m▶\033[0m") + +# Use docker based commitsar if it isn't in the path +ifeq ($(COMMITSAR),) + COMMITSAR = $(COMMITSAR_DOCKER) +endif + +.PHONY: help +help: + @$(GREP) --no-filename -E '^[ a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | \ + $(AWK) 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-28s\033[0m %s\n", $$1, $$2}' | sort + +.PHONY: clean +clean: ; $(info $(M) cleaning...) @ ## Cleanup everything + $Q rm -rf $(CURDIR)/target + +.PHONY: commitsar +commitsar: ## Run git commit linter + $Q $(info $(M) running commitsar...) + $(COMMITSAR) + +.PHONY: list-targets +list-targets: ## List all available platform targets + $Q echo $(TARGETS) | $(SED) -e 's/ /\n/g' + +.PHONY: all +all: $(TARGETS) ## Build all available platform targets [see: list-targets] + +.PHONY: $(TARGETS) +.ONESHELL: $(TARGETS) +$(TARGETS): ## Build for a specific target + $Q if [ ! -f "$(CURDIR)/target/$(@)/release/$(OUTPUT_BINARY)" ]; then + echo "$(M) building $(OUTPUT_BINARY) with flags [$(RELEASE_BUILD_FLAGS) --target $(@)]" + $(CARGO) build $(RELEASE_BUILD_FLAGS) --target $@ + fi + +target: + $Q mkdir -p $@ + +.PHONY: debug +debug: target/debug/$(OUTPUT_BINARY) ## Build current platform target in debug mode + +target/debug/$(OUTPUT_BINARY): + $Q echo "$(M) building $(OUTPUT_BINARY) in debug mode for the current platform" + $Q $(CARGO) build --bin $(OUTPUT_BINARY) + +.PHONY: release +release: target/release/$(OUTPUT_BINARY) ## Build current platform target in release mode + +target/release/$(OUTPUT_BINARY): + $Q echo "$(M) building $(OUTPUT_BINARY) in release mode for the current platform" + $Q $(CARGO) build $(RELEASE_BUILD_FLAGS) + +.PHONY: test +test: ## Run tests + $Q $(CARGO) test + +.ONESHELL: target/man/$(OUTPUT_BINARY).1.gz +target/man/$(OUTPUT_BINARY).1.gz: + $Q $(info $(M) building distributable manpage) + mkdir -p target/man + $(SED) 's/%%VERSION%%/$(VERSION)/' man/$(OUTPUT_BINARY).1 > $(CURDIR)/target/man/$(OUTPUT_BINARY).1 + gzip $(CURDIR)/target/man/$(OUTPUT_BINARY).1 + +target/gz: + $Q mkdir -p target/gz + +.PHONY: manpage +manpage: target/man/$(OUTPUT_BINARY).1.gz ## Builds man page + +.openapi_cache: + $Q mkdir -p $@ + +.PHONY: openapi-generate +openapi-generate: .openapi_cache ## Generate (or regenerate) UNIT API access code via a OpenAPI spec + $Q $(info $(M) generating UNIT API access code via a OpenAPI spec) + OPENAPI_GENERATOR_VERSION="$(OPENAPI_GENERATOR_VERSION)" OPENAPI_GENERATOR_DOWNLOAD_CACHE_DIR="$(CURDIR)/.openapi_cache" $(CURDIR)/build/openapi-generator-cli.sh \ + generate \ + --input-spec "$(CURDIR)/openapi.yaml" \ + --config "$(CURDIR)/openapi-config.json" \ + --template-dir "$(CURDIR)/unit-openapi/openapi-templates" \ + --output "$(CURDIR)/unit-openapi" \ + --generator-name rust + $Q echo "mod error;" >> "$(CURDIR)/unit-openapi/src/apis/mod.rs" + $Q $(SED) -i '1i #![allow(clippy::all)]' "$(CURDIR)/unit-openapi/src/lib.rs" + $Q $(CARGO) fmt + +.PHONY: openapi-clean +openapi-clean: ## Clean up generated OpenAPI files + $Q $(info $(M) cleaning up generated OpenAPI documentation) + $Q rm -rf "$(CURDIR)/unit-openapi/docs/*" + $Q $(info $(M) cleaning up generated OpenAPI api code) + $Q find "$(CURDIR)/unit-openapi/src/apis" ! -name 'error.rs' -type f -exec rm -f {} + + $Q $(info $(M) cleaning up generated OpenAPI models code) + $Q rm -rf "$(CURDIR)/unit-openapi/src/models/*" + +include $(CURDIR)/build/package.mk +include $(CURDIR)/build/container.mk +include $(CURDIR)/build/release.mk +include $(CURDIR)/build/github.mk \ No newline at end of file diff --git a/cli/HomebrewFormula b/cli/HomebrewFormula new file mode 120000 index 000000000..1ffaf0422 --- /dev/null +++ b/cli/HomebrewFormula @@ -0,0 +1 @@ +pkg/brew \ No newline at end of file diff --git a/cli/README.md b/cli/README.md new file mode 100644 index 000000000..c518e5357 --- /dev/null +++ b/cli/README.md @@ -0,0 +1,135 @@ +# NGINX UNIT Rust SDK and CLI + +This project provides a Rust SDK interface to the [NGINX UNIT](https://unit.nginx.org/) +[control API](https://unit.nginx.org/howto/source/#source-startup) and a CLI that exposes +the functionality provided by the SDK. + +## Vision + +There are two main goals for this project: + +1. Provide a Rust SDK for the NGINX UNIT control API that has been pregenerated from the + OpenAPI specification. This will allow Rust developers to easily integrate NGINX UNIT + into their applications without having to generate their own SDK from the OpenAPI + [specification file](https://unit.nginx.org/controlapi/#openapi-specification). + +2. Provide a CLI that exposes the functionality of the SDK. This will allow users to + interact with NGINX UNIT from the command line without having to write their own + scripts or programs. The CLI will also provide a reference implementation of the SDK. + Moreover, the CLI will integrate in data format conversions and validations that are + not supported by NGINX UNIT. + +## Features (Current) + +### Parses and validates configuration formats that UNIT does not support like JSON5 and YAML and converts them before sending to UNIT +### Syntactic highlighting of JSON output +### Interpretation of UNIT errors with (arguably more) useful error messages + +### Lists all running UNIT processes and provides details about each process. +``` +$ unitctl instances +No socket path provided - attempting to detect from running instance +unitd instance [pid: 79489, version: 1.32.0]: + Executable: /opt/unit/sbin/unitd + API control unix socket: unix:/opt/unit/control.unit.sock + Child processes ids: 79489, 79489 + Runtime flags: --no-daemon + Configure options: --prefix=/opt/unit --user=elijah --group=elijah --openssl --debug +``` + +### Lists active listeners from running UNIT processes +``` +unitctl listeners +No socket path provided - attempting to detect from running instance +{ + "127.0.0.1:8080": { + "pass": "routes" + } +} +``` + +### Get the current status of NGINX UNIT processes +``` +$ unitctl status -t yaml +No socket path provided - attempting to detect from running instance +connections: + accepted: 0 + active: 0 + idle: 0 + closed: 0 +requests: + total: 0 +applications: {} +``` + +### Send arbitrary configuration payloads to UNIT +``` +$ echo '{ + "listeners": { + "127.0.0.1:8080": { + "pass": "routes" + } + }, + + "routes": [ + { + "action": { + "share": "/www/data$uri" + } + } + ] +}' | unitctl execute --http-method PUT --path /config -f - +{ + "success": "Reconfiguration done." +} +``` + +### Edit current configuration in your favorite editor +``` +$ unitctl edit +[[EDITOR LOADS SHOWING CURRENT CONFIGURATION - USER EDITS AND SAVES]] + +{ + "success": "Reconfiguration done." +} +``` + +### Display interactive OpenAPI control panel +``` +$ unitctl ui +Starting UI server on http://127.0.0.1:3000/control-ui/ +Press Ctrl-C to stop the server +``` + +### Import configuration, certificates, and NJS modules from directory +``` +$ unitctl import /opt/unit/config +Imported /opt/unit/config/certificates/consolidated_snake.pem -> /certificates/consolidated_snake.pem +Imported /opt/unit/config/hello.js -> /js_modules/hello.js +Imported /opt/unit/config/put.json -> /config +Imported 3 files +``` +### Wait for socket to become available +``` +$ unitctl --wait-timeout-seconds=3 --wait-max-tries=4 import /opt/unit/config` +Waiting for 3s control socket to be available try 2/4... +Waiting for 3s control socket to be available try 3/4... +Waiting for 3s control socket to be available try 4/4... +Timeout waiting for unit to start has been exceeded +``` + +## Features (Proposed) +* Certificate validation (expiration date and validity checks) before upload +* Make adding and maintaining mime types easier +* Add features present in unit-cli + +## Contribution + +We welcome pull requests and issues! + +Please refer to the [Contributing Guidelines](CONTRIBUTING.md) when doing a PR. + +## License + +All code in this repository is licensed under the +[Apache License v2 license](LICENSE.txt). diff --git a/cli/build/changelog.sh b/cli/build/changelog.sh new file mode 100755 index 000000000..7b8165074 --- /dev/null +++ b/cli/build/changelog.sh @@ -0,0 +1,52 @@ +#!/usr/bin/env bash + +# This script generates a changelog for the current version of the project. + +set -o errexit # abort on nonzero exit status +set -o nounset # abort on unbound variable +set -o pipefail # don't hide errors within pipes + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)" +EXCLUDED_COMMIT_TYPES="ci|chore" + +pushd . > /dev/null +cd "${SCRIPT_DIR}/.." + +if command -v ggrep > /dev/null; then + GREP=ggrep +else + GREP=grep +fi +if command -v gsed > /dev/null; then + SED=gsed +else + SED=sed +fi + +# if gh is installed, use it to pull the last version number +if command -v gh > /dev/null; then + LAST_RELEASE="$(gh release list --exclude-drafts --exclude-pre-releases --limit 1 | ${GREP} -E 'v[0-9]+\.[0-9]+\.[0-9]+' | cut -f1 | ${GREP} -v "${VERSION}" || true)" +else + LAST_RELEASE="$(git tag --list v* | ${GREP} -E '^v[0-9]+\.[0-9]+\.[0-9]+$' | sort --version-sort --field-separator=. --reverse | ${GREP} -v "${VERSION}" | head -n1 || true)" +fi + +if [ -z "${LAST_RELEASE}" ]; then + echo "## Initial release ${VERSION}" + git log --format="%s (%h)" | \ + ${GREP} -E -v "^(${EXCLUDED_COMMIT_TYPES}): .*" | \ + ${SED} 's/: /:\t/g1' | \ + column -s " " -t | \ + ${SED} -e 's/^/ * /' +else + LAST_RELEASE_HASH="$(git show --format=%H "${LAST_RELEASE}" | head -n1 | ${SED} -e 's/^tag //')" + + echo "## Changes between ${LAST_RELEASE} [$LAST_RELEASE_HASH] and ${VERSION}:" + git log --format="%s (%h)" "${LAST_RELEASE_HASH}..HEAD" | \ + ${GREP} -E -v "^(${EXCLUDED_COMMIT_TYPES}): .*" | \ + ${SED} 's/: /:\t/g1' | \ + column -s " " -t | \ + ${SED} -e 's/^/ * /' +fi + +echo "" +popd > /dev/null \ No newline at end of file diff --git a/cli/build/container.mk b/cli/build/container.mk new file mode 100644 index 000000000..4600ec358 --- /dev/null +++ b/cli/build/container.mk @@ -0,0 +1,46 @@ +.PHONY: container-debian-build-image +.ONESHELL: container-debian-build-image +container-debian-build-image: +container-debian-build-image: ## Builds a container image for building on Debian Linux + $Q echo "$(M) building debian linux docker build image: $(@)" + $(DOCKER) buildx build $(DOCKER_BUILD_FLAGS) -t debian_builder -f Containerfile.debian $(CURDIR); + +.PHONY: container-deb-packages +container-deb-packages: container-debian-build-image ## Builds deb packages using a container image + $Q $(DOCKER) run --rm --volume "$(CURDIR):/project" --workdir /project debian_builder make deb-packages + # Reset permissions on the target directory to the current user + if command -v id > /dev/null; then \ + $(DOCKER) run --rm --volume "$(CURDIR):/project" --workdir /project debian_builder chown --recursive "$(shell id -u):$(shell id -g)" /project/target + fi + +.PHONY: container-rpm-packages +container-rpm-packages: container-debian-build-image ## Builds a rpm packages using a container image + $Q $(DOCKER) run --rm --volume "$(CURDIR):/project" --workdir /project debian_builder make rpm-packages + # Reset permissions on the target directory to the current user + if command -v id > /dev/null; then \ + $(DOCKER) run --rm --volume "$(CURDIR):/project" --workdir /project debian_builder chown --recursive "$(shell id -u):$(shell id -g)" /project/target + fi + +.PHONY: container-all-packages +container-all-packages: container-debian-build-image ## Builds all packages using a container image + $Q $(DOCKER) run --rm --volume "$(CURDIR):/project" --workdir /project debian_builder make all-packages + # Reset permissions on the target directory to the current user + if command -v id > /dev/null; then \ + $(DOCKER) run --rm --volume "$(CURDIR):/project" --workdir /project debian_builder chown --recursive "$(shell id -u):$(shell id -g)" /project/target + fi + +.PHONY: container-test +container-test: container-debian-build-image ## Run tests inside container + $Q $(DOCKER) run --rm --volume "$(CURDIR):/project" --workdir /project debian_builder make test + # Reset permissions on the target directory to the current user + if command -v id > /dev/null; then \ + $(DOCKER) run --rm --volume "$(CURDIR):/project" --workdir /project debian_builder chown --recursive "$(shell id -u):$(shell id -g)" /project/target + fi + +.PHONY: container-shell +container-shell: container-debian-build-image ## Run tests inside container + $Q $(DOCKER) run -it --rm --volume "$(CURDIR):/project" --workdir /project debian_builder bash + # Reset permissions on the target directory to the current user + if command -v id > /dev/null; then \ + $(DOCKER) run --rm --volume "$(CURDIR):/project" --workdir /project debian_builder chown --recursive "$(shell id -u):$(shell id -g)" /project/target + fi \ No newline at end of file diff --git a/cli/build/github.mk b/cli/build/github.mk new file mode 100644 index 000000000..b205e979f --- /dev/null +++ b/cli/build/github.mk @@ -0,0 +1,21 @@ +.PHONY: gh-make-release +.ONESHELL: gh-make-release +gh-make-release: +ifndef CI + $(error must be running in CI) +endif +ifneq ($(shell git rev-parse --abbrev-ref HEAD),release-v$(VERSION)) + $(error must be running on release-v$(VERSION) branch) +endif + $(info $(M) updating files with release version [$(GIT_BRANCH)]) @ + git commit -m "ci: update files to version $(VERSION)" Cargo.toml pkg/brew/$(PACKAGE_NAME).rb + git push origin "release-v$(VERSION)" + git tag -a "v$(VERSION)" -m "ci: tagging v$(VERSION)" + git push origin --tags + gh release create "v$(VERSION)" \ + --title "v$(VERSION)" \ + --notes-file $(CURDIR)/target/dist/release_notes.md \ + $(CURDIR)/target/dist/*.gz \ + $(CURDIR)/target/dist/*.deb \ + $(CURDIR)/target/dist/*.rpm \ + $(CURDIR)/target/dist/SHA256SUMS \ No newline at end of file diff --git a/cli/build/openapi-generator-cli.sh b/cli/build/openapi-generator-cli.sh new file mode 100755 index 000000000..2261a6778 --- /dev/null +++ b/cli/build/openapi-generator-cli.sh @@ -0,0 +1,77 @@ +#!/usr/bin/env bash + +# Source: https://github.com/OpenAPITools/openapi-generator/blob/master/bin/utils/openapi-generator-cli.sh +# License: Apache 2.0 + +#### +# Save as openapi-generator-cli on your PATH. chmod u+x. Enjoy. +# +# This script will query github on every invocation to pull the latest released version +# of openapi-generator. +# +# If you want repeatable executions, you can explicitly set a version via +# OPENAPI_GENERATOR_VERSION +# e.g. (in Bash) +# export OPENAPI_GENERATOR_VERSION=3.1.0 +# openapi-generator-cli.sh +# or +# OPENAPI_GENERATOR_VERSION=3.1.0 openapi-generator-cli.sh +# +# This is also helpful, for example, if you want to evaluate a SNAPSHOT version. +# +# NOTE: Jars are downloaded on demand from maven into the same directory as this script +# for every 'latest' version pulled from github. Consider putting this under its own directory. +#### +set -o pipefail + +for cmd in {mvn,jq,curl}; do + if ! command -v ${cmd} > /dev/null; then + >&2 echo "This script requires '${cmd}' to be installed." + exit 1 + fi +done + +function latest.tag { + local uri="https://api.github.com/repos/${1}/releases" + local ver=$(curl -s ${uri} | jq -r 'first(.[]|select(.prerelease==false)).tag_name') + if [[ $ver == v* ]]; then + ver=${ver:1} + fi + echo $ver +} + +ghrepo=openapitools/openapi-generator +groupid=org.openapitools +artifactid=openapi-generator-cli +ver=${OPENAPI_GENERATOR_VERSION:-$(latest.tag $ghrepo)} + +echo "Using OpenAPI Generator version: ${ver}" + +jar=${artifactid}-${ver}.jar +cachedir=${OPENAPI_GENERATOR_DOWNLOAD_CACHE_DIR} + +DIR=${cachedir:-"$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"} + +if [ ! -d "${DIR}" ]; then + mkdir -p "${DIR}" +fi + +if [ ! -f ${DIR}/${jar} ]; then + repo="central::default::https://repo1.maven.org/maven2/" + if [[ ${ver} =~ ^.*-SNAPSHOT$ ]]; then + repo="central::default::https://oss.sonatype.org/content/repositories/snapshots" + fi + mvn org.apache.maven.plugins:maven-dependency-plugin:2.9:get \ + -DremoteRepositories=${repo} \ + -Dartifact=${groupid}:${artifactid}:${ver} \ + -Dtransitive=false \ + -Ddest=${DIR}/${jar} +fi + +java -ea \ + ${JAVA_OPTS} \ + -Xms512M \ + -Xmx1024M \ + -server \ + -jar ${DIR}/${jar} "$@" + diff --git a/cli/build/package.mk b/cli/build/package.mk new file mode 100644 index 000000000..08bf57e44 --- /dev/null +++ b/cli/build/package.mk @@ -0,0 +1,131 @@ +.PHONY: install-packaging-deb +install-packaging-deb: + $Q if ! command -v cargo-deb > /dev/null; then \ + $(CARGO) install --quiet cargo-deb; \ + fi + +.PHONY: install-packaging-rpm +install-packaging-rpm: + $Q if ! command -v cargo-generate-rpm > /dev/null; then \ + $(CARGO) install --quiet cargo-generate-rpm; \ + fi + +.PHONY: install-packaging-tools +install-packaging-tools: ## Installs tools needed for building distributable packages + $Q $(CARGO) install --quiet cargo-deb cargo-generate-rpm + +target/dist: + $Q mkdir -p $@ + +.PHONY: all-packages +all-packages: deb-packages rpm-packages gz-packages ## Builds all packages for all targets + +target/dist/SHA256SUMS: target/dist + $Q cd target/dist && $(CHECKSUM) * > SHA256SUMS + +.PHONY: checksums +checksums: target/dist/SHA256SUMS ## Generates checksums for all packages + +###################################################################################################################### +### Debian Packages +###################################################################################################################### + +to_debian_arch = $(shell echo $(1) | $(SED) -e 's/x86_64/amd64/' -e 's/aarch64/arm64/' -e 's/armv7/armhf/') +DEBIAN_PACKAGE_TARGETS := $(foreach t, $(TARGETS), target/$(t)/debian/$(PACKAGE_NAME)_$(VERSION)_$(call to_debian_arch, $(firstword $(subst -, , $(t)))).deb) + +.ONESHELL: $(DEBIAN_PACKAGE_TARGETS) +.NOTPARALLEL: $(DEBIAN_PACKAGE_TARGETS) +$(DEBIAN_PACKAGE_TARGETS): $(TARGETS) target/man/$(OUTPUT_BINARY).1.gz target/dist + $Q TARGET="$(word 2, $(subst /, , $(dir $@)))" + # Skip building debs for musl targets + if echo "$(@)" | $(GREP) -q 'musl\|apple'; then \ + exit 0 + fi + if [ ! -f "$(CURDIR)/$(@)" ]; then + if [ -d "$(CURDIR)/target/release" ]; then \ + echo "$(M) removing existing release directory: $(CURDIR)/target/release" + rm -rf "$(CURDIR)/target/release" + fi + echo "$(M) copying target architecture [$${TARGET}] build to target/release directory" + cp -r "$(CURDIR)/target/$${TARGET}/release" "$(CURDIR)/target/release" + echo "$(M) building debian package for target [$${TARGET}]: $(@)" + $(CARGO) deb --package unitctl --no-build --target "$${TARGET}" --output "$(CURDIR)/$(@)" + ln -f "$(CURDIR)/$(@)" "$(CURDIR)/target/dist/" + fi + +.PHONY: deb-packages +deb-packages: install-packaging-deb $(TARGETS) manpage $(DEBIAN_PACKAGE_TARGETS) ## Creates a debian package for the current platform + +###################################################################################################################### +### RPM Packages +###################################################################################################################### + +RPM_PACKAGE_TARGETS := $(foreach t, $(TARGETS), target/$(t)/generate-rpm/$(PACKAGE_NAME)_$(VERSION)_$(firstword $(subst -, , $(t))).rpm) + +.ONESHELL: $(RPM_PACKAGE_TARGETS) +.NOTPARALLEL: $(RPM_PACKAGE_TARGETS) +$(RPM_PACKAGE_TARGETS): $(TARGETS) target/man/$(OUTPUT_BINARY).1.gz target/dist + $Q TARGET="$(word 2, $(subst /, , $(dir $@)))" + ARCH="$(firstword $(subst -, , $(word 2, $(subst /, , $(dir $@)))))" + # Skip building rpms for musl targets + if echo "$(@)" | $(GREP) -q 'musl\|apple'; then \ + exit 0 + fi + if [ ! -f "$(CURDIR)/$(@)" ]; then + if [ -d "$(CURDIR)/target/release" ]; then \ + echo "$(M) removing existing release directory: $(CURDIR)/target/release" + rm -rf "$(CURDIR)/target/release" + fi + echo "$(M) copying target architecture [$${ARCH}] build to target/release directory" + cp -r "$(CURDIR)/target/$${TARGET}/release" "$(CURDIR)/target/release" + echo "$(M) building rpm package: $(@)" + $(CARGO) generate-rpm --package unitctl --arch "$${ARCH}" --target "$${TARGET}" --output "$(CURDIR)/$(@)" + rm -rf "$(CURDIR)/target/release" + ln -f "$(CURDIR)/$(@)" "$(CURDIR)/target/dist/" + fi + +.PHONY: rpm-packages +rpm-packages: install-packaging-rpm $(TARGETS) manpage $(RPM_PACKAGE_TARGETS) ## Creates a rpm package for the current platform + +###################################################################################################################### +### Homebrew Packages +###################################################################################################################### + +.PHONY: homebrew-packages +.ONESHELL: homebrew-packages +homebrew-packages: target/dist/SHA256SUMS ## Modifies the homebrew formula to point to the latest release +ifdef NEW_VERSION + VERSION=$(NEW_VERSION) +endif + $Q \ + VERSION="$(VERSION)" \ + PACKAGE_NAME="$(PACKAGE_NAME)" \ + SRC_REPO="$(SRC_REPO)" \ + AARCH64_UNKNOWN_LINUX_GNU_SHA256="$$($(GREP) $(PACKAGE_NAME)_v$(VERSION)_aarch64-unknown-linux-gnu.tar.gz $(CURDIR)/target/dist/SHA256SUMS | cut -d ' ' -f 1)" \ + X86_64_UNKNOWN_LINUX_GNU_SHA256="$$($(GREP) $(PACKAGE_NAME)_v$(VERSION)_x86_64-unknown-linux-gnu.tar.gz $(CURDIR)/target/dist/SHA256SUMS | cut -d ' ' -f 1)" \ + X86_64_APPLE_DARWIN_SHA256="$$($(GREP) $(PACKAGE_NAME)_v$(VERSION)_x86_64-apple-darwin.tar.gz $(CURDIR)/target/dist/SHA256SUMS | cut -d ' ' -f 1)" \ + AARCH64_APPLE_DARWIN_SHA256="$$($(GREP) $(PACKAGE_NAME)_v$(VERSION)_aarch64-apple-darwin.tar.gz $(CURDIR)/target/dist/SHA256SUMS | cut -d ' ' -f 1)" \ + envsubst < $(CURDIR)/pkg/brew/$(PACKAGE_NAME).rb.template > $(CURDIR)/pkg/brew/$(PACKAGE_NAME).rb + + +###################################################################################################################### +### Tarball Packages +###################################################################################################################### + +GZ_PACKAGE_TARGETS = $(foreach t, $(TARGETS), target/gz/$(t)/$(PACKAGE_NAME)_$(VERSION)_$(firstword $(subst -, , $(t))).tar.gz) + +.ONESHELL: $(GZ_PACKAGE_TARGETS) +$(GZ_PACKAGE_TARGETS): $(TARGETS) target/man/$(PACKAGE_NAME).1.gz target/dist + $Q mkdir -p "$(CURDIR)/target/gz" + TARGET="$(word 3, $(subst /, , $(dir $@)))" + PACKAGE="$(CURDIR)/target/gz/$(PACKAGE_NAME)_v$(VERSION)_$${TARGET}.tar.gz" + if [ ! -f "$${PACKAGE}}" ]; then + tar -cz -f $${PACKAGE} \ + -C $(CURDIR)/target/man $(PACKAGE_NAME).1.gz \ + -C $(CURDIR)/target/$${TARGET}/release $(PACKAGE_NAME) \ + -C $(CURDIR) LICENSE.txt + ln -f "$${PACKAGE}" "$(CURDIR)/target/dist/" + fi + +.PHONE: gz-packages +gz-packages: $(GZ_PACKAGE_TARGETS) ## Creates a gzipped tarball all target platforms diff --git a/cli/build/release.mk b/cli/build/release.mk new file mode 100644 index 000000000..c92a92328 --- /dev/null +++ b/cli/build/release.mk @@ -0,0 +1,53 @@ +.PHONY: changelog +.ONESHELL: changelog +changelog: ## Outputs the changes since the last version committed + $Q VERSION="$(VERSION)" $(CURDIR)/build/changelog.sh + +.ONESHELL: target/dist/release_notes.md +target/dist/release_notes.md: target/dist target/dist/SHA256SUMS + $(info $(M) building release notes) @ + $Q echo "# Release Notes" > target/dist/release_notes.md + VERSION="$(VERSION)" $(CURDIR)/build/changelog.sh >> target/dist/release_notes.md + echo '## SHA256 Checksums' >> target/dist/release_notes.md + echo '```' >> target/dist/release_notes.md + cat target/dist/SHA256SUMS >> target/dist/release_notes.md + echo '```' >> target/dist/release_notes.md + +.PHONY: release-notes +release-notes: target/dist/release_notes.md ## Build release notes + +.PHONY: version +version: ## Outputs the current version + $Q echo "Version: $(VERSION)" + +.PHONY: version-update +.ONESHELL: version-update +version-update: ## Prompts for a new version + $(info $(M) updating repository to new version) @ + $Q echo " last committed version: $(LAST_VERSION)" + $Q echo " Cargo.toml file version : $(VERSION)" + read -p " Enter new version in the format (MAJOR.MINOR.PATCH): " version + $Q echo "$$version" | $(GREP) -qE '^[0-9]+\.[0-9]+\.[0-9]+-?.*$$' || \ + (echo "invalid version identifier: $$version" && exit 1) && \ + $(SED) -i "s/^version\s*=.*$$/version = \"$$version\"/" $(CURDIR)/unit-client-rs/Cargo.toml + $(SED) -i "s/^version\s*=.*$$/version = \"$$version\"/" $(CURDIR)/unitctl/Cargo.toml + $(SED) -i "s/^version\s*=.*$$/version = \"$$version\"/" $(CURDIR)/unit-openapi/Cargo.toml + $(SED) -i "s/^\s*\"packageVersion\":\s*.*$$/ \"packageVersion\": \"$$version\",/" $(CURDIR)/openapi-config.json + @ VERSION=$(shell $(GREP) -Po '^version\s+=\s+"\K.*?(?=")' $(CURDIR)/unitctl/Cargo.toml) + +.PHONY: version-release +.ONESHELL: version-release +version-release: ## Change from a pre-release to full release version + $Q echo "$(VERSION)" | $(GREP) -qE '^[0-9]+\.[0-9]+\.[0-9]+-beta$$' || \ + (echo "invalid version identifier - must contain suffix -beta: $(VERSION)" && exit 1) + export NEW_VERSION="$(shell echo $(VERSION) | $(SED) -e 's/-beta$$//')" + $(SED) -i "s/^version\s*=.*$$/version = \"$$NEW_VERSION\"/" $(CURDIR)/unit-client-rs/Cargo.toml + $(SED) -i "s/^version\s*=.*$$/version = \"$$NEW_VERSION\"/" $(CURDIR)/unitctl/Cargo.toml + $(SED) -i "s/^version\s*=.*$$/version = \"$$NEW_VERSION\"/" $(CURDIR)/unit-openapi/Cargo.toml + $(SED) -i "s/^\s*\"packageVersion\":\s*.*$$/ \"packageVersion\": \"$$NEW_VERSION\",/" $(CURDIR)/openapi-config.json + @ VERSION=$(shell $(GREP) -Po '^version\s+=\s+"\K.*?(?=")' $(CURDIR)/unitctl/Cargo.toml) + +.PHONY: cargo-release +cargo-release: ## Releases a new version to crates.io + $(info $(M) releasing version $(VERSION) to crates.io) @ + $Q $(CARGO) publish \ No newline at end of file diff --git a/cli/man/unitctl.1 b/cli/man/unitctl.1 new file mode 100644 index 000000000..2067f202b --- /dev/null +++ b/cli/man/unitctl.1 @@ -0,0 +1,30 @@ +.\" Manpage for unitctl +.\" +.TH UNITCTL "1" "2022-12-29" "%%VERSION%%" "unitctl" +.SH NAME +unitctl \- NGINX UNIT Control Utility +.SH SYNOPSIS +unitctl [\fI\,FLAGS\/\fR] [\fI\,OPTIONS\/\fR] [\fI\,FILE\/\fR]... +.SH DESCRIPTION +WRITE ME +. +.SH "REPORTING BUGS" +Report any issues on the project issue tracker at: +.br +\fB\fR +. +.SH ACKNOWLEDGEMENTS +WRITE ME +. +.SH "SEE ALSO" +NGINX UNIT: \fB\fR +. +.SH AUTHOR +Elijah Zupancic \fB\fR +. +.SH COPYRIGHT +Copyright \(co 2022 F5. All Rights Reserved. +.br +License: Apache License 2.0 (Apache-2.0) +.br +Full License Text: \ No newline at end of file diff --git a/cli/openapi-config.json b/cli/openapi-config.json new file mode 100644 index 000000000..783c87409 --- /dev/null +++ b/cli/openapi-config.json @@ -0,0 +1,6 @@ +{ + "packageName": "unit-openapi", + "packageVersion": "0.4.0-beta", + "library": "hyper", + "preferUnsignedInt": true +} \ No newline at end of file diff --git a/cli/pkg/brew/unitctl.rb b/cli/pkg/brew/unitctl.rb new file mode 100644 index 000000000..771f2806b --- /dev/null +++ b/cli/pkg/brew/unitctl.rb @@ -0,0 +1,29 @@ +class Unitctl < Formula + desc "CLI interface to the NGINX UNIT Control API" + homepage "https://github.com/nginxinc/unit-rust-sdk" + version "0.3.0" + package_name = "unitctl" + src_repo = "https://github.com/nginxinc/unit-rust-sdk" + + if OS.mac? and Hardware::CPU.intel? + url "#{src_repo}/releases/download/v#{version}/#{package_name}_v#{version}_x86_64-apple-darwin.tar.gz" + sha256 "3e476850d1fc08aabc3cb25d19d42d171f52d55cea887aec754d47d1142c3638" + elsif OS.mac? and Hardware::CPU.arm? + url "#{src_repo}/releases/download/v#{version}/#{package_name}_#{version}_aarch64-apple-darwin.tar.gz" + sha256 "c1ec83ae67c08640f1712fba1c8aa305c063570fb7f96203228bf75413468bab" + elsif OS.linux? and Hardware::CPU.intel? + url "#{src_repo}/releases/download/v#{version}/#{package_name}_#{version}_x86_64-unknown-linux-gnu.tar.gz" + sha256 "9616687a7e4319c8399c0071059e6c1bb80b7e5b616714edc81a92717264a70f" + elsif OS.linux? and Hardware::CPU.arm? and Hardware::CPU.is_64_bit? + url "#{src_repo}/releases/download/v#{version}/#{package_name}_#{version}_aarch64-unknown-linux-gnu.tar.gz" + sha256 "88c2c7a8bc3d1930080c2b9a397a33e156ae4f876903b6565775270584055534" + else + odie "Unsupported architecture" + end + + + def install + bin.install "unitctl" + man1.install "unitctl.1.gz" + end +end diff --git a/cli/pkg/brew/unitctl.rb.template b/cli/pkg/brew/unitctl.rb.template new file mode 100644 index 000000000..db6991f68 --- /dev/null +++ b/cli/pkg/brew/unitctl.rb.template @@ -0,0 +1,29 @@ +class Unitctl < Formula + desc "CLI interface to the NGINX UNIT Control API" + homepage "https://github.com/nginxinc/unit-rust-sdk" + version "$VERSION" + package_name = "$PACKAGE_NAME" + src_repo = "$SRC_REPO" + + if OS.mac? and Hardware::CPU.intel? + url "#{src_repo}/releases/download/v#{version}/#{package_name}_v#{version}_x86_64-apple-darwin.tar.gz" + sha256 "$X86_64_APPLE_DARWIN_SHA256" + elsif OS.mac? and Hardware::CPU.arm? + url "#{src_repo}/releases/download/v#{version}/#{package_name}_#{version}_aarch64-apple-darwin.tar.gz" + sha256 "$AARCH64_APPLE_DARWIN_SHA256" + elsif OS.linux? and Hardware::CPU.intel? + url "#{src_repo}/releases/download/v#{version}/#{package_name}_#{version}_x86_64-unknown-linux-gnu.tar.gz" + sha256 "$X86_64_UNKNOWN_LINUX_GNU_SHA256" + elsif OS.linux? and Hardware::CPU.arm? and Hardware::CPU.is_64_bit? + url "#{src_repo}/releases/download/v#{version}/#{package_name}_#{version}_aarch64-unknown-linux-gnu.tar.gz" + sha256 "$AARCH64_UNKNOWN_LINUX_GNU_SHA256" + else + odie "Unsupported architecture" + end + + + def install + bin.install "unitctl" + man1.install "unitctl.1.gz" + end +end diff --git a/cli/rustfmt.toml b/cli/rustfmt.toml new file mode 100644 index 000000000..866c75610 --- /dev/null +++ b/cli/rustfmt.toml @@ -0,0 +1 @@ +max_width = 120 \ No newline at end of file diff --git a/cli/unit-client-rs/Cargo.toml b/cli/unit-client-rs/Cargo.toml new file mode 100644 index 000000000..81e062ff2 --- /dev/null +++ b/cli/unit-client-rs/Cargo.toml @@ -0,0 +1,32 @@ +[package] +name = "unit-client-rs" +version = "0.4.0-beta" +authors = ["Elijah Zupancic"] +edition = "2021" +license = "Apache-2.0" + +[lib] +name = "unit_client_rs" + +[features] +# this preserves the ordering of json +default = ["serde_json/preserve_order"] + +[dependencies] +openssl = { version = "0.10", features = ["vendored"] } +custom_error = "1.9" +hyper = { version = "0.14", features = ["stream"] } +hyper-tls = "0.5" +hyperlocal = "0.8" +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +sysinfo = "0.30.5" +tokio = { version = "1.34", features = ["macros"] } +futures = "0.3" +hex = "0.4" +which = "5.0" + +unit-openapi = { path = "../unit-openapi" } + +[dev-dependencies] +rand = "0.8.5" diff --git a/cli/unit-client-rs/src/control_socket_address.rs b/cli/unit-client-rs/src/control_socket_address.rs new file mode 100644 index 000000000..b9ae5afc8 --- /dev/null +++ b/cli/unit-client-rs/src/control_socket_address.rs @@ -0,0 +1,571 @@ +use crate::control_socket_address::ControlSocket::{TcpSocket, UnixLocalAbstractSocket, UnixLocalSocket}; +use crate::control_socket_address::ControlSocketScheme::{HTTP, HTTPS}; +use crate::unit_client::UnitClientError; +use hyper::http::uri::{Authority, PathAndQuery}; +use hyper::Uri; +use std::fmt::{Display, Formatter}; +use std::fs; +use std::os::unix::fs::FileTypeExt; +use std::path::{PathBuf, MAIN_SEPARATOR}; + +type AbstractSocketName = String; +type UnixSocketPath = PathBuf; +type Port = u16; + +#[derive(Debug, Clone)] +pub enum ControlSocket { + UnixLocalAbstractSocket(AbstractSocketName), + UnixLocalSocket(UnixSocketPath), + TcpSocket(Uri), +} + +#[derive(Debug)] +pub enum ControlSocketScheme { + HTTP, + HTTPS, +} + +impl ControlSocketScheme { + fn port(&self) -> Port { + match self { + HTTP => 80, + HTTPS => 443, + } + } +} + +impl ControlSocket { + pub fn socket_scheme(&self) -> ControlSocketScheme { + match self { + UnixLocalAbstractSocket(_) => ControlSocketScheme::HTTP, + UnixLocalSocket(_) => ControlSocketScheme::HTTP, + TcpSocket(uri) => match uri.scheme_str().expect("Scheme should not be None") { + "http" => ControlSocketScheme::HTTP, + "https" => ControlSocketScheme::HTTPS, + _ => unreachable!("Scheme should be http or https"), + }, + } + } + + pub fn create_uri_with_path(&self, str_path: &str) -> Uri { + match self { + UnixLocalAbstractSocket(name) => { + let socket_path = PathBuf::from(format!("@{}", name)); + hyperlocal::Uri::new(socket_path, str_path).into() + } + UnixLocalSocket(socket_path) => hyperlocal::Uri::new(socket_path, str_path).into(), + TcpSocket(uri) => { + if str_path.is_empty() { + uri.clone() + } else { + let authority = uri.authority().expect("Authority should not be None"); + Uri::builder() + .scheme(uri.scheme_str().expect("Scheme should not be None")) + .authority(authority.clone()) + .path_and_query(str_path) + .build() + .expect("URI should be valid") + } + } + } + } +} + +impl Display for ControlSocket { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + UnixLocalAbstractSocket(name) => f.write_fmt(format_args!("unix:@{}", name)), + UnixLocalSocket(path) => f.write_fmt(format_args!("unix:{}", path.to_string_lossy())), + TcpSocket(uri) => uri.fmt(f), + } + } +} + +impl From for String { + fn from(val: ControlSocket) -> Self { + val.to_string() + } +} + +impl From for PathBuf { + fn from(val: ControlSocket) -> Self { + match val { + UnixLocalAbstractSocket(socket_name) => PathBuf::from(format!("@{}", socket_name)), + UnixLocalSocket(socket_path) => socket_path, + TcpSocket(_) => PathBuf::default(), + } + } +} + +impl From for Uri { + fn from(val: ControlSocket) -> Self { + val.create_uri_with_path("") + } +} + +impl ControlSocket { + pub fn validate_http_address(uri: Uri) -> Result<(), UnitClientError> { + let http_address = uri.to_string(); + if uri.authority().is_none() { + return Err(UnitClientError::TcpSocketAddressParseError { + message: "No authority found in socket address".to_string(), + control_socket_address: http_address, + }); + } + if uri.port_u16().is_none() { + return Err(UnitClientError::TcpSocketAddressNoPortError { + control_socket_address: http_address, + }); + } + if !(uri.path().is_empty() || uri.path().eq("/")) { + return Err(UnitClientError::TcpSocketAddressParseError { + message: format!("Path is not empty or is not / [path={}]", uri.path()), + control_socket_address: http_address, + }); + } + + Ok(()) + } + + pub fn validate_unix_address(socket: PathBuf) -> Result<(), UnitClientError> { + if !socket.exists() { + return Err(UnitClientError::UnixSocketNotFound { + control_socket_address: socket.to_string_lossy().to_string(), + }); + } + let metadata = fs::metadata(&socket).map_err(|error| UnitClientError::UnixSocketAddressError { + source: error, + control_socket_address: socket.to_string_lossy().to_string(), + })?; + let file_type = metadata.file_type(); + if !file_type.is_socket() { + return Err(UnitClientError::UnixSocketAddressError { + source: std::io::Error::new(std::io::ErrorKind::Other, "Control socket path is not a socket"), + control_socket_address: socket.to_string_lossy().to_string(), + }); + } + + Ok(()) + } + + pub fn validate(&self) -> Result { + match self { + UnixLocalAbstractSocket(socket_name) => { + let socket_path = PathBuf::from(format!("@{}", socket_name)); + Self::validate_unix_address(socket_path.clone()) + } + UnixLocalSocket(socket_path) => Self::validate_unix_address(socket_path.clone()), + TcpSocket(socket_uri) => Self::validate_http_address(socket_uri.clone()), + } + .map(|_| self.to_owned()) + } + + fn normalize_and_parse_http_address(http_address: String) -> Result { + // Convert *:1 style network addresses to URI format + let address = if http_address.starts_with("*:") { + http_address.replacen("*:", "http://127.0.0.1:", 1) + // Add scheme if not present + } else if !(http_address.starts_with("http://") || http_address.starts_with("https://")) { + format!("http://{}", http_address) + } else { + http_address.to_owned() + }; + + let is_https = address.starts_with("https://"); + + let parsed_uri = + Uri::try_from(address.as_str()).map_err(|error| UnitClientError::TcpSocketAddressUriError { + source: error, + control_socket_address: address, + })?; + let authority = parsed_uri.authority().expect("Authority should not be None"); + let expected_port = if is_https { HTTPS.port() } else { HTTP.port() }; + let normalized_authority = match authority.port_u16() { + Some(_) => authority.to_owned(), + None => { + let host = format!("{}:{}", authority.host(), expected_port); + Authority::try_from(host.as_str()).expect("Authority should be valid") + } + }; + + let normalized_uri = Uri::builder() + .scheme(parsed_uri.scheme_str().expect("Scheme should not be None")) + .authority(normalized_authority) + .path_and_query(PathAndQuery::from_static("")) + .build() + .map_err(|error| UnitClientError::TcpSocketAddressParseError { + message: error.to_string(), + control_socket_address: http_address.clone(), + })?; + + Ok(normalized_uri) + } + + /// Flexibly parse a textual representation of a socket address + fn parse_address>(socket_address: S) -> Result { + let full_socket_address: String = socket_address.into(); + let socket_prefix = "unix:"; + let socket_uri_prefix = "unix://"; + let mut buf = String::with_capacity(socket_prefix.len()); + for (i, c) in full_socket_address.char_indices() { + // Abstract unix socket with no prefix + if i == 0 && c == '@' { + return Ok(UnixLocalAbstractSocket(full_socket_address[1..].to_string())); + } + buf.push(c); + // Unix socket with prefix + if i == socket_prefix.len() - 1 && buf.eq(socket_prefix) { + let path_text = full_socket_address[socket_prefix.len()..].to_string(); + // Return here if this URI does not have a scheme followed by double slashes + if !path_text.starts_with("//") { + return match path_text.strip_prefix('@') { + Some(name) => Ok(UnixLocalAbstractSocket(name.to_string())), + None => { + let path = PathBuf::from(path_text); + Ok(UnixLocalSocket(path)) + } + }; + } + } + + // Unix socket with URI prefix + if i == socket_uri_prefix.len() - 1 && buf.eq(socket_uri_prefix) { + let uri = Uri::try_from(full_socket_address.as_str()).map_err(|error| { + UnitClientError::TcpSocketAddressParseError { + message: error.to_string(), + control_socket_address: full_socket_address.clone(), + } + })?; + return ControlSocket::try_from(uri); + } + } + + /* Sockets on Windows are not supported, so there is no need to check + * if the socket address is a valid path, so we can do this shortcut + * here to see if a path was specified without a unix: prefix. */ + if buf.starts_with(MAIN_SEPARATOR) { + let path = PathBuf::from(buf); + return Ok(UnixLocalSocket(path)); + } + + let uri = Self::normalize_and_parse_http_address(buf)?; + Ok(TcpSocket(uri)) + } + + pub fn is_local_socket(&self) -> bool { + match self { + UnixLocalAbstractSocket(_) | UnixLocalSocket(_) => true, + TcpSocket(_) => false, + } + } +} + +impl TryFrom for ControlSocket { + type Error = UnitClientError; + + fn try_from(socket_address: String) -> Result { + ControlSocket::parse_address(socket_address.as_str()) + } +} + +impl TryFrom<&str> for ControlSocket { + type Error = UnitClientError; + + fn try_from(socket_address: &str) -> Result { + ControlSocket::parse_address(socket_address) + } +} + +impl TryFrom for ControlSocket { + type Error = UnitClientError; + + fn try_from(socket_uri: Uri) -> Result { + match socket_uri.scheme_str() { + // URIs with the unix scheme will have a hostname that is a hex encoded string + // representing the path to the socket + Some("unix") => { + let host = match socket_uri.host() { + Some(host) => host, + None => { + return Err(UnitClientError::TcpSocketAddressParseError { + message: "No host found in socket address".to_string(), + control_socket_address: socket_uri.to_string(), + }) + } + }; + let bytes = hex::decode(host).map_err(|error| UnitClientError::TcpSocketAddressParseError { + message: error.to_string(), + control_socket_address: socket_uri.to_string(), + })?; + let path = String::from_utf8_lossy(&bytes); + ControlSocket::parse_address(path) + } + Some("http") | Some("https") => Ok(TcpSocket(socket_uri)), + Some(unknown) => Err(UnitClientError::TcpSocketAddressParseError { + message: format!("Unsupported scheme found in socket address: {}", unknown).to_string(), + control_socket_address: socket_uri.to_string(), + }), + None => Err(UnitClientError::TcpSocketAddressParseError { + message: "No scheme found in socket address".to_string(), + control_socket_address: socket_uri.to_string(), + }), + } + } +} + +#[cfg(test)] +mod tests { + use rand::distributions::{Alphanumeric, DistString}; + use std::env::temp_dir; + use std::fmt::Display; + use std::io; + use std::os::unix::net::UnixListener; + + use super::*; + + struct TempSocket { + socket_path: PathBuf, + _listener: UnixListener, + } + + impl TempSocket { + fn shutdown(&mut self) -> io::Result<()> { + fs::remove_file(&self.socket_path) + } + } + + impl Display for TempSocket { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "unix:{}", self.socket_path.to_string_lossy().to_string()) + } + } + + impl Drop for TempSocket { + fn drop(&mut self) { + self.shutdown() + .expect(format!("Unable to shutdown socket {}", self.socket_path.to_string_lossy()).as_str()); + } + } + + #[test] + fn will_error_with_nonexistent_unix_socket() { + let socket_address = "unix:/tmp/some_random_filename_that_doesnt_exist.sock"; + let control_socket = + ControlSocket::try_from(socket_address).expect("No error should be returned until validate() is called"); + assert!(control_socket.is_local_socket(), "Not parsed as a local socket"); + assert!(control_socket.validate().is_err(), "Socket should not be valid"); + } + + #[test] + fn can_parse_socket_with_prefix() { + let temp_socket = create_file_socket().expect("Unable to create socket"); + let control_socket = ControlSocket::try_from(temp_socket.to_string()).expect("Error parsing good socket path"); + assert!(control_socket.is_local_socket(), "Not parsed as a local socket"); + if let Err(e) = control_socket.validate() { + panic!("Socket should be valid: {}", e); + } + } + + #[test] + fn can_parse_socket_from_uri() { + let temp_socket = create_file_socket().expect("Unable to create socket"); + let uri: Uri = hyperlocal::Uri::new(temp_socket.socket_path.clone(), "").into(); + let control_socket = ControlSocket::try_from(uri).expect("Error parsing good socket path"); + assert!(control_socket.is_local_socket(), "Not parsed as a local socket"); + if let Err(e) = control_socket.validate() { + panic!("Socket should be valid: {}", e); + } + } + + #[test] + fn can_parse_socket_from_uri_text() { + let temp_socket = create_file_socket().expect("Unable to create socket"); + let uri: Uri = hyperlocal::Uri::new(temp_socket.socket_path.clone(), "").into(); + let control_socket = ControlSocket::parse_address(uri.to_string()).expect("Error parsing good socket path"); + assert!(control_socket.is_local_socket(), "Not parsed as a local socket"); + if let Err(e) = control_socket.validate() { + panic!("Socket for input text should be valid: {}", e); + } + } + + #[test] + #[cfg(target_os = "linux")] + fn can_parse_abstract_socket_from_uri() { + let temp_socket = create_abstract_socket().expect("Unable to create socket"); + let uri: Uri = hyperlocal::Uri::new(temp_socket.socket_path.clone(), "").into(); + let control_socket = ControlSocket::try_from(uri).expect("Error parsing good socket path"); + assert!(control_socket.is_local_socket(), "Not parsed as a local socket"); + if let Err(e) = control_socket.validate() { + panic!("Socket should be valid: {}", e); + } + } + + #[test] + #[cfg(target_os = "linux")] + fn can_parse_abstract_socket_from_uri_text() { + let temp_socket = create_abstract_socket().expect("Unable to create socket"); + let uri: Uri = hyperlocal::Uri::new(temp_socket.socket_path.clone(), "").into(); + let control_socket = ControlSocket::parse_address(uri.to_string()).expect("Error parsing good socket path"); + assert!(control_socket.is_local_socket(), "Not parsed as a local socket"); + if let Err(e) = control_socket.validate() { + panic!("Socket should be valid: {}", e); + } + } + + #[test] + fn can_parse_socket_without_prefix() { + let temp_socket = create_file_socket().expect("Unable to create socket"); + let control_socket = ControlSocket::try_from(temp_socket.socket_path.to_string_lossy().to_string()) + .expect("Error parsing good socket path"); + assert!(control_socket.is_local_socket(), "Not parsed as a local socket"); + if let Err(e) = control_socket.validate() { + panic!("Socket should be valid: {}", e); + } + } + + #[cfg(target_os = "linux")] + #[test] + fn can_parse_abstract_socket() { + let temp_socket = create_abstract_socket().expect("Unable to create socket"); + let control_socket = ControlSocket::try_from(temp_socket.to_string()).expect("Error parsing good socket path"); + assert!(control_socket.is_local_socket(), "Not parsed as a local socket"); + if let Err(e) = control_socket.validate() { + panic!("Socket should be valid: {}", e); + } + } + + #[test] + fn can_normalize_good_http_socket_addresses() { + let valid_socket_addresses = vec![ + "http://127.0.0.1:8080", + "https://127.0.0.1:8080", + "http://127.0.0.1:8080/", + "127.0.0.1:8080", + "http://0.0.0.0:8080", + "https://0.0.0.0:8080", + "http://0.0.0.0:8080/", + "0.0.0.0:8080", + "http://localhost:8080", + "https://localhost:8080", + "http://localhost:8080/", + "localhost:8080", + "http://[::1]:8080", + "https://[::1]:8080", + "http://[::1]:8080/", + "[::1]:8080", + "http://[0000:0000:0000:0000:0000:0000:0000:0000]:8080", + "https://[0000:0000:0000:0000:0000:0000:0000:0000]:8080", + "http://[0000:0000:0000:0000:0000:0000:0000:0000]:8080/", + "[0000:0000:0000:0000:0000:0000:0000:0000]:8080", + ]; + for socket_address in valid_socket_addresses { + let mut expected = if socket_address.starts_with("http") { + socket_address.to_string().trim_end_matches('/').to_string() + } else { + format!("http://{}", socket_address).trim_end_matches('/').to_string() + }; + expected.push('/'); + + let control_socket = ControlSocket::try_from(socket_address).expect("Error parsing good socket path"); + assert!(!control_socket.is_local_socket(), "Not parsed as a local socket"); + if let Err(e) = control_socket.validate() { + panic!("Socket should be valid: {}", e); + } + } + } + + #[test] + fn can_normalize_wildcard_http_socket_address() { + let socket_address = "*:8080"; + let expected = "http://127.0.0.1:8080/"; + let normalized_result = ControlSocket::normalize_and_parse_http_address(socket_address.to_string()); + let normalized = normalized_result + .expect("Unable to normalize socket address") + .to_string(); + assert_eq!(normalized, expected); + } + + #[test] + fn can_normalize_http_socket_address_with_no_port() { + let socket_address = "http://localhost"; + let expected = "http://localhost:80/"; + let normalized_result = ControlSocket::normalize_and_parse_http_address(socket_address.to_string()); + let normalized = normalized_result + .expect("Unable to normalize socket address") + .to_string(); + assert_eq!(normalized, expected); + } + + #[test] + fn can_normalize_https_socket_address_with_no_port() { + let socket_address = "https://localhost"; + let expected = "https://localhost:443/"; + let normalized_result = ControlSocket::normalize_and_parse_http_address(socket_address.to_string()); + let normalized = normalized_result + .expect("Unable to normalize socket address") + .to_string(); + assert_eq!(normalized, expected); + } + + #[test] + fn can_parse_http_addresses() { + let valid_socket_addresses = vec![ + "http://127.0.0.1:8080", + "https://127.0.0.1:8080", + "http://127.0.0.1:8080/", + "127.0.0.1:8080", + "http://0.0.0.0:8080", + "https://0.0.0.0:8080", + "http://0.0.0.0:8080/", + "0.0.0.0:8080", + "http://localhost:8080", + "https://localhost:8080", + "http://localhost:8080/", + "localhost:8080", + "http://[::1]:8080", + "https://[::1]:8080", + "http://[::1]:8080/", + "[::1]:8080", + "http://[0000:0000:0000:0000:0000:0000:0000:0000]:8080", + "https://[0000:0000:0000:0000:0000:0000:0000:0000]:8080", + "http://[0000:0000:0000:0000:0000:0000:0000:0000]:8080/", + "[0000:0000:0000:0000:0000:0000:0000:0000]:8080", + ]; + for socket_address in valid_socket_addresses { + let mut expected = if socket_address.starts_with("http") { + socket_address.to_string().trim_end_matches('/').to_string() + } else { + format!("http://{}", socket_address).trim_end_matches('/').to_string() + }; + expected.push('/'); + + let normalized = ControlSocket::normalize_and_parse_http_address(socket_address.to_string()) + .expect("Unable to normalize socket address") + .to_string(); + assert_eq!(normalized, expected); + } + } + + fn create_file_socket() -> Result { + let random = Alphanumeric.sample_string(&mut rand::thread_rng(), 10); + let socket_name = format!("unit-client-socket-test-{}.sock", random); + let socket_path = temp_dir().join(socket_name); + let listener = UnixListener::bind(&socket_path)?; + Ok(TempSocket { + socket_path, + _listener: listener, + }) + } + + #[cfg(target_os = "linux")] + fn create_abstract_socket() -> Result { + let random = Alphanumeric.sample_string(&mut rand::thread_rng(), 10); + let socket_name = format!("@unit-client-socket-test-{}.sock", random); + let socket_path = PathBuf::from(socket_name); + let listener = UnixListener::bind(&socket_path)?; + Ok(TempSocket { + socket_path, + _listener: listener, + }) + } +} diff --git a/cli/unit-client-rs/src/lib.rs b/cli/unit-client-rs/src/lib.rs new file mode 100644 index 000000000..dca8a86f9 --- /dev/null +++ b/cli/unit-client-rs/src/lib.rs @@ -0,0 +1,15 @@ +extern crate custom_error; +extern crate futures; +extern crate hyper; +extern crate hyper_tls; +extern crate hyperlocal; +extern crate serde; +extern crate serde_json; +pub mod control_socket_address; +mod runtime_flags; +pub mod unit_client; +mod unitd_cmd; +pub mod unitd_configure_options; +pub mod unitd_instance; +pub mod unitd_process; +mod unitd_process_user; diff --git a/cli/unit-client-rs/src/runtime_flags.rs b/cli/unit-client-rs/src/runtime_flags.rs new file mode 100644 index 000000000..7b31274d9 --- /dev/null +++ b/cli/unit-client-rs/src/runtime_flags.rs @@ -0,0 +1,90 @@ +use std::borrow::Cow; +use std::fmt; +use std::fmt::Display; +use std::path::{Path, PathBuf}; + +#[derive(Debug, Clone)] +pub struct RuntimeFlags { + pub flags: Cow<'static, str>, +} + +impl Display for RuntimeFlags { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.flags) + } +} + +impl RuntimeFlags { + pub fn new(flags: S) -> RuntimeFlags + where + S: Into, + { + RuntimeFlags { + flags: Cow::from(flags.into()), + } + } + + pub fn has_flag(&self, flag_name: &str) -> bool { + self.flags.contains(format!("--{}", flag_name).as_str()) + } + + pub fn get_flag_value(&self, flag_name: &str) -> Option { + let flag_parts = self.flags.split_ascii_whitespace().collect::>(); + for (i, flag) in flag_parts.iter().enumerate() { + if let Some(name) = flag.strip_prefix("--") { + /* If there is no flag value after the current one, there is by definition no + * flag value for the current flag. */ + let index_lt_len = flag_parts.len() > i + 1; + if index_lt_len { + let next_value_isnt_flag = !flag_parts[i + 1].starts_with("--"); + if name.eq(flag_name) && next_value_isnt_flag { + return Some(flag_parts[i + 1].to_string()); + } + } + } + } + None + } + + pub fn control_api_socket_address(&self) -> Option { + self.get_flag_value("control") + } + + pub fn pid_path(&self) -> Option> { + self.get_flag_value("pid") + .map(PathBuf::from) + .map(PathBuf::into_boxed_path) + } + + pub fn log_path(&self) -> Option> { + self.get_flag_value("log") + .map(PathBuf::from) + .map(PathBuf::into_boxed_path) + } + + pub fn modules_directory(&self) -> Option> { + self.get_flag_value("modules") + .map(PathBuf::from) + .map(PathBuf::into_boxed_path) + } + + pub fn state_directory(&self) -> Option> { + self.get_flag_value("state") + .map(PathBuf::from) + .map(PathBuf::into_boxed_path) + } + + pub fn tmp_directory(&self) -> Option> { + self.get_flag_value("tmp") + .map(PathBuf::from) + .map(PathBuf::into_boxed_path) + } + + pub fn user(&self) -> Option { + self.get_flag_value("user").map(String::from) + } + + pub fn group(&self) -> Option { + self.get_flag_value("group").map(String::from) + } +} diff --git a/cli/unit-client-rs/src/unit_client.rs b/cli/unit-client-rs/src/unit_client.rs new file mode 100644 index 000000000..b856fd206 --- /dev/null +++ b/cli/unit-client-rs/src/unit_client.rs @@ -0,0 +1,393 @@ +use std::collections::HashMap; +use std::error::Error as StdError; +use std::fmt::Debug; +use std::future::Future; +use std::rc::Rc; +use std::{fmt, io}; + +use custom_error::custom_error; +use hyper::body::{Buf, HttpBody}; +use hyper::client::{HttpConnector, ResponseFuture}; +use hyper::Error as HyperError; +use hyper::{http, Body, Client, Request}; +use hyper_tls::HttpsConnector; +use hyperlocal::{UnixClientExt, UnixConnector}; +use serde::{Deserialize, Serialize}; +use tokio::runtime::Runtime; + +use crate::control_socket_address::ControlSocket; +use unit_openapi::apis::configuration::Configuration; +use unit_openapi::apis::{Error as OpenAPIError, StatusApi}; +use unit_openapi::apis::{ListenersApi, ListenersApiClient, StatusApiClient}; +use unit_openapi::models::{ConfigListener, Status}; + +const USER_AGENT: &str = concat!("UNIT CLI/", env!("CARGO_PKG_VERSION"), "/rust"); + +custom_error! {pub UnitClientError + OpenAPIError { source: OpenAPIError } = "OpenAPI error", + JsonError { source: serde_json::Error, + path: String} = "JSON error [path={path}]", + HyperError { source: hyper::Error, + control_socket_address: String, + path: String} = "Communications error [control_socket_address={control_socket_address}, path={path}]: {source}", + HttpRequestError { source: http::Error, + path: String} = "HTTP error [path={path}]", + HttpResponseError { status: http::StatusCode, + path: String, + body: String} = "HTTP response error [path={path}, status={status}]:\n{body}", + HttpResponseJsonBodyError { status: http::StatusCode, + path: String, + error: String, + detail: String} = "HTTP response error [path={path}, status={status}]:\n Error: {error}\n Detail: {detail}", + IoError { source: io::Error, socket: String } = "IO error [socket={socket}]", + UnixSocketAddressError { + source: io::Error, + control_socket_address: String + } = "Invalid unix domain socket address [control_socket_address={control_socket_address}]", + SocketPermissionsError { control_socket_address: String } = + "Insufficient permissions to connect to control socket [control_socket_address={control_socket_address}]", + UnixSocketNotFound { control_socket_address: String } = "Unix socket not found [control_socket_address={control_socket_address}]", + TcpSocketAddressUriError { + source: http::uri::InvalidUri, + control_socket_address: String + } = "Invalid TCP socket address [control_socket_address={control_socket_address}]", + TcpSocketAddressParseError { + message: String, + control_socket_address: String + } = "Invalid TCP socket address [control_socket_address={control_socket_address}]: {message}", + TcpSocketAddressNoPortError { + control_socket_address: String + } = "TCP socket address does not have a port specified [control_socket_address={control_socket_address}]", + UnitdProcessParseError { + message: String, + pid: u64 + } = "{message} for [pid={pid}]", + UnitdProcessExecError { + source: Box, + message: String, + executable_path: String, + pid: u64 + } = "{message} for [pid={pid}, executable_path={executable_path}]: {source}", +} + +impl UnitClientError { + fn new(error: HyperError, control_socket_address: String, path: String) -> Self { + if error.is_connect() { + if let Some(source) = error.source() { + if let Some(io_error) = source.downcast_ref::() { + if io_error.kind().eq(&io::ErrorKind::PermissionDenied) { + return UnitClientError::SocketPermissionsError { control_socket_address }; + } + } + } + } + + UnitClientError::HyperError { + source: error, + control_socket_address, + path, + } + } +} + +macro_rules! new_openapi_client_from_hyper_client { + ($unit_client:expr, $hyper_client: ident, $api_client:ident, $api_trait:ident) => {{ + let config = Configuration { + base_path: $unit_client.control_socket.create_uri_with_path("/").to_string(), + user_agent: Some(format!("{}/OpenAPI-Generator", USER_AGENT).to_owned()), + client: $hyper_client.clone(), + basic_auth: None, + oauth_access_token: None, + api_key: None, + }; + let rc_config = Rc::new(config); + Box::new($api_client::new(rc_config)) as Box + }}; +} + +macro_rules! new_openapi_client { + ($unit_client:expr, $api_client:ident, $api_trait:ident) => { + match &*$unit_client.client { + RemoteClient::Tcp { client } => { + new_openapi_client_from_hyper_client!($unit_client, client, $api_client, $api_trait) + } + RemoteClient::Unix { client } => { + new_openapi_client_from_hyper_client!($unit_client, client, $api_client, $api_trait) + } + } + }; +} + +#[derive(Clone)] +pub enum RemoteClient +where + B: HttpBody + Send + 'static, + B::Data: Send, + B::Error: Into>, +{ + Unix { + client: Client, + }, + Tcp { + client: Client, B>, + }, +} + +impl RemoteClient +where + B: HttpBody + Send + 'static, + B::Data: Send, + B::Error: Into>, +{ + fn client_name(&self) -> &str { + match self { + RemoteClient::Unix { .. } => "Client", + RemoteClient::Tcp { .. } => "Client, Body>", + } + } + + pub fn request(&self, req: Request) -> ResponseFuture { + match self { + RemoteClient::Unix { client } => client.request(req), + RemoteClient::Tcp { client } => client.request(req), + } + } +} + +impl Debug for RemoteClient +where + B: HttpBody + Send + 'static, + B::Data: Send, + B::Error: Into>, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.client_name()) + } +} + +#[derive(Debug)] +pub struct UnitClient { + pub control_socket: ControlSocket, + /// A `current_thread` runtime for executing operations on the + /// asynchronous client in a blocking manner. + rt: Runtime, + /// Client for communicating with the control API over the UNIX domain socket + client: Box>, +} + +impl UnitClient { + pub fn new_with_runtime(control_socket: ControlSocket, runtime: Runtime) -> Self { + if control_socket.is_local_socket() { + Self::new_unix(control_socket, runtime) + } else { + Self::new_http(control_socket, runtime) + } + } + + pub fn new(control_socket: ControlSocket) -> Self { + let runtime = tokio::runtime::Builder::new_current_thread() + .enable_all() + .build() + .expect("Unable to create a current_thread runtime"); + Self::new_with_runtime(control_socket, runtime) + } + + pub fn new_http(control_socket: ControlSocket, runtime: Runtime) -> Self { + let remote_client = Client::builder().build(HttpsConnector::new()); + Self { + control_socket, + rt: runtime, + client: Box::from(RemoteClient::Tcp { client: remote_client }), + } + } + + pub fn new_unix(control_socket: ControlSocket, runtime: Runtime) -> UnitClient { + let remote_client = Client::unix(); + + Self { + control_socket, + rt: runtime, + client: Box::from(RemoteClient::Unix { client: remote_client }), + } + } + + /// Sends a request to UNIT and deserializes the JSON response body into the value of type `RESPONSE`. + pub fn send_request_and_deserialize_response serde::Deserialize<'de>>( + &self, + mut request: Request, + ) -> Result { + let uri = request.uri().clone(); + let path: &str = uri.path(); + + request.headers_mut().insert("User-Agent", USER_AGENT.parse().unwrap()); + + let response_future = self.client.request(request); + + self.rt.block_on(async { + let response = response_future + .await + .map_err(|error| UnitClientError::new(error, self.control_socket.to_string(), path.to_string()))?; + + let status = response.status(); + let body = hyper::body::aggregate(response) + .await + .map_err(|error| UnitClientError::new(error, self.control_socket.to_string(), path.to_string()))?; + let reader = &mut body.reader(); + if !status.is_success() { + let error: HashMap = + serde_json::from_reader(reader).map_err(|error| UnitClientError::JsonError { + source: error, + path: path.to_string(), + })?; + + return Err(UnitClientError::HttpResponseJsonBodyError { + status, + path: path.to_string(), + error: error.get("error").unwrap_or(&"Unknown error".into()).to_string(), + detail: error.get("detail").unwrap_or(&"".into()).to_string(), + }); + } + serde_json::from_reader(reader).map_err(|error| UnitClientError::JsonError { + source: error, + path: path.to_string(), + }) + }) + } + + pub fn listeners_api(&self) -> Box { + new_openapi_client!(self, ListenersApiClient, ListenersApi) + } + + pub fn listeners(&self) -> Result, Box> { + let list_listeners = self.listeners_api().get_listeners(); + self.execute_openapi_future(list_listeners) + } + + pub fn execute_openapi_future>, R: for<'de> serde::Deserialize<'de>>( + &self, + future: F, + ) -> Result> { + self.rt.block_on(future).map_err(|error| { + let remapped_error = if let OpenAPIError::Hyper(hyper_error) = error { + UnitClientError::new(hyper_error, self.control_socket.to_string(), "".to_string()) + } else { + UnitClientError::OpenAPIError { source: error } + }; + + Box::new(remapped_error) + }) + } + + pub fn status_api(&self) -> Box { + new_openapi_client!(self, StatusApiClient, StatusApi) + } + + pub fn status(&self) -> Result> { + let status = self.status_api().get_status(); + self.execute_openapi_future(status) + } + + pub fn is_running(&self) -> bool { + self.status().is_ok() + } +} + +pub type UnitSerializableMap = HashMap; + +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct UnitStatus { + pub connections: UnitStatusConnections, + pub requests: UnitStatusRequests, + pub applications: HashMap, +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct UnitStatusConnections { + #[serde(default)] + pub closed: usize, + #[serde(default)] + pub idle: usize, + #[serde(default)] + pub active: usize, + #[serde(default)] + pub accepted: usize, +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct UnitStatusRequests { + #[serde(default)] + pub active: usize, + #[serde(default)] + pub total: usize, +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct UnitStatusApplication { + #[serde(default)] + pub processes: HashMap, + #[serde(default)] + pub requests: HashMap, +} + +#[cfg(test)] +mod tests { + use crate::unitd_instance::UnitdInstance; + + use super::*; + // Integration tests + + #[test] + fn can_connect_to_unit_api() { + match UnitdInstance::running_unitd_instances().first() { + Some(unit_instance) => { + let control_api_socket_address = unit_instance + .control_api_socket_address() + .expect("No control API socket path found"); + let control_socket = ControlSocket::try_from(control_api_socket_address) + .expect("Unable to parse control socket address"); + let unit_client = UnitClient::new(control_socket); + assert!(unit_client.is_running()); + } + None => { + eprintln!("No running unitd instances found - skipping test"); + } + } + } + + #[test] + fn can_get_unit_status() { + match UnitdInstance::running_unitd_instances().first() { + Some(unit_instance) => { + let control_api_socket_address = unit_instance + .control_api_socket_address() + .expect("No control API socket path found"); + let control_socket = ControlSocket::try_from(control_api_socket_address) + .expect("Unable to parse control socket address"); + let unit_client = UnitClient::new(control_socket); + let status = unit_client.status().expect("Unable to get unit status"); + println!("Unit status: {:?}", status); + } + None => { + eprintln!("No running unitd instances found - skipping test"); + } + } + } + + #[test] + fn can_get_unit_listeners() { + match UnitdInstance::running_unitd_instances().first() { + Some(unit_instance) => { + let control_api_socket_address = unit_instance + .control_api_socket_address() + .expect("No control API socket path found"); + let control_socket = ControlSocket::try_from(control_api_socket_address) + .expect("Unable to parse control socket address"); + let unit_client = UnitClient::new(control_socket); + unit_client.listeners().expect("Unable to get Unit listeners"); + } + None => { + eprintln!("No running unitd instances found - skipping test"); + } + } + } +} diff --git a/cli/unit-client-rs/src/unitd_cmd.rs b/cli/unit-client-rs/src/unitd_cmd.rs new file mode 100644 index 000000000..c4883ed5f --- /dev/null +++ b/cli/unit-client-rs/src/unitd_cmd.rs @@ -0,0 +1,85 @@ +use std::error::Error as StdError; +use std::io::{Error as IoError, ErrorKind}; + +use crate::runtime_flags::RuntimeFlags; +use std::path::{Path, PathBuf}; + +#[derive(Debug, Clone)] +pub struct UnitdCmd { + pub(crate) process_executable_path: Option>, + pub version: Option, + pub flags: Option, +} + +impl UnitdCmd { + pub(crate) fn new(full_cmd: S, binary_name: &str) -> Result> + where + S: Into, + { + let process_cmd: String = full_cmd.into(); + let parsable = process_cmd + .strip_prefix("unit: main v") + .and_then(|s| s.strip_suffix(']')); + if parsable.is_none() { + let msg = format!("cmd does not have the expected format: {}", process_cmd); + return Err(IoError::new(ErrorKind::InvalidInput, msg).into()); + } + let parts = parsable + .expect("Unable to parse cmd") + .splitn(2, " [") + .collect::>(); + if parts.len() != 2 { + let msg = format!("cmd does not have the expected format: {}", process_cmd); + return Err(IoError::new(ErrorKind::InvalidInput, msg).into()); + } + let version: Option = Some(parts[0].to_string()); + let executable_path = UnitdCmd::parse_executable_path_from_cmd(parts[1], binary_name); + let flags = UnitdCmd::parse_runtime_flags_from_cmd(parts[1]); + + Ok(UnitdCmd { + process_executable_path: executable_path, + version, + flags, + }) + } + + fn parse_executable_path_from_cmd(full_cmd: S, binary_name: &str) -> Option> + where + S: Into, + { + let cmd = full_cmd.into(); + if cmd.is_empty() { + return None; + } + + let split = cmd.splitn(2, binary_name).collect::>(); + if split.is_empty() { + return None; + } + + let path = format!("{}{}", split[0], binary_name); + Some(PathBuf::from(path).into_boxed_path()) + } + + fn parse_runtime_flags_from_cmd(full_cmd: S) -> Option + where + S: Into, + { + let cmd = full_cmd.into(); + if cmd.is_empty() { + return None; + } + // Split out everything in between the brackets [ and ] + let split = cmd.trim_end_matches(']').splitn(2, '[').collect::>(); + if split.is_empty() { + return None; + } + /* Now we need to parse a string like this: + * ./sbin/unitd --no-daemon --tmp /tmp + * and only return what is after the invoking command */ + split[0] + .find("--") + .map(|index| cmd[index..].to_string()) + .map(RuntimeFlags::new) + } +} diff --git a/cli/unit-client-rs/src/unitd_configure_options.rs b/cli/unit-client-rs/src/unitd_configure_options.rs new file mode 100644 index 000000000..88ab1101e --- /dev/null +++ b/cli/unit-client-rs/src/unitd_configure_options.rs @@ -0,0 +1,235 @@ +use custom_error::custom_error; +use std::borrow::Cow; +use std::error::Error as stdError; +use std::io::{BufRead, BufReader, Lines}; +use std::path::{Path, PathBuf}; +use std::process::{Command, Stdio}; + +custom_error! {UnitdStderrParseError + VersionNotFound = "Version string output not found", + BuildSettingsNotFound = "Build settings not found" +} + +#[derive(Debug, Clone)] +pub struct UnitdConfigureOptions { + pub version: Cow<'static, str>, + pub all_flags: Cow<'static, str>, +} + +impl UnitdConfigureOptions { + pub fn new(unitd_path: &Path) -> Result> { + fn parse_configure_settings_from_unitd_stderr_output( + lines: &mut Lines, + ) -> Result> { + const VERSION_PREFIX: &str = "unit version: "; + const CONFIGURED_AS_PREFIX: &str = "configured as "; + const CONFIGURE_PREFIX: &str = "configured as ./configure "; + + fn aggregate_parsable_lines( + mut accum: (Option, Option), + line: String, + ) -> (Option, Option) { + if line.starts_with(VERSION_PREFIX) { + accum.0 = line.strip_prefix(VERSION_PREFIX).map(|l| l.to_string()); + } else if line.starts_with(CONFIGURED_AS_PREFIX) { + accum.1 = line.strip_prefix(CONFIGURE_PREFIX).map(|l| l.to_string()); + } + + accum + } + + let options_lines = lines + .filter_map(|line| line.ok()) + .fold((None, None), aggregate_parsable_lines); + + if options_lines.0.is_none() { + return Err(Box::new(UnitdStderrParseError::VersionNotFound) as Box); + } else if options_lines.1.is_none() { + return Err(Box::new(UnitdStderrParseError::BuildSettingsNotFound) as Box); + } + + Ok(UnitdConfigureOptions { + version: options_lines.0.unwrap().into(), + all_flags: options_lines.1.unwrap().into(), + }) + } + + let program = unitd_path.as_os_str(); + let child = Command::new(program) + .arg("--version") + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) + .spawn()?; + let output = child.wait_with_output()?; + let err = BufReader::new(&*output.stderr); + parse_configure_settings_from_unitd_stderr_output(&mut err.lines()) + } + + pub fn has_flag(&self, flag_name: &str) -> bool { + self.all_flags + .split_ascii_whitespace() + .any(|flag| flag.starts_with(format!("--{}", flag_name).as_str())) + } + + pub fn get_flag_value(&self, flag_name: &str) -> Option { + self.all_flags + .split_ascii_whitespace() + .find(|flag| flag.starts_with(format!("--{}", flag_name).as_str())) + .and_then(|flag| { + let parts: Vec<&str> = flag.split('=').collect(); + if parts.len() >= 2 { + Some(parts[1].to_owned()) + } else { + None + } + }) + } + + pub fn debug_enabled(&self) -> bool { + self.has_flag("debug") + } + + pub fn openssl_enabled(&self) -> bool { + self.has_flag("openssl") + } + + pub fn prefix_path(&self) -> Option> { + self.get_flag_value("prefix") + .map(PathBuf::from) + .map(PathBuf::into_boxed_path) + } + + fn join_to_prefix_path(&self, sub_path: S) -> Option> + where + S: Into, + { + self.prefix_path() + .map(|path| path.join(sub_path.into()).into_boxed_path()) + } + + pub fn default_control_api_socket_address(&self) -> Option { + // If the socket address is specific configured in the configure options, we use + // that. Otherwise, we use the default path as assumed to be unix:$prefix/control.unit.sock. + match self.get_flag_value("control") { + Some(socket_address) => Some(socket_address), + None => { + // Give up if the unitd is compiled with unix sockets disabled + if self.has_flag("no-unix-sockets") { + return None; + } + let socket_path = self.join_to_prefix_path("control.unit.sock"); + socket_path.map(|path| format!("unix:{}", path.to_string_lossy())) + } + } + } + + pub fn default_pid_path(&self) -> Option> { + match self.get_flag_value("pid") { + Some(pid_path) => self.join_to_prefix_path(pid_path), + None => self.join_to_prefix_path("unit.pid"), + } + } + + pub fn default_log_path(&self) -> Option> { + match self.get_flag_value("log") { + Some(pid_path) => self.join_to_prefix_path(pid_path), + None => self.join_to_prefix_path("unit.log"), + } + } + + pub fn default_modules_directory(&self) -> Option> { + match self.get_flag_value("modules") { + Some(modules_dir_name) => self.join_to_prefix_path(modules_dir_name), + None => self.join_to_prefix_path("modules"), + } + } + + pub fn default_state_directory(&self) -> Option> { + match self.get_flag_value("state") { + Some(state_dir_name) => self.join_to_prefix_path(state_dir_name), + None => self.join_to_prefix_path("state"), + } + } + + pub fn default_tmp_directory(&self) -> Option> { + match self.get_flag_value("tmp") { + Some(tmp_dir_name) => self.join_to_prefix_path(tmp_dir_name), + None => self.join_to_prefix_path("tmp"), + } + } + pub fn default_user(&self) -> Option { + self.get_flag_value("user").map(String::from) + } + pub fn default_group(&self) -> Option { + self.get_flag_value("group").map(String::from) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::unitd_instance; + use crate::unitd_instance::UNITD_PATH_ENV_KEY; + + #[test] + fn can_detect_key() { + let options = UnitdConfigureOptions { + version: Default::default(), + all_flags: Cow::from("--debug --openssl --prefix=/opt/unit"), + }; + assert!(options.has_flag("debug")); + assert!(options.has_flag("openssl")); + assert!(options.has_flag("prefix")); + assert!(!options.has_flag("fobar")); + } + + #[test] + fn can_get_flag_value_by_key() { + let expected = "/opt/unit"; + let options = UnitdConfigureOptions { + version: Default::default(), + all_flags: Cow::from("--debug --openssl --prefix=/opt/unit"), + }; + + let actual = options.get_flag_value("prefix"); + assert_eq!(expected, actual.unwrap()) + } + + #[test] + fn can_get_prefix_path() { + let expected: Box = Path::new("/opt/unit").into(); + let options = UnitdConfigureOptions { + version: Default::default(), + all_flags: Cow::from("--debug --openssl --prefix=/opt/unit"), + }; + + let actual = options.prefix_path(); + assert_eq!(expected, actual.unwrap()) + } + + #[test] + fn can_parse_complicated_configure_options() { + let expected: Box = Path::new("/usr").into(); + let options = UnitdConfigureOptions { + version: Default::default(), + all_flags: Cow::from("--prefix=/usr --state=/var/lib/unit --control=unix:/var/run/control.unit.sock --pid=/var/run/unit.pid --log=/var/log/unit.log --tmp=/var/tmp --user=unit --group=unit --tests --openssl --modules=/usr/lib/unit/modules --libdir=/usr/lib/x86_64-linux-gnu --cc-opt='-g -O2 -fdebug-prefix-map=/data/builder/debuild/unit-1.28.0/pkg/deb/debuild/unit-1.28.0=. -specs=/usr/share/dpkg/no-pie-compile.specs -fstack-protector-strong -Wformat -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -fPIC' --ld-opt='-Wl,-Bsymbolic-functions -specs=/usr/share/dpkg/no-pie-link.specs -Wl,-z,relro -Wl,-z,now -Wl,--as-needed -pie' +"), + }; + + let actual = options.prefix_path(); + assert_eq!(expected, actual.unwrap()) + } + + #[test] + fn can_run_unitd() { + let specific_path = std::env::var(UNITD_PATH_ENV_KEY).map_err(|error| Box::new(error) as Box); + let unitd_path = unitd_instance::find_executable_path(specific_path); + let config_options = UnitdConfigureOptions::new(&unitd_path.unwrap()); + match config_options { + Ok(options) => { + println!("{:?}", options) + } + Err(error) => panic!("{}", error), + }; + } +} diff --git a/cli/unit-client-rs/src/unitd_instance.rs b/cli/unit-client-rs/src/unitd_instance.rs new file mode 100644 index 000000000..9467fcb70 --- /dev/null +++ b/cli/unit-client-rs/src/unitd_instance.rs @@ -0,0 +1,360 @@ +use crate::unit_client::UnitClientError; +use serde::ser::SerializeMap; +use serde::{Serialize, Serializer}; +use std::error::Error as StdError; +use std::path::{Path, PathBuf}; +use std::{fmt, io}; +use which::which; + +use crate::runtime_flags::RuntimeFlags; +use crate::unitd_configure_options::UnitdConfigureOptions; +use crate::unitd_process::UnitdProcess; + +pub const UNITD_PATH_ENV_KEY: &str = "UNITD_PATH"; +pub const UNITD_BINARY_NAMES: [&str; 2] = ["unitd", "unitd-debug"]; + +#[derive(Debug)] +pub struct UnitdInstance { + pub process: UnitdProcess, + pub configure_options: Option, + pub errors: Vec, +} + +impl Serialize for UnitdInstance { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let mut state = serializer.serialize_map(Some(15))?; + let runtime_flags = self + .process + .cmd() + .and_then(|cmd| cmd.flags) + .map(|flags| flags.to_string()); + + let configure_flags = self.configure_options.as_ref().map(|opts| opts.all_flags.clone()); + + state.serialize_entry("pid", &self.process.process_id)?; + state.serialize_entry("version", &self.version())?; + state.serialize_entry("user", &self.process.user)?; + state.serialize_entry("effective_user", &self.process.effective_user)?; + state.serialize_entry("executable", &self.process.executable_path())?; + state.serialize_entry("control_socket", &self.control_api_socket_address())?; + state.serialize_entry("child_pids", &self.process.child_pids)?; + state.serialize_entry("log_path", &self.log_path())?; + state.serialize_entry("pid_path", &self.pid_path())?; + state.serialize_entry("modules_directory", &self.modules_directory())?; + state.serialize_entry("state_directory", &self.state_directory())?; + state.serialize_entry("tmp_directory", &self.tmp_directory())?; + state.serialize_entry("runtime_flags", &runtime_flags)?; + state.serialize_entry("configure_flags", &configure_flags)?; + let string_errors = &self.errors.iter().map(|e| e.to_string()).collect::>(); + state.serialize_entry("errors", string_errors)?; + + state.end() + } +} + +impl UnitdInstance { + pub fn running_unitd_instances() -> Vec { + Self::collect_unitd_processes(UnitdProcess::find_unitd_processes()) + } + + /// Find all running unitd processes and convert them into UnitdInstances and filter + /// out all errors by printing them to stderr and leaving errored instances out of + /// the returned vector. + fn collect_unitd_processes(processes: Vec) -> Vec { + Self::map_processes_to_instances(processes).into_iter().collect() + } + + fn map_processes_to_instances(processes: Vec) -> Vec { + fn unitd_path_from_process(process: &UnitdProcess) -> Result, UnitClientError> { + match process.executable_path() { + Some(executable_path) => { + let is_absolute_working_dir = process + .working_dir + .as_ref() + .map(|p| p.is_absolute()) + .unwrap_or_default(); + if executable_path.is_absolute() { + Ok(executable_path.to_owned()) + } else if executable_path.is_relative() && is_absolute_working_dir { + let new_path = process + .working_dir + .as_ref() + .unwrap() + .join(executable_path) + .canonicalize() + .map(|path| path.into_boxed_path()) + .map_err(|error| UnitClientError::UnitdProcessParseError { + message: format!("Error canonicalizing unitd executable path: {}", error), + pid: process.process_id, + })?; + Ok(new_path) + } else { + Err(UnitClientError::UnitdProcessParseError { + message: "Unable to get absolute unitd executable path from process".to_string(), + pid: process.process_id, + }) + } + } + None => Err(UnitClientError::UnitdProcessParseError { + message: "Unable to get unitd executable path from process".to_string(), + pid: process.process_id, + }), + } + } + + fn map_process_to_unitd_instance(process: &UnitdProcess) -> UnitdInstance { + match unitd_path_from_process(process) { + Ok(unitd_path) => match UnitdConfigureOptions::new(&unitd_path.clone().into_path_buf()) { + Ok(configure_options) => UnitdInstance { + process: process.to_owned(), + configure_options: Some(configure_options), + errors: vec![], + }, + Err(error) => { + let error = UnitClientError::UnitdProcessExecError { + source: error, + executable_path: unitd_path.to_string_lossy().parse().unwrap_or_default(), + message: "Error running unitd binary to get configure options".to_string(), + pid: process.process_id, + }; + UnitdInstance { + process: process.to_owned(), + configure_options: None, + errors: vec![error], + } + } + }, + Err(err) => UnitdInstance { + process: process.to_owned(), + configure_options: None, + errors: vec![err], + }, + } + } + + processes + .iter() + // This converts processes into a UnitdInstance + .map(map_process_to_unitd_instance) + .collect() + } + + fn version(&self) -> Option { + match self.process.cmd()?.version { + Some(version) => Some(version), + None => self.configure_options.as_ref().map(|opts| opts.version.to_string()), + } + } + + fn flag_or_default_option( + &self, + read_flag: fn(RuntimeFlags) -> Option, + read_opts: fn(UnitdConfigureOptions) -> Option, + ) -> Option { + self.process + .cmd()? + .flags + .and_then(read_flag) + .or_else(|| self.configure_options.to_owned().and_then(read_opts)) + } + + pub fn control_api_socket_address(&self) -> Option { + self.flag_or_default_option( + |flags| flags.control_api_socket_address(), + |opts| opts.default_control_api_socket_address(), + ) + } + + pub fn pid_path(&self) -> Option> { + self.flag_or_default_option(|flags| flags.pid_path(), |opts| opts.default_pid_path()) + } + + pub fn log_path(&self) -> Option> { + self.flag_or_default_option(|flags| flags.log_path(), |opts| opts.default_log_path()) + } + + pub fn modules_directory(&self) -> Option> { + self.flag_or_default_option( + |flags| flags.modules_directory(), + |opts| opts.default_modules_directory(), + ) + } + + pub fn state_directory(&self) -> Option> { + self.flag_or_default_option(|flags| flags.state_directory(), |opts| opts.default_state_directory()) + } + + pub fn tmp_directory(&self) -> Option> { + self.flag_or_default_option(|flags| flags.tmp_directory(), |opts| opts.default_tmp_directory()) + } +} + +impl fmt::Display for UnitdInstance { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + const UNKNOWN: &str = "[unknown]"; + let version = self.version().unwrap_or_else(|| String::from("[unknown]")); + let runtime_flags = self + .process + .cmd() + .and_then(|cmd| cmd.flags) + .map(|flags| flags.to_string()) + .unwrap_or_else(|| UNKNOWN.into()); + let configure_flags = self + .configure_options + .as_ref() + .map(|opts| opts.all_flags.clone()) + .unwrap_or_else(|| UNKNOWN.into()); + let unitd_path: String = self + .process + .executable_path() + .map(|p| p.to_string_lossy().into()) + .unwrap_or_else(|| UNKNOWN.into()); + let working_dir: String = self + .process + .working_dir + .as_ref() + .map(|p| p.to_string_lossy().into()) + .unwrap_or_else(|| UNKNOWN.into()); + let socket_address = self.control_api_socket_address().unwrap_or_else(|| UNKNOWN.to_string()); + let child_pids = self + .process + .child_pids + .iter() + .map(u64::to_string) + .collect::>() + .join(", "); + + writeln!( + f, + "{} instance [pid: {}, version: {}]:", + self.process.binary_name, self.process.process_id, version + )?; + writeln!(f, " Executable: {}", unitd_path)?; + writeln!(f, " Process working directory: {}", working_dir)?; + write!(f, " Process ownership: ")?; + if let Some(user) = &self.process.user { + writeln!(f, "name: {}, uid: {}, gid: {}", user.name, user.uid, user.gid)?; + } else { + writeln!(f, "{}", UNKNOWN)?; + } + write!(f, " Process effective ownership: ")?; + if let Some(user) = &self.process.effective_user { + writeln!(f, "name: {}, uid: {}, gid: {}", user.name, user.uid, user.gid)?; + } else { + writeln!(f, "{}", UNKNOWN)?; + } + + writeln!(f, " API control unix socket: {}", socket_address)?; + writeln!(f, " Child processes ids: {}", child_pids)?; + writeln!(f, " Runtime flags: {}", runtime_flags)?; + write!(f, " Configure options: {}", configure_flags)?; + + if !self.errors.is_empty() { + write!(f, "\n Errors:")?; + for error in &self.errors { + write!(f, "\n {}", error)?; + } + } + + Ok(()) + } +} + +pub fn find_executable_path(specific_path: Result>) -> Result> { + fn find_unitd_in_system_path() -> Vec { + UNITD_BINARY_NAMES + .iter() + .map(which) + .filter_map(Result::ok) + .collect::>() + } + + match specific_path { + Ok(path) => Ok(PathBuf::from(path)), + Err(_) => { + let unitd_paths = find_unitd_in_system_path(); + if unitd_paths.is_empty() { + let err_msg = format!( + "Could not find unitd in system path or in UNITD_PATH environment variable. Searched for: {:?}", + UNITD_BINARY_NAMES + ); + let err = io::Error::new(io::ErrorKind::NotFound, err_msg); + Err(Box::from(err)) + } else { + Ok(unitd_paths[0].clone()) + } + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use rand::rngs::StdRng; + use rand::{RngCore, SeedableRng}; + + // We don't need a secure seed for testing, in fact it is better that we have a + // predictable value + const SEED: [u8; 32] = [ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, + ]; + #[test] + fn can_find_unitd_instances() { + UnitdInstance::running_unitd_instances().iter().for_each(|p| { + println!("{:?}", p); + println!("Runtime Flags: {:?}", p.process.cmd().map(|c| c.flags)); + println!("Temp directory: {:?}", p.tmp_directory()); + }) + } + + fn mock_process>( + rng: &mut StdRng, + binary_name: S, + executable_path: Option, + ) -> UnitdProcess { + UnitdProcess { + process_id: rng.next_u32() as u64, + binary_name: binary_name.into(), + executable_path: executable_path.map(|p| Box::from(Path::new(&p))), + environ: vec![], + all_cmds: vec![], + working_dir: Some(Box::from(Path::new("/opt/unit"))), + child_pids: vec![], + user: None, + effective_user: None, + } + } + + #[test] + fn will_list_without_errors_valid_processes() { + let specific_path = std::env::var(UNITD_PATH_ENV_KEY).map_err(|error| Box::new(error) as Box); + let binding = match find_executable_path(specific_path) { + Ok(path) => path, + Err(error) => { + eprintln!("Could not find unitd executable path: {} - skipping test", error); + return; + } + }; + let binary_name = binding + .file_name() + .expect("Could not get binary name") + .to_string_lossy() + .to_string(); + let unitd_path = binding.to_string_lossy(); + let mut rng: StdRng = SeedableRng::from_seed(SEED); + + let processes = vec![ + mock_process(&mut rng, &binary_name, Some(unitd_path.to_string())), + mock_process(&mut rng, &binary_name, Some(unitd_path.to_string())), + ]; + let instances = UnitdInstance::collect_unitd_processes(processes); + // assert_eq!(instances.len(), 3); + instances.iter().for_each(|p| { + assert_eq!(p.errors.len(), 0, "Expected no errors, got: {:?}", p.errors); + }) + } +} diff --git a/cli/unit-client-rs/src/unitd_process.rs b/cli/unit-client-rs/src/unitd_process.rs new file mode 100644 index 000000000..b8604e89c --- /dev/null +++ b/cli/unit-client-rs/src/unitd_process.rs @@ -0,0 +1,170 @@ +use crate::unitd_cmd::UnitdCmd; +use crate::unitd_instance::UNITD_BINARY_NAMES; +use crate::unitd_process_user::UnitdProcessUser; +use std::collections::HashMap; +use std::path::Path; +use sysinfo::{Pid, Process, ProcessRefreshKind, System, UpdateKind, Users}; + +#[derive(Debug, Clone)] +pub struct UnitdProcess { + pub binary_name: String, + pub process_id: u64, + pub executable_path: Option>, + pub environ: Vec, + pub all_cmds: Vec, + pub working_dir: Option>, + pub child_pids: Vec, + pub user: Option, + pub effective_user: Option, +} + +impl UnitdProcess { + pub fn find_unitd_processes() -> Vec { + let process_refresh_kind = ProcessRefreshKind::new() + .with_cmd(UpdateKind::Always) + .with_cwd(UpdateKind::Always) + .with_exe(UpdateKind::Always) + .with_user(UpdateKind::Always); + let refresh_kind = sysinfo::RefreshKind::new().with_processes(process_refresh_kind); + let sys = System::new_with_specifics(refresh_kind); + let unitd_processes: HashMap<&Pid, &Process> = sys + .processes() + .iter() + .filter(|p| { + let process_name = p.1.name(); + UNITD_BINARY_NAMES.contains(&process_name) + }) + .collect::>(); + let users = Users::new_with_refreshed_list(); + + unitd_processes + .iter() + // Filter out child processes + .filter(|p| { + let parent_pid = p.1.parent(); + match parent_pid { + Some(pid) => !unitd_processes.contains_key(&pid), + None => false, + } + }) + .map(|p| { + let tuple = p.to_owned(); + /* The sysinfo library only supports 32-bit pids, yet larger values are possible + * if the OS is configured to support it, thus we use 64-bit integers internally + * because it is just a matter of time until the library changes to larger values. */ + let pid = *tuple.0; + let process = *tuple.1; + let process_id: u64 = pid.as_u32().into(); + let executable_path: Option> = process.exe().map(|p| p.to_path_buf().into_boxed_path()); + let environ: Vec = process.environ().into(); + let cmd: Vec = process.cmd().into(); + let working_dir: Option> = process.cwd().map(|p| p.to_path_buf().into_boxed_path()); + let child_pids = unitd_processes + .iter() + .filter_map(|p| p.to_owned().1.parent()) + .filter(|parent_pid| parent_pid == pid) + .map(|p| p.as_u32() as u64) + .collect::>(); + + let user = process + .user_id() + .and_then(|uid| users.get_user_by_id(uid)) + .map(UnitdProcessUser::from); + let effective_user = process + .effective_user_id() + .and_then(|uid| users.get_user_by_id(uid)) + .map(UnitdProcessUser::from); + + UnitdProcess { + binary_name: process.name().to_string(), + process_id, + executable_path, + environ, + all_cmds: cmd, + working_dir, + child_pids, + user, + effective_user, + } + }) + .collect::>() + } + + pub fn cmd(&self) -> Option { + if self.all_cmds.is_empty() { + return None; + } + + match UnitdCmd::new(self.all_cmds[0].clone(), self.binary_name.as_ref()) { + Ok(cmd) => Some(cmd), + Err(error) => { + eprintln!("Failed to parse process cmd: {}", error); + None + } + } + } + + pub fn executable_path(&self) -> Option> { + if self.executable_path.is_some() { + return self.executable_path.clone(); + } + self.cmd().and_then(|cmd| cmd.process_executable_path) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + fn can_parse_runtime_cmd_absolute_path(binary_name: &str) { + let cmd = format!( + "unit: main v1.28.0 [/usr/sbin/{} --log /var/log/unit.log --pid /var/run/unit.pid]", + binary_name + ); + let unitd_cmd = UnitdCmd::new(cmd, binary_name).expect("Failed to parse unitd cmd"); + assert_eq!(unitd_cmd.version.unwrap(), "1.28.0"); + assert_eq!( + unitd_cmd.process_executable_path.unwrap().to_string_lossy(), + format!("/usr/sbin/{}", binary_name) + ); + let flags = unitd_cmd.flags.unwrap(); + assert_eq!(flags.get_flag_value("log").unwrap(), "/var/log/unit.log"); + assert_eq!(flags.get_flag_value("pid").unwrap(), "/var/run/unit.pid"); + } + + fn can_parse_runtime_cmd_relative_path(binary_name: &str) { + let cmd = format!( + "unit: main v1.29.0 [./sbin/{} --no-daemon --tmp /tmp --something]", + binary_name + ); + let unitd_cmd = UnitdCmd::new(cmd, binary_name).expect("Failed to parse unitd cmd"); + assert_eq!(unitd_cmd.version.unwrap(), "1.29.0"); + assert_eq!( + unitd_cmd.process_executable_path.unwrap().to_string_lossy(), + format!("./sbin/{}", binary_name) + ); + let flags = unitd_cmd.flags.unwrap(); + assert_eq!(flags.get_flag_value("tmp").unwrap(), "/tmp"); + assert!(flags.has_flag("something")); + } + + #[test] + fn can_parse_runtime_cmd_unitd_absolute_path() { + can_parse_runtime_cmd_absolute_path("unitd"); + } + + #[test] + fn can_parse_runtime_cmd_unitd_debug_absolute_path() { + can_parse_runtime_cmd_absolute_path("unitd-debug"); + } + + #[test] + fn can_parse_runtime_cmd_unitd_relative_path() { + can_parse_runtime_cmd_relative_path("unitd"); + } + + #[test] + fn can_parse_runtime_cmd_unitd_debug_relative_path() { + can_parse_runtime_cmd_relative_path("unitd-debug"); + } +} diff --git a/cli/unit-client-rs/src/unitd_process_user.rs b/cli/unit-client-rs/src/unitd_process_user.rs new file mode 100644 index 000000000..c4f9be224 --- /dev/null +++ b/cli/unit-client-rs/src/unitd_process_user.rs @@ -0,0 +1,36 @@ +use serde::Serialize; +use std::fmt; +use std::fmt::Display; +use sysinfo::User; + +#[derive(Debug, Clone, Serialize)] +pub struct UnitdProcessUser { + pub name: String, + pub uid: u32, + pub gid: u32, + pub groups: Vec, +} + +impl Display for UnitdProcessUser { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "name: {}, uid: {}, gid: {}, groups: {}", + self.name, + self.uid, + self.gid, + self.groups.join(", ") + ) + } +} + +impl From<&User> for UnitdProcessUser { + fn from(user: &User) -> Self { + UnitdProcessUser { + name: user.name().into(), + uid: *user.id().clone(), + gid: *user.group_id(), + groups: user.groups().iter().map(|g| g.name().into()).collect(), + } + } +} diff --git a/cli/unit-openapi/.gitignore b/cli/unit-openapi/.gitignore new file mode 100644 index 000000000..6aa106405 --- /dev/null +++ b/cli/unit-openapi/.gitignore @@ -0,0 +1,3 @@ +/target/ +**/*.rs.bk +Cargo.lock diff --git a/cli/unit-openapi/.openapi-generator-ignore b/cli/unit-openapi/.openapi-generator-ignore new file mode 100644 index 000000000..aa9e0e407 --- /dev/null +++ b/cli/unit-openapi/.openapi-generator-ignore @@ -0,0 +1,27 @@ +# OpenAPI Generator Ignore +# Generated by openapi-generator https://github.com/openapitools/openapi-generator + +# Use this file to prevent files from being overwritten by the generator. +# The patterns follow closely to .gitignore or .dockerignore. + +# As an example, the C# client generator defines ApiClient.cs. +# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line: +#ApiClient.cs + +# You can match any string of characters against a directory, file or extension with a single asterisk (*): +#foo/*/qux +# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux + +# You can recursively match patterns against a directory, file or extension with a double asterisk (**): +#foo/**/qux +# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux + +# You can also negate patterns with an exclamation (!). +# For example, you can ignore all files in a docs folder with the file extension .md: +#docs/*.md +# Then explicitly reverse the ignore rule for a single file: +#!docs/README.md + +src/apis/error.rs +.travis.yml +git_push.sh \ No newline at end of file diff --git a/cli/unit-openapi/.openapi-generator/FILES b/cli/unit-openapi/.openapi-generator/FILES new file mode 100644 index 000000000..4f177f5ff --- /dev/null +++ b/cli/unit-openapi/.openapi-generator/FILES @@ -0,0 +1,161 @@ +.gitignore +Cargo.toml +README.md +docs/AccessLogApi.md +docs/ApplicationsApi.md +docs/AppsApi.md +docs/CertBundle.md +docs/CertBundleChainCert.md +docs/CertBundleChainCertIssuer.md +docs/CertBundleChainCertSubj.md +docs/CertBundleChainCertValidity.md +docs/CertificatesApi.md +docs/Config.md +docs/ConfigAccessLog.md +docs/ConfigAccessLogObject.md +docs/ConfigApi.md +docs/ConfigApplication.md +docs/ConfigApplicationCommon.md +docs/ConfigApplicationCommonIsolation.md +docs/ConfigApplicationCommonIsolationAutomount.md +docs/ConfigApplicationCommonIsolationCgroup.md +docs/ConfigApplicationCommonIsolationGidmapInner.md +docs/ConfigApplicationCommonIsolationNamespaces.md +docs/ConfigApplicationCommonIsolationUidmapInner.md +docs/ConfigApplicationCommonLimits.md +docs/ConfigApplicationCommonProcesses.md +docs/ConfigApplicationCommonProcessesAnyOf.md +docs/ConfigApplicationExternal.md +docs/ConfigApplicationExternalAllOf.md +docs/ConfigApplicationJava.md +docs/ConfigApplicationJavaAllOf.md +docs/ConfigApplicationPerl.md +docs/ConfigApplicationPerlAllOf.md +docs/ConfigApplicationPhp.md +docs/ConfigApplicationPhpAllOf.md +docs/ConfigApplicationPhpAllOfOptions.md +docs/ConfigApplicationPhpAllOfTargets.md +docs/ConfigApplicationPython.md +docs/ConfigApplicationPythonAllOf.md +docs/ConfigApplicationPythonAllOfPath.md +docs/ConfigApplicationPythonAllOfTargets.md +docs/ConfigApplicationRuby.md +docs/ConfigApplicationRubyAllOf.md +docs/ConfigListener.md +docs/ConfigListenerForwarded.md +docs/ConfigListenerForwardedSource.md +docs/ConfigListenerTls.md +docs/ConfigListenerTlsCertificate.md +docs/ConfigListenerTlsSession.md +docs/ConfigListenerTlsSessionTickets.md +docs/ConfigRouteStep.md +docs/ConfigRouteStepAction.md +docs/ConfigRouteStepActionPass.md +docs/ConfigRouteStepActionProxy.md +docs/ConfigRouteStepActionReturn.md +docs/ConfigRouteStepActionShare.md +docs/ConfigRouteStepMatch.md +docs/ConfigRouteStepMatchArguments.md +docs/ConfigRouteStepMatchCookies.md +docs/ConfigRouteStepMatchHeaders.md +docs/ConfigRoutes.md +docs/ConfigSettings.md +docs/ConfigSettingsHttp.md +docs/ConfigSettingsHttpStatic.md +docs/ConfigSettingsHttpStaticMimeType.md +docs/ControlApi.md +docs/ListenersApi.md +docs/RoutesApi.md +docs/SettingsApi.md +docs/Status.md +docs/StatusApi.md +docs/StatusApplicationsApp.md +docs/StatusApplicationsAppProcesses.md +docs/StatusApplicationsAppRequests.md +docs/StatusConnections.md +docs/StatusRequests.md +docs/StringOrStringArray.md +docs/TlsApi.md +docs/XffApi.md +src/apis/access_log_api.rs +src/apis/applications_api.rs +src/apis/apps_api.rs +src/apis/certificates_api.rs +src/apis/client.rs +src/apis/config_api.rs +src/apis/configuration.rs +src/apis/control_api.rs +src/apis/listeners_api.rs +src/apis/mod.rs +src/apis/request.rs +src/apis/routes_api.rs +src/apis/settings_api.rs +src/apis/status_api.rs +src/apis/tls_api.rs +src/apis/xff_api.rs +src/lib.rs +src/models/cert_bundle.rs +src/models/cert_bundle_chain_cert.rs +src/models/cert_bundle_chain_cert_issuer.rs +src/models/cert_bundle_chain_cert_subj.rs +src/models/cert_bundle_chain_cert_validity.rs +src/models/config.rs +src/models/config_access_log.rs +src/models/config_access_log_object.rs +src/models/config_application.rs +src/models/config_application_common.rs +src/models/config_application_common_isolation.rs +src/models/config_application_common_isolation_automount.rs +src/models/config_application_common_isolation_cgroup.rs +src/models/config_application_common_isolation_gidmap_inner.rs +src/models/config_application_common_isolation_namespaces.rs +src/models/config_application_common_isolation_uidmap_inner.rs +src/models/config_application_common_limits.rs +src/models/config_application_common_processes.rs +src/models/config_application_common_processes_any_of.rs +src/models/config_application_external.rs +src/models/config_application_external_all_of.rs +src/models/config_application_java.rs +src/models/config_application_java_all_of.rs +src/models/config_application_perl.rs +src/models/config_application_perl_all_of.rs +src/models/config_application_php.rs +src/models/config_application_php_all_of.rs +src/models/config_application_php_all_of_options.rs +src/models/config_application_php_all_of_targets.rs +src/models/config_application_python.rs +src/models/config_application_python_all_of.rs +src/models/config_application_python_all_of_path.rs +src/models/config_application_python_all_of_targets.rs +src/models/config_application_ruby.rs +src/models/config_application_ruby_all_of.rs +src/models/config_listener.rs +src/models/config_listener_forwarded.rs +src/models/config_listener_forwarded_source.rs +src/models/config_listener_tls.rs +src/models/config_listener_tls_certificate.rs +src/models/config_listener_tls_session.rs +src/models/config_listener_tls_session_tickets.rs +src/models/config_route_step.rs +src/models/config_route_step_action.rs +src/models/config_route_step_action_pass.rs +src/models/config_route_step_action_proxy.rs +src/models/config_route_step_action_return.rs +src/models/config_route_step_action_share.rs +src/models/config_route_step_match.rs +src/models/config_route_step_match_arguments.rs +src/models/config_route_step_match_cookies.rs +src/models/config_route_step_match_headers.rs +src/models/config_routes.rs +src/models/config_settings.rs +src/models/config_settings_http.rs +src/models/config_settings_http_static.rs +src/models/config_settings_http_static_mime_type.rs +src/models/mod.rs +src/models/status.rs +src/models/status_applications_app.rs +src/models/status_applications_app_processes.rs +src/models/status_applications_app_requests.rs +src/models/status_connections.rs +src/models/status_requests.rs +src/models/string_or_string_array.rs diff --git a/cli/unit-openapi/.openapi-generator/VERSION b/cli/unit-openapi/.openapi-generator/VERSION new file mode 100644 index 000000000..cd802a1ec --- /dev/null +++ b/cli/unit-openapi/.openapi-generator/VERSION @@ -0,0 +1 @@ +6.6.0 \ No newline at end of file diff --git a/cli/unit-openapi/Cargo.toml b/cli/unit-openapi/Cargo.toml new file mode 100644 index 000000000..3e8bdbf63 --- /dev/null +++ b/cli/unit-openapi/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "unit-openapi" +version = "0.4.0-beta" +authors = ["unit-owner@nginx.org"] +description = "NGINX Unit is a lightweight and versatile application runtime that provides the essential components for your web application as a single open-source server: running application code, serving static assets, handling TLS and request routing. **Important**: Ufnit's API is designed to expose any part of its configuration as an addressable endpoint. Suppose a JSON object is stored at `/config/listeners/`: ```json { \"*:8080\": { \"pass\": \"applications/wp_emea_dev\" } } ``` Here, `/config/listeners/_*:8080` and `/config/listeners/_*:8080/pass` are also endpoints. Generally, object options are addressable by their names, array items—by their indexes (`/array/0/`). **Note**: By default, Unit is configured through a UNIX domain socket. To use this specification with OpenAPI tools interactively, [start](https://unit.nginx.org/howto/source/#source-startup) Unit with a TCP port as the control socket." +license = "Apache 2.0" +edition = "2018" + +[dependencies] +serde = "1.0" +serde_derive = "1.0" +serde_json = "1.0" +url = "2.2" +hyper = { version = "0.14" } +http = "0.2" +base64 = "0.21" +futures = "0.3" diff --git a/cli/unit-openapi/README.md b/cli/unit-openapi/README.md new file mode 100644 index 000000000..cfa61fccc --- /dev/null +++ b/cli/unit-openapi/README.md @@ -0,0 +1,412 @@ +# Rust API client for unit-openapi + +NGINX Unit is a lightweight and versatile application runtime that provides the essential components for your web application as a single open-source server: running application code, serving static assets, handling TLS and request routing. + + +**Important**: Ufnit's API is designed to expose any part of its configuration as an addressable endpoint. Suppose a JSON object is stored at `/config/listeners/`: + + +```json { \"*:8080\": { \"pass\": \"applications/wp_emea_dev\" } } ``` + +Here, `/config/listeners/_*:8080` and `/config/listeners/_*:8080/pass` are also endpoints. Generally, object options are addressable by their names, array items—by their indexes (`/array/0/`). + + + +**Note**: By default, Unit is configured through a UNIX domain socket. To use this specification with OpenAPI tools interactively, [start](https://unit.nginx.org/howto/source/#source-startup) Unit with a TCP port as the control socket. + +For more information, please visit [https://unit.nginx.org/](https://unit.nginx.org/) + +## Overview + +This API client was generated by the [OpenAPI Generator](https://openapi-generator.tech) project. By using the [openapi-spec](https://openapis.org) from a remote server, you can easily generate an API client. + +- API version: 0.2.0 +- Package version: 0.4.0-beta +- Build package: `org.openapitools.codegen.languages.RustClientCodegen` + +## Installation + +Put the package under your project folder in a directory named `unit-openapi` and add the following to `Cargo.toml` under `[dependencies]`: + +``` +unit-openapi = { path = "./unit-openapi" } +``` + +## Documentation for API Endpoints + +All URIs are relative to *http://localhost:8080* + +Class | Method | HTTP request | Description +------------ | ------------- | ------------- | ------------- +*AccessLogApi* | [**delete_access_log**](docs/AccessLogApi.md#delete_access_log) | **Delete** /config/access_log | Delete the access log +*AccessLogApi* | [**delete_access_log_format**](docs/AccessLogApi.md#delete_access_log_format) | **Delete** /config/access_log/format | Delete the access log format +*AccessLogApi* | [**delete_access_log_path**](docs/AccessLogApi.md#delete_access_log_path) | **Delete** /config/access_log/path | Delete the access log path +*AccessLogApi* | [**get_access_log**](docs/AccessLogApi.md#get_access_log) | **Get** /config/access_log | Retrieve the access log +*AccessLogApi* | [**get_access_log_format**](docs/AccessLogApi.md#get_access_log_format) | **Get** /config/access_log/format | Retrieve the access log format option +*AccessLogApi* | [**get_access_log_path**](docs/AccessLogApi.md#get_access_log_path) | **Get** /config/access_log/path | Retrieve the access log path option +*AccessLogApi* | [**update_access_log**](docs/AccessLogApi.md#update_access_log) | **Put** /config/access_log | Create or overwrite the access log +*AccessLogApi* | [**update_access_log_format**](docs/AccessLogApi.md#update_access_log_format) | **Put** /config/access_log/format | Create or overwrite the access log format +*AccessLogApi* | [**update_access_log_path**](docs/AccessLogApi.md#update_access_log_path) | **Put** /config/access_log/path | Create or overwrite the access log path +*ApplicationsApi* | [**delete_application**](docs/ApplicationsApi.md#delete_application) | **Delete** /config/applications/{appName} | Delete the application object +*ApplicationsApi* | [**delete_applications**](docs/ApplicationsApi.md#delete_applications) | **Delete** /config/applications | Delete the applications object +*ApplicationsApi* | [**get_application**](docs/ApplicationsApi.md#get_application) | **Get** /config/applications/{appName} | Retrieve an application object +*ApplicationsApi* | [**get_applications**](docs/ApplicationsApi.md#get_applications) | **Get** /config/applications | Retrieve the applications object +*ApplicationsApi* | [**update_application**](docs/ApplicationsApi.md#update_application) | **Put** /config/applications/{appName} | Create or overwrite the application object +*ApplicationsApi* | [**update_applications**](docs/ApplicationsApi.md#update_applications) | **Put** /config/applications | Overwrite the applications object +*AppsApi* | [**get_app_restart**](docs/AppsApi.md#get_app_restart) | **Get** /control/applications/{appName}/restart | Restart the {appName} application +*CertificatesApi* | [**get_cert_bundle**](docs/CertificatesApi.md#get_cert_bundle) | **Get** /certificates/{bundleName} | Retrieve the certificate bundle object +*CertificatesApi* | [**get_cert_bundle_chain**](docs/CertificatesApi.md#get_cert_bundle_chain) | **Get** /certificates/{bundleName}/chain | Retrieve the certificate bundle chain +*CertificatesApi* | [**get_cert_bundle_chain_cert**](docs/CertificatesApi.md#get_cert_bundle_chain_cert) | **Get** /certificates/{bundleName}/chain/{arrayIndex} | Retrieve certificate object from the chain array +*CertificatesApi* | [**get_cert_bundle_chain_cert_issuer**](docs/CertificatesApi.md#get_cert_bundle_chain_cert_issuer) | **Get** /certificates/{bundleName}/chain/{arrayIndex}/issuer | Retrieve the issuer object from the certificate object +*CertificatesApi* | [**get_cert_bundle_chain_cert_issuer_cn**](docs/CertificatesApi.md#get_cert_bundle_chain_cert_issuer_cn) | **Get** /certificates/{bundleName}/chain/{arrayIndex}/issuer/common_name | Retrieve the common name from the certificate issuer +*CertificatesApi* | [**get_cert_bundle_chain_cert_issuer_org**](docs/CertificatesApi.md#get_cert_bundle_chain_cert_issuer_org) | **Get** /certificates/{bundleName}/chain/{arrayIndex}/issuer/organization | Retrieve the organization name from the certificate issuer +*CertificatesApi* | [**get_cert_bundle_chain_cert_issuer_state**](docs/CertificatesApi.md#get_cert_bundle_chain_cert_issuer_state) | **Get** /certificates/{bundleName}/chain/{arrayIndex}/issuer/state_or_province | Retrieve the state or province code from the certificate issuer +*CertificatesApi* | [**get_cert_bundle_chain_cert_subj**](docs/CertificatesApi.md#get_cert_bundle_chain_cert_subj) | **Get** /certificates/{bundleName}/chain/{arrayIndex}/subject | Retrieve the subject from the certificate object +*CertificatesApi* | [**get_cert_bundle_chain_cert_subj_alt**](docs/CertificatesApi.md#get_cert_bundle_chain_cert_subj_alt) | **Get** /certificates/{bundleName}/chain/{arrayIndex}/subject/alt_names/{arrayIndex2} | Retrieve an alternative name from the certificate subject +*CertificatesApi* | [**get_cert_bundle_chain_cert_subj_alt_array**](docs/CertificatesApi.md#get_cert_bundle_chain_cert_subj_alt_array) | **Get** /certificates/{bundleName}/chain/{arrayIndex}/subject/alt_names | Retrieve the alternative names array from the certificate subject +*CertificatesApi* | [**get_cert_bundle_chain_cert_subj_cn**](docs/CertificatesApi.md#get_cert_bundle_chain_cert_subj_cn) | **Get** /certificates/{bundleName}/chain/{arrayIndex}/subject/common_name | Retrieve the common name from the certificate subject +*CertificatesApi* | [**get_cert_bundle_chain_cert_subj_country**](docs/CertificatesApi.md#get_cert_bundle_chain_cert_subj_country) | **Get** /certificates/{bundleName}/chain/{arrayIndex}/subject/country | Retrieve the country code from the certificate subject +*CertificatesApi* | [**get_cert_bundle_chain_cert_subj_org**](docs/CertificatesApi.md#get_cert_bundle_chain_cert_subj_org) | **Get** /certificates/{bundleName}/chain/{arrayIndex}/subject/organization | Retrieve the organization name from the certificate subject +*CertificatesApi* | [**get_cert_bundle_chain_cert_subj_state**](docs/CertificatesApi.md#get_cert_bundle_chain_cert_subj_state) | **Get** /certificates/{bundleName}/chain/{arrayIndex}/subject/state_or_province | Retrieve the state or province code from the certificate subject +*CertificatesApi* | [**get_cert_bundle_chain_cert_valid**](docs/CertificatesApi.md#get_cert_bundle_chain_cert_valid) | **Get** /certificates/{bundleName}/chain/{arrayIndex}/validity | Retrieve the validity object from the certificate object +*CertificatesApi* | [**get_cert_bundle_chain_cert_valid_since**](docs/CertificatesApi.md#get_cert_bundle_chain_cert_valid_since) | **Get** /certificates/{bundleName}/chain/{arrayIndex}/validity/since | Retrieve the starting time of certificate validity +*CertificatesApi* | [**get_cert_bundle_chain_cert_valid_until**](docs/CertificatesApi.md#get_cert_bundle_chain_cert_valid_until) | **Get** /certificates/{bundleName}/chain/{arrayIndex}/validity/until | Retrieve the ending time of certificate validity +*CertificatesApi* | [**get_cert_bundle_chain_certissuer_country**](docs/CertificatesApi.md#get_cert_bundle_chain_certissuer_country) | **Get** /certificates/{bundleName}/chain/{arrayIndex}/issuer/country | Retrieve the country code from the certificate issuer +*CertificatesApi* | [**get_cert_bundle_key**](docs/CertificatesApi.md#get_cert_bundle_key) | **Get** /certificates/{bundleName}/key | Retrieve the certificate bundle key type +*CertificatesApi* | [**get_certs**](docs/CertificatesApi.md#get_certs) | **Get** /certificates | Retrieve the certificates object +*CertificatesApi* | [**put_cert_bundle**](docs/CertificatesApi.md#put_cert_bundle) | **Put** /certificates/{bundleName} | Create or overwrite the actual certificate bundle +*ConfigApi* | [**delete_access_log**](docs/ConfigApi.md#delete_access_log) | **Delete** /config/access_log | Delete the access log +*ConfigApi* | [**delete_access_log_format**](docs/ConfigApi.md#delete_access_log_format) | **Delete** /config/access_log/format | Delete the access log format +*ConfigApi* | [**delete_access_log_path**](docs/ConfigApi.md#delete_access_log_path) | **Delete** /config/access_log/path | Delete the access log path +*ConfigApi* | [**delete_application**](docs/ConfigApi.md#delete_application) | **Delete** /config/applications/{appName} | Delete the application object +*ConfigApi* | [**delete_applications**](docs/ConfigApi.md#delete_applications) | **Delete** /config/applications | Delete the applications object +*ConfigApi* | [**delete_config**](docs/ConfigApi.md#delete_config) | **Delete** /config | Delete the config object +*ConfigApi* | [**delete_listener**](docs/ConfigApi.md#delete_listener) | **Delete** /config/listeners/{listenerName} | Delete a listener object +*ConfigApi* | [**delete_listener_forwarded_recursive**](docs/ConfigApi.md#delete_listener_forwarded_recursive) | **Delete** /config/listeners/{listenerName}/forwarded/recursive | Delete the recursive object in a listener +*ConfigApi* | [**delete_listener_forwarded_source**](docs/ConfigApi.md#delete_listener_forwarded_source) | **Delete** /config/listeners/{listenerName}/forwarded/source/{arrayIndex} | Delete a source array item in a listener +*ConfigApi* | [**delete_listener_forwarded_sources**](docs/ConfigApi.md#delete_listener_forwarded_sources) | **Delete** /config/listeners/{listenerName}/forwarded/source | Delete the source option in a listener +*ConfigApi* | [**delete_listener_forwared**](docs/ConfigApi.md#delete_listener_forwared) | **Delete** /config/listeners/{listenerName}/forwarded | Delete the forwarded object in a listener +*ConfigApi* | [**delete_listener_tls**](docs/ConfigApi.md#delete_listener_tls) | **Delete** /config/listeners/{listenerName}/tls | Delete the tls object in a listener +*ConfigApi* | [**delete_listener_tls_certificate**](docs/ConfigApi.md#delete_listener_tls_certificate) | **Delete** /config/listeners/{listenerName}/tls/certificate/{arrayIndex} | Delete a certificate array item in a listener +*ConfigApi* | [**delete_listener_tls_certificates**](docs/ConfigApi.md#delete_listener_tls_certificates) | **Delete** /config/listeners/{listenerName}/tls/certificate | Delete the certificate option in a listener +*ConfigApi* | [**delete_listener_tls_conf_commands**](docs/ConfigApi.md#delete_listener_tls_conf_commands) | **Delete** /config/listeners/{listenerName}/tls/conf_commands | Delete the conf_commands object in a listener +*ConfigApi* | [**delete_listener_tls_session**](docs/ConfigApi.md#delete_listener_tls_session) | **Delete** /config/listeners/{listenerName}/tls/session | Delete the session object in a listener +*ConfigApi* | [**delete_listener_tls_session_ticket**](docs/ConfigApi.md#delete_listener_tls_session_ticket) | **Delete** /config/listeners/{listenerName}/tls/session/tickets/{arrayIndex} | Delete a ticket array item in a listener +*ConfigApi* | [**delete_listener_tls_session_tickets**](docs/ConfigApi.md#delete_listener_tls_session_tickets) | **Delete** /config/listeners/{listenerName}/tls/session/tickets | Delete the tickets option in a listener +*ConfigApi* | [**delete_listeners**](docs/ConfigApi.md#delete_listeners) | **Delete** /config/listeners | Delete all the listeners +*ConfigApi* | [**delete_routes**](docs/ConfigApi.md#delete_routes) | **Delete** /config/routes | Delete the routes entity +*ConfigApi* | [**delete_settings**](docs/ConfigApi.md#delete_settings) | **Delete** /config/settings | Delete the settings object +*ConfigApi* | [**delete_settings_discard_unsafe_fields**](docs/ConfigApi.md#delete_settings_discard_unsafe_fields) | **Delete** /config/settings/http/discard_unsafe_fields | Delete the discard_unsafe_fields option +*ConfigApi* | [**delete_settings_http**](docs/ConfigApi.md#delete_settings_http) | **Delete** /config/settings/http | Delete the http object +*ConfigApi* | [**delete_settings_http_body_read_timeout**](docs/ConfigApi.md#delete_settings_http_body_read_timeout) | **Delete** /config/settings/http/body_read_timeout | Delete the body_read_timeout option +*ConfigApi* | [**delete_settings_http_header_read_timeout**](docs/ConfigApi.md#delete_settings_http_header_read_timeout) | **Delete** /config/settings/http/header_read_timeout | Delete the header_read_timeout option +*ConfigApi* | [**delete_settings_http_idle_timeout**](docs/ConfigApi.md#delete_settings_http_idle_timeout) | **Delete** /config/settings/http/idle_timeout | Delete the idle_timeout option +*ConfigApi* | [**delete_settings_http_max_body_size**](docs/ConfigApi.md#delete_settings_http_max_body_size) | **Delete** /config/settings/http/max_body_size | Delete the max_body_size option +*ConfigApi* | [**delete_settings_http_send_timeout**](docs/ConfigApi.md#delete_settings_http_send_timeout) | **Delete** /config/settings/http/send_timeout | Delete the send_timeout option +*ConfigApi* | [**delete_settings_http_static**](docs/ConfigApi.md#delete_settings_http_static) | **Delete** /config/settings/http/static | Delete the static object +*ConfigApi* | [**delete_settings_http_static_mime_type**](docs/ConfigApi.md#delete_settings_http_static_mime_type) | **Delete** /config/settings/http/static/mime_types/{mimeType} | Delete the MIME type option +*ConfigApi* | [**delete_settings_http_static_mime_types**](docs/ConfigApi.md#delete_settings_http_static_mime_types) | **Delete** /config/settings/http/static/mime_types | Delete the mime_types object +*ConfigApi* | [**delete_settings_log_route**](docs/ConfigApi.md#delete_settings_log_route) | **Delete** /config/settings/http/log_route | Delete the log_route option +*ConfigApi* | [**delete_settings_server_version**](docs/ConfigApi.md#delete_settings_server_version) | **Delete** /config/settings/http/server_version | Delete the server_version option +*ConfigApi* | [**get_access_log**](docs/ConfigApi.md#get_access_log) | **Get** /config/access_log | Retrieve the access log +*ConfigApi* | [**get_access_log_format**](docs/ConfigApi.md#get_access_log_format) | **Get** /config/access_log/format | Retrieve the access log format option +*ConfigApi* | [**get_access_log_path**](docs/ConfigApi.md#get_access_log_path) | **Get** /config/access_log/path | Retrieve the access log path option +*ConfigApi* | [**get_application**](docs/ConfigApi.md#get_application) | **Get** /config/applications/{appName} | Retrieve an application object +*ConfigApi* | [**get_applications**](docs/ConfigApi.md#get_applications) | **Get** /config/applications | Retrieve the applications object +*ConfigApi* | [**get_config**](docs/ConfigApi.md#get_config) | **Get** /config | Retrieve the config +*ConfigApi* | [**get_listener**](docs/ConfigApi.md#get_listener) | **Get** /config/listeners/{listenerName} | Retrieve a listener object +*ConfigApi* | [**get_listener_forwarded**](docs/ConfigApi.md#get_listener_forwarded) | **Get** /config/listeners/{listenerName}/forwarded | Retrieve the forwarded object in a listener +*ConfigApi* | [**get_listener_forwarded_client_ip**](docs/ConfigApi.md#get_listener_forwarded_client_ip) | **Get** /config/listeners/{listenerName}/forwarded/client_ip | Retrieve the client_ip option in a listener +*ConfigApi* | [**get_listener_forwarded_protocol**](docs/ConfigApi.md#get_listener_forwarded_protocol) | **Get** /config/listeners/{listenerName}/forwarded/protocol | Retrieve the protocol option in a listener +*ConfigApi* | [**get_listener_forwarded_recursive**](docs/ConfigApi.md#get_listener_forwarded_recursive) | **Get** /config/listeners/{listenerName}/forwarded/recursive | Retrieve the recursive option in a listener +*ConfigApi* | [**get_listener_forwarded_source**](docs/ConfigApi.md#get_listener_forwarded_source) | **Get** /config/listeners/{listenerName}/forwarded/source/{arrayIndex} | Retrieve a source array item in a listener +*ConfigApi* | [**get_listener_pass**](docs/ConfigApi.md#get_listener_pass) | **Get** /config/listeners/{listenerName}/pass | Retrieve the pass option in a listener +*ConfigApi* | [**get_listener_tls**](docs/ConfigApi.md#get_listener_tls) | **Get** /config/listeners/{listenerName}/tls | Retrieve the tls object in a listener +*ConfigApi* | [**get_listener_tls_certificate**](docs/ConfigApi.md#get_listener_tls_certificate) | **Get** /config/listeners/{listenerName}/tls/certificate/{arrayIndex} | Retrieve a certificate array item in a listener +*ConfigApi* | [**get_listener_tls_session**](docs/ConfigApi.md#get_listener_tls_session) | **Get** /config/listeners/{listenerName}/tls/session | Retrieve the session object in a listener +*ConfigApi* | [**get_listener_tls_session_ticket**](docs/ConfigApi.md#get_listener_tls_session_ticket) | **Get** /config/listeners/{listenerName}/tls/session/tickets/{arrayIndex} | Retrieve a ticket array item in a listener +*ConfigApi* | [**get_listeners**](docs/ConfigApi.md#get_listeners) | **Get** /config/listeners | Retrieve all the listeners +*ConfigApi* | [**get_routes**](docs/ConfigApi.md#get_routes) | **Get** /config/routes | Retrieve the routes entity +*ConfigApi* | [**get_settings**](docs/ConfigApi.md#get_settings) | **Get** /config/settings | Retrieve the settings object +*ConfigApi* | [**get_settings_discard_unsafe_fields**](docs/ConfigApi.md#get_settings_discard_unsafe_fields) | **Get** /config/settings/http/discard_unsafe_fields | Retrieve the discard_unsafe_fields option from http settings +*ConfigApi* | [**get_settings_http**](docs/ConfigApi.md#get_settings_http) | **Get** /config/settings/http | Retrieve the http object from settings +*ConfigApi* | [**get_settings_http_body_read_timeout**](docs/ConfigApi.md#get_settings_http_body_read_timeout) | **Get** /config/settings/http/body_read_timeout | Retrieve the body_read_timeout option from http settings +*ConfigApi* | [**get_settings_http_header_read_timeout**](docs/ConfigApi.md#get_settings_http_header_read_timeout) | **Get** /config/settings/http/header_read_timeout | Retrieve the header_read_timeout option from http settings +*ConfigApi* | [**get_settings_http_idle_timeout**](docs/ConfigApi.md#get_settings_http_idle_timeout) | **Get** /config/settings/http/idle_timeout | Retrieve the idle_timeout option from http settings +*ConfigApi* | [**get_settings_http_max_body_size**](docs/ConfigApi.md#get_settings_http_max_body_size) | **Get** /config/settings/http/max_body_size | Retrieve the max_body_size option from http settings +*ConfigApi* | [**get_settings_http_send_timeout**](docs/ConfigApi.md#get_settings_http_send_timeout) | **Get** /config/settings/http/send_timeout | Retrieve the send_timeout option from http settings +*ConfigApi* | [**get_settings_http_static**](docs/ConfigApi.md#get_settings_http_static) | **Get** /config/settings/http/static | Retrieve the static object from http settings +*ConfigApi* | [**get_settings_http_static_mime_type**](docs/ConfigApi.md#get_settings_http_static_mime_type) | **Get** /config/settings/http/static/mime_types/{mimeType} | Retrieve the MIME type option from MIME type settings +*ConfigApi* | [**get_settings_http_static_mime_types**](docs/ConfigApi.md#get_settings_http_static_mime_types) | **Get** /config/settings/http/static/mime_types | Retrieve the mime_types object from static settings +*ConfigApi* | [**get_settings_log_route**](docs/ConfigApi.md#get_settings_log_route) | **Get** /config/settings/http/log_route | Retrieve the log_route option from http settings +*ConfigApi* | [**get_settings_server_version**](docs/ConfigApi.md#get_settings_server_version) | **Get** /config/settings/http/server_version | Retrieve the server_version option from http settings +*ConfigApi* | [**insert_listener_forwarded_source**](docs/ConfigApi.md#insert_listener_forwarded_source) | **Post** /config/listeners/{listenerName}/forwarded/source | Add a new source array item in a listener +*ConfigApi* | [**insert_listener_tls_certificate**](docs/ConfigApi.md#insert_listener_tls_certificate) | **Post** /config/listeners/{listenerName}/tls/certificate | Add a new certificate array item in a listener +*ConfigApi* | [**insert_listener_tls_session_ticket**](docs/ConfigApi.md#insert_listener_tls_session_ticket) | **Post** /config/listeners/{listenerName}/tls/session/tickets | Add a new tickets array item in a listener +*ConfigApi* | [**list_listener_forwarded_sources**](docs/ConfigApi.md#list_listener_forwarded_sources) | **Get** /config/listeners/{listenerName}/forwarded/source | Retrieve the source option in a listener +*ConfigApi* | [**list_listener_tls_certificates**](docs/ConfigApi.md#list_listener_tls_certificates) | **Get** /config/listeners/{listenerName}/tls/certificate | Retrieve the certificate option in a listener +*ConfigApi* | [**list_listener_tls_conf_commands**](docs/ConfigApi.md#list_listener_tls_conf_commands) | **Get** /config/listeners/{listenerName}/tls/conf_commands | Retrieve the conf_commands object in a listener +*ConfigApi* | [**list_listener_tls_session_tickets**](docs/ConfigApi.md#list_listener_tls_session_tickets) | **Get** /config/listeners/{listenerName}/tls/session/tickets | Retrieve the tickets option in a listener +*ConfigApi* | [**update_access_log**](docs/ConfigApi.md#update_access_log) | **Put** /config/access_log | Create or overwrite the access log +*ConfigApi* | [**update_access_log_format**](docs/ConfigApi.md#update_access_log_format) | **Put** /config/access_log/format | Create or overwrite the access log format +*ConfigApi* | [**update_access_log_path**](docs/ConfigApi.md#update_access_log_path) | **Put** /config/access_log/path | Create or overwrite the access log path +*ConfigApi* | [**update_application**](docs/ConfigApi.md#update_application) | **Put** /config/applications/{appName} | Create or overwrite the application object +*ConfigApi* | [**update_applications**](docs/ConfigApi.md#update_applications) | **Put** /config/applications | Overwrite the applications object +*ConfigApi* | [**update_config**](docs/ConfigApi.md#update_config) | **Put** /config | Create or overwrite the config +*ConfigApi* | [**update_listener**](docs/ConfigApi.md#update_listener) | **Put** /config/listeners/{listenerName} | Create or overwrite a listener object +*ConfigApi* | [**update_listener_forwarded**](docs/ConfigApi.md#update_listener_forwarded) | **Put** /config/listeners/{listenerName}/forwarded | Create or overwrite the forwarded object in a listener +*ConfigApi* | [**update_listener_forwarded_client_ip**](docs/ConfigApi.md#update_listener_forwarded_client_ip) | **Put** /config/listeners/{listenerName}/forwarded/client_ip | Create or overwrite the client_ip option in a listener +*ConfigApi* | [**update_listener_forwarded_protocol**](docs/ConfigApi.md#update_listener_forwarded_protocol) | **Put** /config/listeners/{listenerName}/forwarded/protocol | Create or overwrite the protocol option in a listener +*ConfigApi* | [**update_listener_forwarded_recursive**](docs/ConfigApi.md#update_listener_forwarded_recursive) | **Put** /config/listeners/{listenerName}/forwarded/recursive | Create or overwrite the recursive option in a listener +*ConfigApi* | [**update_listener_forwarded_source**](docs/ConfigApi.md#update_listener_forwarded_source) | **Put** /config/listeners/{listenerName}/forwarded/source/{arrayIndex} | Update a source array item in a listener +*ConfigApi* | [**update_listener_forwarded_sources**](docs/ConfigApi.md#update_listener_forwarded_sources) | **Put** /config/listeners/{listenerName}/forwarded/source | Create or overwrite the source option in a listener +*ConfigApi* | [**update_listener_pass**](docs/ConfigApi.md#update_listener_pass) | **Put** /config/listeners/{listenerName}/pass | Update the pass option in a listener +*ConfigApi* | [**update_listener_tls**](docs/ConfigApi.md#update_listener_tls) | **Put** /config/listeners/{listenerName}/tls | Create or overwrite the tls object in a listener +*ConfigApi* | [**update_listener_tls_certificate**](docs/ConfigApi.md#update_listener_tls_certificate) | **Put** /config/listeners/{listenerName}/tls/certificate/{arrayIndex} | Update a certificate array item in a listener +*ConfigApi* | [**update_listener_tls_certificates**](docs/ConfigApi.md#update_listener_tls_certificates) | **Put** /config/listeners/{listenerName}/tls/certificate | Create or overwrite the certificate option in a listener +*ConfigApi* | [**update_listener_tls_conf_commands**](docs/ConfigApi.md#update_listener_tls_conf_commands) | **Put** /config/listeners/{listenerName}/tls/conf_commands | Create or overwrite the conf_commands object in a listener +*ConfigApi* | [**update_listener_tls_session**](docs/ConfigApi.md#update_listener_tls_session) | **Put** /config/listeners/{listenerName}/tls/session | Create or overwrite the session object in a listener +*ConfigApi* | [**update_listener_tls_session_ticket**](docs/ConfigApi.md#update_listener_tls_session_ticket) | **Put** /config/listeners/{listenerName}/tls/session/tickets/{arrayIndex} | Create or overwrite a ticket array item in a listener +*ConfigApi* | [**update_listener_tls_session_tickets**](docs/ConfigApi.md#update_listener_tls_session_tickets) | **Put** /config/listeners/{listenerName}/tls/session/tickets | Create or overwrite the tickets option in a listener +*ConfigApi* | [**update_listeners**](docs/ConfigApi.md#update_listeners) | **Put** /config/listeners | Create or overwrite all the listeners +*ConfigApi* | [**update_routes**](docs/ConfigApi.md#update_routes) | **Put** /config/routes | Overwrite the routes entity +*ConfigApi* | [**update_settings**](docs/ConfigApi.md#update_settings) | **Put** /config/settings | Create or overwrite the settings object +*ConfigApi* | [**update_settings_discard_unsafe_fields**](docs/ConfigApi.md#update_settings_discard_unsafe_fields) | **Put** /config/settings/http/discard_unsafe_fields | Create or overwrite the discard_unsafe_fields option +*ConfigApi* | [**update_settings_http**](docs/ConfigApi.md#update_settings_http) | **Put** /config/settings/http | Create or overwrite the http object +*ConfigApi* | [**update_settings_http_body_read_timeout**](docs/ConfigApi.md#update_settings_http_body_read_timeout) | **Put** /config/settings/http/body_read_timeout | Create or overwrite the body_read_timeout option +*ConfigApi* | [**update_settings_http_header_read_timeout**](docs/ConfigApi.md#update_settings_http_header_read_timeout) | **Put** /config/settings/http/header_read_timeout | Create or overwrite the header_read_timeout option +*ConfigApi* | [**update_settings_http_idle_timeout**](docs/ConfigApi.md#update_settings_http_idle_timeout) | **Put** /config/settings/http/idle_timeout | Create or overwrite the idle_timeout option +*ConfigApi* | [**update_settings_http_max_body_size**](docs/ConfigApi.md#update_settings_http_max_body_size) | **Put** /config/settings/http/max_body_size | Create or overwrite the max_body_size option +*ConfigApi* | [**update_settings_http_send_timeout**](docs/ConfigApi.md#update_settings_http_send_timeout) | **Put** /config/settings/http/send_timeout | Create or overwrite the send_timeout option +*ConfigApi* | [**update_settings_http_static**](docs/ConfigApi.md#update_settings_http_static) | **Put** /config/settings/http/static | Create or overwrite the static object +*ConfigApi* | [**update_settings_http_static_mime_type**](docs/ConfigApi.md#update_settings_http_static_mime_type) | **Put** /config/settings/http/static/mime_types/{mimeType} | Create or overwrite the MIME type option +*ConfigApi* | [**update_settings_http_static_mime_types**](docs/ConfigApi.md#update_settings_http_static_mime_types) | **Put** /config/settings/http/static/mime_types | Create or overwrite the mime_types object +*ConfigApi* | [**update_settings_log_route**](docs/ConfigApi.md#update_settings_log_route) | **Put** /config/settings/http/log_route | Create or overwrite the log_route option +*ConfigApi* | [**update_settings_server_version**](docs/ConfigApi.md#update_settings_server_version) | **Put** /config/settings/http/server_version | Create or overwrite the server_version option +*ControlApi* | [**get_app_restart**](docs/ControlApi.md#get_app_restart) | **Get** /control/applications/{appName}/restart | Restart the {appName} application +*ListenersApi* | [**delete_listener**](docs/ListenersApi.md#delete_listener) | **Delete** /config/listeners/{listenerName} | Delete a listener object +*ListenersApi* | [**delete_listener_forwarded_recursive**](docs/ListenersApi.md#delete_listener_forwarded_recursive) | **Delete** /config/listeners/{listenerName}/forwarded/recursive | Delete the recursive object in a listener +*ListenersApi* | [**delete_listener_forwarded_source**](docs/ListenersApi.md#delete_listener_forwarded_source) | **Delete** /config/listeners/{listenerName}/forwarded/source/{arrayIndex} | Delete a source array item in a listener +*ListenersApi* | [**delete_listener_forwarded_sources**](docs/ListenersApi.md#delete_listener_forwarded_sources) | **Delete** /config/listeners/{listenerName}/forwarded/source | Delete the source option in a listener +*ListenersApi* | [**delete_listener_forwared**](docs/ListenersApi.md#delete_listener_forwared) | **Delete** /config/listeners/{listenerName}/forwarded | Delete the forwarded object in a listener +*ListenersApi* | [**delete_listener_tls**](docs/ListenersApi.md#delete_listener_tls) | **Delete** /config/listeners/{listenerName}/tls | Delete the tls object in a listener +*ListenersApi* | [**delete_listener_tls_certificate**](docs/ListenersApi.md#delete_listener_tls_certificate) | **Delete** /config/listeners/{listenerName}/tls/certificate/{arrayIndex} | Delete a certificate array item in a listener +*ListenersApi* | [**delete_listener_tls_certificates**](docs/ListenersApi.md#delete_listener_tls_certificates) | **Delete** /config/listeners/{listenerName}/tls/certificate | Delete the certificate option in a listener +*ListenersApi* | [**delete_listener_tls_conf_commands**](docs/ListenersApi.md#delete_listener_tls_conf_commands) | **Delete** /config/listeners/{listenerName}/tls/conf_commands | Delete the conf_commands object in a listener +*ListenersApi* | [**delete_listener_tls_session**](docs/ListenersApi.md#delete_listener_tls_session) | **Delete** /config/listeners/{listenerName}/tls/session | Delete the session object in a listener +*ListenersApi* | [**delete_listener_tls_session_ticket**](docs/ListenersApi.md#delete_listener_tls_session_ticket) | **Delete** /config/listeners/{listenerName}/tls/session/tickets/{arrayIndex} | Delete a ticket array item in a listener +*ListenersApi* | [**delete_listener_tls_session_tickets**](docs/ListenersApi.md#delete_listener_tls_session_tickets) | **Delete** /config/listeners/{listenerName}/tls/session/tickets | Delete the tickets option in a listener +*ListenersApi* | [**delete_listeners**](docs/ListenersApi.md#delete_listeners) | **Delete** /config/listeners | Delete all the listeners +*ListenersApi* | [**get_listener**](docs/ListenersApi.md#get_listener) | **Get** /config/listeners/{listenerName} | Retrieve a listener object +*ListenersApi* | [**get_listener_forwarded**](docs/ListenersApi.md#get_listener_forwarded) | **Get** /config/listeners/{listenerName}/forwarded | Retrieve the forwarded object in a listener +*ListenersApi* | [**get_listener_forwarded_client_ip**](docs/ListenersApi.md#get_listener_forwarded_client_ip) | **Get** /config/listeners/{listenerName}/forwarded/client_ip | Retrieve the client_ip option in a listener +*ListenersApi* | [**get_listener_forwarded_protocol**](docs/ListenersApi.md#get_listener_forwarded_protocol) | **Get** /config/listeners/{listenerName}/forwarded/protocol | Retrieve the protocol option in a listener +*ListenersApi* | [**get_listener_forwarded_recursive**](docs/ListenersApi.md#get_listener_forwarded_recursive) | **Get** /config/listeners/{listenerName}/forwarded/recursive | Retrieve the recursive option in a listener +*ListenersApi* | [**get_listener_forwarded_source**](docs/ListenersApi.md#get_listener_forwarded_source) | **Get** /config/listeners/{listenerName}/forwarded/source/{arrayIndex} | Retrieve a source array item in a listener +*ListenersApi* | [**get_listener_pass**](docs/ListenersApi.md#get_listener_pass) | **Get** /config/listeners/{listenerName}/pass | Retrieve the pass option in a listener +*ListenersApi* | [**get_listener_tls**](docs/ListenersApi.md#get_listener_tls) | **Get** /config/listeners/{listenerName}/tls | Retrieve the tls object in a listener +*ListenersApi* | [**get_listener_tls_certificate**](docs/ListenersApi.md#get_listener_tls_certificate) | **Get** /config/listeners/{listenerName}/tls/certificate/{arrayIndex} | Retrieve a certificate array item in a listener +*ListenersApi* | [**get_listener_tls_session**](docs/ListenersApi.md#get_listener_tls_session) | **Get** /config/listeners/{listenerName}/tls/session | Retrieve the session object in a listener +*ListenersApi* | [**get_listener_tls_session_ticket**](docs/ListenersApi.md#get_listener_tls_session_ticket) | **Get** /config/listeners/{listenerName}/tls/session/tickets/{arrayIndex} | Retrieve a ticket array item in a listener +*ListenersApi* | [**get_listeners**](docs/ListenersApi.md#get_listeners) | **Get** /config/listeners | Retrieve all the listeners +*ListenersApi* | [**insert_listener_forwarded_source**](docs/ListenersApi.md#insert_listener_forwarded_source) | **Post** /config/listeners/{listenerName}/forwarded/source | Add a new source array item in a listener +*ListenersApi* | [**insert_listener_tls_certificate**](docs/ListenersApi.md#insert_listener_tls_certificate) | **Post** /config/listeners/{listenerName}/tls/certificate | Add a new certificate array item in a listener +*ListenersApi* | [**insert_listener_tls_session_ticket**](docs/ListenersApi.md#insert_listener_tls_session_ticket) | **Post** /config/listeners/{listenerName}/tls/session/tickets | Add a new tickets array item in a listener +*ListenersApi* | [**list_listener_forwarded_sources**](docs/ListenersApi.md#list_listener_forwarded_sources) | **Get** /config/listeners/{listenerName}/forwarded/source | Retrieve the source option in a listener +*ListenersApi* | [**list_listener_tls_certificates**](docs/ListenersApi.md#list_listener_tls_certificates) | **Get** /config/listeners/{listenerName}/tls/certificate | Retrieve the certificate option in a listener +*ListenersApi* | [**list_listener_tls_conf_commands**](docs/ListenersApi.md#list_listener_tls_conf_commands) | **Get** /config/listeners/{listenerName}/tls/conf_commands | Retrieve the conf_commands object in a listener +*ListenersApi* | [**list_listener_tls_session_tickets**](docs/ListenersApi.md#list_listener_tls_session_tickets) | **Get** /config/listeners/{listenerName}/tls/session/tickets | Retrieve the tickets option in a listener +*ListenersApi* | [**update_listener**](docs/ListenersApi.md#update_listener) | **Put** /config/listeners/{listenerName} | Create or overwrite a listener object +*ListenersApi* | [**update_listener_forwarded**](docs/ListenersApi.md#update_listener_forwarded) | **Put** /config/listeners/{listenerName}/forwarded | Create or overwrite the forwarded object in a listener +*ListenersApi* | [**update_listener_forwarded_client_ip**](docs/ListenersApi.md#update_listener_forwarded_client_ip) | **Put** /config/listeners/{listenerName}/forwarded/client_ip | Create or overwrite the client_ip option in a listener +*ListenersApi* | [**update_listener_forwarded_protocol**](docs/ListenersApi.md#update_listener_forwarded_protocol) | **Put** /config/listeners/{listenerName}/forwarded/protocol | Create or overwrite the protocol option in a listener +*ListenersApi* | [**update_listener_forwarded_recursive**](docs/ListenersApi.md#update_listener_forwarded_recursive) | **Put** /config/listeners/{listenerName}/forwarded/recursive | Create or overwrite the recursive option in a listener +*ListenersApi* | [**update_listener_forwarded_source**](docs/ListenersApi.md#update_listener_forwarded_source) | **Put** /config/listeners/{listenerName}/forwarded/source/{arrayIndex} | Update a source array item in a listener +*ListenersApi* | [**update_listener_forwarded_sources**](docs/ListenersApi.md#update_listener_forwarded_sources) | **Put** /config/listeners/{listenerName}/forwarded/source | Create or overwrite the source option in a listener +*ListenersApi* | [**update_listener_pass**](docs/ListenersApi.md#update_listener_pass) | **Put** /config/listeners/{listenerName}/pass | Update the pass option in a listener +*ListenersApi* | [**update_listener_tls**](docs/ListenersApi.md#update_listener_tls) | **Put** /config/listeners/{listenerName}/tls | Create or overwrite the tls object in a listener +*ListenersApi* | [**update_listener_tls_certificate**](docs/ListenersApi.md#update_listener_tls_certificate) | **Put** /config/listeners/{listenerName}/tls/certificate/{arrayIndex} | Update a certificate array item in a listener +*ListenersApi* | [**update_listener_tls_certificates**](docs/ListenersApi.md#update_listener_tls_certificates) | **Put** /config/listeners/{listenerName}/tls/certificate | Create or overwrite the certificate option in a listener +*ListenersApi* | [**update_listener_tls_conf_commands**](docs/ListenersApi.md#update_listener_tls_conf_commands) | **Put** /config/listeners/{listenerName}/tls/conf_commands | Create or overwrite the conf_commands object in a listener +*ListenersApi* | [**update_listener_tls_session**](docs/ListenersApi.md#update_listener_tls_session) | **Put** /config/listeners/{listenerName}/tls/session | Create or overwrite the session object in a listener +*ListenersApi* | [**update_listener_tls_session_ticket**](docs/ListenersApi.md#update_listener_tls_session_ticket) | **Put** /config/listeners/{listenerName}/tls/session/tickets/{arrayIndex} | Create or overwrite a ticket array item in a listener +*ListenersApi* | [**update_listener_tls_session_tickets**](docs/ListenersApi.md#update_listener_tls_session_tickets) | **Put** /config/listeners/{listenerName}/tls/session/tickets | Create or overwrite the tickets option in a listener +*ListenersApi* | [**update_listeners**](docs/ListenersApi.md#update_listeners) | **Put** /config/listeners | Create or overwrite all the listeners +*RoutesApi* | [**delete_routes**](docs/RoutesApi.md#delete_routes) | **Delete** /config/routes | Delete the routes entity +*RoutesApi* | [**get_routes**](docs/RoutesApi.md#get_routes) | **Get** /config/routes | Retrieve the routes entity +*RoutesApi* | [**update_routes**](docs/RoutesApi.md#update_routes) | **Put** /config/routes | Overwrite the routes entity +*SettingsApi* | [**delete_settings**](docs/SettingsApi.md#delete_settings) | **Delete** /config/settings | Delete the settings object +*SettingsApi* | [**delete_settings_discard_unsafe_fields**](docs/SettingsApi.md#delete_settings_discard_unsafe_fields) | **Delete** /config/settings/http/discard_unsafe_fields | Delete the discard_unsafe_fields option +*SettingsApi* | [**delete_settings_http**](docs/SettingsApi.md#delete_settings_http) | **Delete** /config/settings/http | Delete the http object +*SettingsApi* | [**delete_settings_http_body_read_timeout**](docs/SettingsApi.md#delete_settings_http_body_read_timeout) | **Delete** /config/settings/http/body_read_timeout | Delete the body_read_timeout option +*SettingsApi* | [**delete_settings_http_header_read_timeout**](docs/SettingsApi.md#delete_settings_http_header_read_timeout) | **Delete** /config/settings/http/header_read_timeout | Delete the header_read_timeout option +*SettingsApi* | [**delete_settings_http_idle_timeout**](docs/SettingsApi.md#delete_settings_http_idle_timeout) | **Delete** /config/settings/http/idle_timeout | Delete the idle_timeout option +*SettingsApi* | [**delete_settings_http_max_body_size**](docs/SettingsApi.md#delete_settings_http_max_body_size) | **Delete** /config/settings/http/max_body_size | Delete the max_body_size option +*SettingsApi* | [**delete_settings_http_send_timeout**](docs/SettingsApi.md#delete_settings_http_send_timeout) | **Delete** /config/settings/http/send_timeout | Delete the send_timeout option +*SettingsApi* | [**delete_settings_http_static**](docs/SettingsApi.md#delete_settings_http_static) | **Delete** /config/settings/http/static | Delete the static object +*SettingsApi* | [**delete_settings_http_static_mime_type**](docs/SettingsApi.md#delete_settings_http_static_mime_type) | **Delete** /config/settings/http/static/mime_types/{mimeType} | Delete the MIME type option +*SettingsApi* | [**delete_settings_http_static_mime_types**](docs/SettingsApi.md#delete_settings_http_static_mime_types) | **Delete** /config/settings/http/static/mime_types | Delete the mime_types object +*SettingsApi* | [**delete_settings_log_route**](docs/SettingsApi.md#delete_settings_log_route) | **Delete** /config/settings/http/log_route | Delete the log_route option +*SettingsApi* | [**delete_settings_server_version**](docs/SettingsApi.md#delete_settings_server_version) | **Delete** /config/settings/http/server_version | Delete the server_version option +*SettingsApi* | [**get_settings**](docs/SettingsApi.md#get_settings) | **Get** /config/settings | Retrieve the settings object +*SettingsApi* | [**get_settings_discard_unsafe_fields**](docs/SettingsApi.md#get_settings_discard_unsafe_fields) | **Get** /config/settings/http/discard_unsafe_fields | Retrieve the discard_unsafe_fields option from http settings +*SettingsApi* | [**get_settings_http**](docs/SettingsApi.md#get_settings_http) | **Get** /config/settings/http | Retrieve the http object from settings +*SettingsApi* | [**get_settings_http_body_read_timeout**](docs/SettingsApi.md#get_settings_http_body_read_timeout) | **Get** /config/settings/http/body_read_timeout | Retrieve the body_read_timeout option from http settings +*SettingsApi* | [**get_settings_http_header_read_timeout**](docs/SettingsApi.md#get_settings_http_header_read_timeout) | **Get** /config/settings/http/header_read_timeout | Retrieve the header_read_timeout option from http settings +*SettingsApi* | [**get_settings_http_idle_timeout**](docs/SettingsApi.md#get_settings_http_idle_timeout) | **Get** /config/settings/http/idle_timeout | Retrieve the idle_timeout option from http settings +*SettingsApi* | [**get_settings_http_max_body_size**](docs/SettingsApi.md#get_settings_http_max_body_size) | **Get** /config/settings/http/max_body_size | Retrieve the max_body_size option from http settings +*SettingsApi* | [**get_settings_http_send_timeout**](docs/SettingsApi.md#get_settings_http_send_timeout) | **Get** /config/settings/http/send_timeout | Retrieve the send_timeout option from http settings +*SettingsApi* | [**get_settings_http_static**](docs/SettingsApi.md#get_settings_http_static) | **Get** /config/settings/http/static | Retrieve the static object from http settings +*SettingsApi* | [**get_settings_http_static_mime_type**](docs/SettingsApi.md#get_settings_http_static_mime_type) | **Get** /config/settings/http/static/mime_types/{mimeType} | Retrieve the MIME type option from MIME type settings +*SettingsApi* | [**get_settings_http_static_mime_types**](docs/SettingsApi.md#get_settings_http_static_mime_types) | **Get** /config/settings/http/static/mime_types | Retrieve the mime_types object from static settings +*SettingsApi* | [**get_settings_log_route**](docs/SettingsApi.md#get_settings_log_route) | **Get** /config/settings/http/log_route | Retrieve the log_route option from http settings +*SettingsApi* | [**get_settings_server_version**](docs/SettingsApi.md#get_settings_server_version) | **Get** /config/settings/http/server_version | Retrieve the server_version option from http settings +*SettingsApi* | [**update_settings**](docs/SettingsApi.md#update_settings) | **Put** /config/settings | Create or overwrite the settings object +*SettingsApi* | [**update_settings_discard_unsafe_fields**](docs/SettingsApi.md#update_settings_discard_unsafe_fields) | **Put** /config/settings/http/discard_unsafe_fields | Create or overwrite the discard_unsafe_fields option +*SettingsApi* | [**update_settings_http**](docs/SettingsApi.md#update_settings_http) | **Put** /config/settings/http | Create or overwrite the http object +*SettingsApi* | [**update_settings_http_body_read_timeout**](docs/SettingsApi.md#update_settings_http_body_read_timeout) | **Put** /config/settings/http/body_read_timeout | Create or overwrite the body_read_timeout option +*SettingsApi* | [**update_settings_http_header_read_timeout**](docs/SettingsApi.md#update_settings_http_header_read_timeout) | **Put** /config/settings/http/header_read_timeout | Create or overwrite the header_read_timeout option +*SettingsApi* | [**update_settings_http_idle_timeout**](docs/SettingsApi.md#update_settings_http_idle_timeout) | **Put** /config/settings/http/idle_timeout | Create or overwrite the idle_timeout option +*SettingsApi* | [**update_settings_http_max_body_size**](docs/SettingsApi.md#update_settings_http_max_body_size) | **Put** /config/settings/http/max_body_size | Create or overwrite the max_body_size option +*SettingsApi* | [**update_settings_http_send_timeout**](docs/SettingsApi.md#update_settings_http_send_timeout) | **Put** /config/settings/http/send_timeout | Create or overwrite the send_timeout option +*SettingsApi* | [**update_settings_http_static**](docs/SettingsApi.md#update_settings_http_static) | **Put** /config/settings/http/static | Create or overwrite the static object +*SettingsApi* | [**update_settings_http_static_mime_type**](docs/SettingsApi.md#update_settings_http_static_mime_type) | **Put** /config/settings/http/static/mime_types/{mimeType} | Create or overwrite the MIME type option +*SettingsApi* | [**update_settings_http_static_mime_types**](docs/SettingsApi.md#update_settings_http_static_mime_types) | **Put** /config/settings/http/static/mime_types | Create or overwrite the mime_types object +*SettingsApi* | [**update_settings_log_route**](docs/SettingsApi.md#update_settings_log_route) | **Put** /config/settings/http/log_route | Create or overwrite the log_route option +*SettingsApi* | [**update_settings_server_version**](docs/SettingsApi.md#update_settings_server_version) | **Put** /config/settings/http/server_version | Create or overwrite the server_version option +*StatusApi* | [**get_status**](docs/StatusApi.md#get_status) | **Get** /status | Retrieve the status object +*StatusApi* | [**get_status_applications**](docs/StatusApi.md#get_status_applications) | **Get** /status/applications | Retrieve the applications status object +*StatusApi* | [**get_status_applications_app**](docs/StatusApi.md#get_status_applications_app) | **Get** /status/applications/{appName} | Retrieve the app status object +*StatusApi* | [**get_status_applications_app_processes**](docs/StatusApi.md#get_status_applications_app_processes) | **Get** /status/applications/{appName}/processes | Retrieve the processes app status object +*StatusApi* | [**get_status_applications_app_processes_idle**](docs/StatusApi.md#get_status_applications_app_processes_idle) | **Get** /status/applications/{appName}/processes/idle | Retrieve the idle processes app status number +*StatusApi* | [**get_status_applications_app_processes_running**](docs/StatusApi.md#get_status_applications_app_processes_running) | **Get** /status/applications/{appName}/processes/running | Retrieve the running processes app status number +*StatusApi* | [**get_status_applications_app_processes_starting**](docs/StatusApi.md#get_status_applications_app_processes_starting) | **Get** /status/applications/{appName}/processes/starting | Retrieve the starting processes app status number +*StatusApi* | [**get_status_applications_app_requests**](docs/StatusApi.md#get_status_applications_app_requests) | **Get** /status/applications/{appName}/requests | Retrieve the requests app status object +*StatusApi* | [**get_status_applications_app_requests_active**](docs/StatusApi.md#get_status_applications_app_requests_active) | **Get** /status/applications/{appName}/requests/active | Retrieve the active requests app status number +*StatusApi* | [**get_status_connections**](docs/StatusApi.md#get_status_connections) | **Get** /status/connections | Retrieve the connections status object +*StatusApi* | [**get_status_connections_accepted**](docs/StatusApi.md#get_status_connections_accepted) | **Get** /status/connections/accepted | Retrieve the accepted connections number +*StatusApi* | [**get_status_connections_active**](docs/StatusApi.md#get_status_connections_active) | **Get** /status/connections/active | Retrieve the active connections number +*StatusApi* | [**get_status_connections_closed**](docs/StatusApi.md#get_status_connections_closed) | **Get** /status/connections/closed | Retrieve the closed connections number +*StatusApi* | [**get_status_connections_idle**](docs/StatusApi.md#get_status_connections_idle) | **Get** /status/connections/idle | Retrieve the idle connections number +*StatusApi* | [**get_status_requests**](docs/StatusApi.md#get_status_requests) | **Get** /status/requests | Retrieve the requests status object +*StatusApi* | [**get_status_requests_total**](docs/StatusApi.md#get_status_requests_total) | **Get** /status/requests/total | Retrieve the total requests number +*TlsApi* | [**delete_listener_tls**](docs/TlsApi.md#delete_listener_tls) | **Delete** /config/listeners/{listenerName}/tls | Delete the tls object in a listener +*TlsApi* | [**delete_listener_tls_certificate**](docs/TlsApi.md#delete_listener_tls_certificate) | **Delete** /config/listeners/{listenerName}/tls/certificate/{arrayIndex} | Delete a certificate array item in a listener +*TlsApi* | [**delete_listener_tls_certificates**](docs/TlsApi.md#delete_listener_tls_certificates) | **Delete** /config/listeners/{listenerName}/tls/certificate | Delete the certificate option in a listener +*TlsApi* | [**delete_listener_tls_conf_commands**](docs/TlsApi.md#delete_listener_tls_conf_commands) | **Delete** /config/listeners/{listenerName}/tls/conf_commands | Delete the conf_commands object in a listener +*TlsApi* | [**delete_listener_tls_session**](docs/TlsApi.md#delete_listener_tls_session) | **Delete** /config/listeners/{listenerName}/tls/session | Delete the session object in a listener +*TlsApi* | [**delete_listener_tls_session_ticket**](docs/TlsApi.md#delete_listener_tls_session_ticket) | **Delete** /config/listeners/{listenerName}/tls/session/tickets/{arrayIndex} | Delete a ticket array item in a listener +*TlsApi* | [**delete_listener_tls_session_tickets**](docs/TlsApi.md#delete_listener_tls_session_tickets) | **Delete** /config/listeners/{listenerName}/tls/session/tickets | Delete the tickets option in a listener +*TlsApi* | [**get_listener_tls**](docs/TlsApi.md#get_listener_tls) | **Get** /config/listeners/{listenerName}/tls | Retrieve the tls object in a listener +*TlsApi* | [**get_listener_tls_certificate**](docs/TlsApi.md#get_listener_tls_certificate) | **Get** /config/listeners/{listenerName}/tls/certificate/{arrayIndex} | Retrieve a certificate array item in a listener +*TlsApi* | [**get_listener_tls_session**](docs/TlsApi.md#get_listener_tls_session) | **Get** /config/listeners/{listenerName}/tls/session | Retrieve the session object in a listener +*TlsApi* | [**get_listener_tls_session_ticket**](docs/TlsApi.md#get_listener_tls_session_ticket) | **Get** /config/listeners/{listenerName}/tls/session/tickets/{arrayIndex} | Retrieve a ticket array item in a listener +*TlsApi* | [**insert_listener_tls_certificate**](docs/TlsApi.md#insert_listener_tls_certificate) | **Post** /config/listeners/{listenerName}/tls/certificate | Add a new certificate array item in a listener +*TlsApi* | [**insert_listener_tls_session_ticket**](docs/TlsApi.md#insert_listener_tls_session_ticket) | **Post** /config/listeners/{listenerName}/tls/session/tickets | Add a new tickets array item in a listener +*TlsApi* | [**list_listener_tls_certificates**](docs/TlsApi.md#list_listener_tls_certificates) | **Get** /config/listeners/{listenerName}/tls/certificate | Retrieve the certificate option in a listener +*TlsApi* | [**list_listener_tls_conf_commands**](docs/TlsApi.md#list_listener_tls_conf_commands) | **Get** /config/listeners/{listenerName}/tls/conf_commands | Retrieve the conf_commands object in a listener +*TlsApi* | [**list_listener_tls_session_tickets**](docs/TlsApi.md#list_listener_tls_session_tickets) | **Get** /config/listeners/{listenerName}/tls/session/tickets | Retrieve the tickets option in a listener +*TlsApi* | [**update_listener_tls**](docs/TlsApi.md#update_listener_tls) | **Put** /config/listeners/{listenerName}/tls | Create or overwrite the tls object in a listener +*TlsApi* | [**update_listener_tls_certificate**](docs/TlsApi.md#update_listener_tls_certificate) | **Put** /config/listeners/{listenerName}/tls/certificate/{arrayIndex} | Update a certificate array item in a listener +*TlsApi* | [**update_listener_tls_certificates**](docs/TlsApi.md#update_listener_tls_certificates) | **Put** /config/listeners/{listenerName}/tls/certificate | Create or overwrite the certificate option in a listener +*TlsApi* | [**update_listener_tls_conf_commands**](docs/TlsApi.md#update_listener_tls_conf_commands) | **Put** /config/listeners/{listenerName}/tls/conf_commands | Create or overwrite the conf_commands object in a listener +*TlsApi* | [**update_listener_tls_session**](docs/TlsApi.md#update_listener_tls_session) | **Put** /config/listeners/{listenerName}/tls/session | Create or overwrite the session object in a listener +*TlsApi* | [**update_listener_tls_session_ticket**](docs/TlsApi.md#update_listener_tls_session_ticket) | **Put** /config/listeners/{listenerName}/tls/session/tickets/{arrayIndex} | Create or overwrite a ticket array item in a listener +*TlsApi* | [**update_listener_tls_session_tickets**](docs/TlsApi.md#update_listener_tls_session_tickets) | **Put** /config/listeners/{listenerName}/tls/session/tickets | Create or overwrite the tickets option in a listener +*XffApi* | [**delete_listener_forwarded_recursive**](docs/XffApi.md#delete_listener_forwarded_recursive) | **Delete** /config/listeners/{listenerName}/forwarded/recursive | Delete the recursive object in a listener +*XffApi* | [**delete_listener_forwarded_source**](docs/XffApi.md#delete_listener_forwarded_source) | **Delete** /config/listeners/{listenerName}/forwarded/source/{arrayIndex} | Delete a source array item in a listener +*XffApi* | [**delete_listener_forwarded_sources**](docs/XffApi.md#delete_listener_forwarded_sources) | **Delete** /config/listeners/{listenerName}/forwarded/source | Delete the source option in a listener +*XffApi* | [**delete_listener_forwared**](docs/XffApi.md#delete_listener_forwared) | **Delete** /config/listeners/{listenerName}/forwarded | Delete the forwarded object in a listener +*XffApi* | [**get_listener_forwarded**](docs/XffApi.md#get_listener_forwarded) | **Get** /config/listeners/{listenerName}/forwarded | Retrieve the forwarded object in a listener +*XffApi* | [**get_listener_forwarded_client_ip**](docs/XffApi.md#get_listener_forwarded_client_ip) | **Get** /config/listeners/{listenerName}/forwarded/client_ip | Retrieve the client_ip option in a listener +*XffApi* | [**get_listener_forwarded_protocol**](docs/XffApi.md#get_listener_forwarded_protocol) | **Get** /config/listeners/{listenerName}/forwarded/protocol | Retrieve the protocol option in a listener +*XffApi* | [**get_listener_forwarded_recursive**](docs/XffApi.md#get_listener_forwarded_recursive) | **Get** /config/listeners/{listenerName}/forwarded/recursive | Retrieve the recursive option in a listener +*XffApi* | [**get_listener_forwarded_source**](docs/XffApi.md#get_listener_forwarded_source) | **Get** /config/listeners/{listenerName}/forwarded/source/{arrayIndex} | Retrieve a source array item in a listener +*XffApi* | [**insert_listener_forwarded_source**](docs/XffApi.md#insert_listener_forwarded_source) | **Post** /config/listeners/{listenerName}/forwarded/source | Add a new source array item in a listener +*XffApi* | [**list_listener_forwarded_sources**](docs/XffApi.md#list_listener_forwarded_sources) | **Get** /config/listeners/{listenerName}/forwarded/source | Retrieve the source option in a listener +*XffApi* | [**update_listener_forwarded**](docs/XffApi.md#update_listener_forwarded) | **Put** /config/listeners/{listenerName}/forwarded | Create or overwrite the forwarded object in a listener +*XffApi* | [**update_listener_forwarded_client_ip**](docs/XffApi.md#update_listener_forwarded_client_ip) | **Put** /config/listeners/{listenerName}/forwarded/client_ip | Create or overwrite the client_ip option in a listener +*XffApi* | [**update_listener_forwarded_protocol**](docs/XffApi.md#update_listener_forwarded_protocol) | **Put** /config/listeners/{listenerName}/forwarded/protocol | Create or overwrite the protocol option in a listener +*XffApi* | [**update_listener_forwarded_recursive**](docs/XffApi.md#update_listener_forwarded_recursive) | **Put** /config/listeners/{listenerName}/forwarded/recursive | Create or overwrite the recursive option in a listener +*XffApi* | [**update_listener_forwarded_source**](docs/XffApi.md#update_listener_forwarded_source) | **Put** /config/listeners/{listenerName}/forwarded/source/{arrayIndex} | Update a source array item in a listener +*XffApi* | [**update_listener_forwarded_sources**](docs/XffApi.md#update_listener_forwarded_sources) | **Put** /config/listeners/{listenerName}/forwarded/source | Create or overwrite the source option in a listener + + +## Documentation For Models + + - [CertBundle](docs/CertBundle.md) + - [CertBundleChainCert](docs/CertBundleChainCert.md) + - [CertBundleChainCertIssuer](docs/CertBundleChainCertIssuer.md) + - [CertBundleChainCertSubj](docs/CertBundleChainCertSubj.md) + - [CertBundleChainCertValidity](docs/CertBundleChainCertValidity.md) + - [Config](docs/Config.md) + - [ConfigAccessLog](docs/ConfigAccessLog.md) + - [ConfigAccessLogObject](docs/ConfigAccessLogObject.md) + - [ConfigApplication](docs/ConfigApplication.md) + - [ConfigApplicationCommon](docs/ConfigApplicationCommon.md) + - [ConfigApplicationCommonIsolation](docs/ConfigApplicationCommonIsolation.md) + - [ConfigApplicationCommonIsolationAutomount](docs/ConfigApplicationCommonIsolationAutomount.md) + - [ConfigApplicationCommonIsolationCgroup](docs/ConfigApplicationCommonIsolationCgroup.md) + - [ConfigApplicationCommonIsolationGidmapInner](docs/ConfigApplicationCommonIsolationGidmapInner.md) + - [ConfigApplicationCommonIsolationNamespaces](docs/ConfigApplicationCommonIsolationNamespaces.md) + - [ConfigApplicationCommonIsolationUidmapInner](docs/ConfigApplicationCommonIsolationUidmapInner.md) + - [ConfigApplicationCommonLimits](docs/ConfigApplicationCommonLimits.md) + - [ConfigApplicationCommonProcesses](docs/ConfigApplicationCommonProcesses.md) + - [ConfigApplicationCommonProcessesAnyOf](docs/ConfigApplicationCommonProcessesAnyOf.md) + - [ConfigApplicationExternal](docs/ConfigApplicationExternal.md) + - [ConfigApplicationExternalAllOf](docs/ConfigApplicationExternalAllOf.md) + - [ConfigApplicationJava](docs/ConfigApplicationJava.md) + - [ConfigApplicationJavaAllOf](docs/ConfigApplicationJavaAllOf.md) + - [ConfigApplicationPerl](docs/ConfigApplicationPerl.md) + - [ConfigApplicationPerlAllOf](docs/ConfigApplicationPerlAllOf.md) + - [ConfigApplicationPhp](docs/ConfigApplicationPhp.md) + - [ConfigApplicationPhpAllOf](docs/ConfigApplicationPhpAllOf.md) + - [ConfigApplicationPhpAllOfOptions](docs/ConfigApplicationPhpAllOfOptions.md) + - [ConfigApplicationPhpAllOfTargets](docs/ConfigApplicationPhpAllOfTargets.md) + - [ConfigApplicationPython](docs/ConfigApplicationPython.md) + - [ConfigApplicationPythonAllOf](docs/ConfigApplicationPythonAllOf.md) + - [ConfigApplicationPythonAllOfPath](docs/ConfigApplicationPythonAllOfPath.md) + - [ConfigApplicationPythonAllOfTargets](docs/ConfigApplicationPythonAllOfTargets.md) + - [ConfigApplicationRuby](docs/ConfigApplicationRuby.md) + - [ConfigApplicationRubyAllOf](docs/ConfigApplicationRubyAllOf.md) + - [ConfigListener](docs/ConfigListener.md) + - [ConfigListenerForwarded](docs/ConfigListenerForwarded.md) + - [ConfigListenerForwardedSource](docs/ConfigListenerForwardedSource.md) + - [ConfigListenerTls](docs/ConfigListenerTls.md) + - [ConfigListenerTlsCertificate](docs/ConfigListenerTlsCertificate.md) + - [ConfigListenerTlsSession](docs/ConfigListenerTlsSession.md) + - [ConfigListenerTlsSessionTickets](docs/ConfigListenerTlsSessionTickets.md) + - [ConfigRouteStep](docs/ConfigRouteStep.md) + - [ConfigRouteStepAction](docs/ConfigRouteStepAction.md) + - [ConfigRouteStepActionPass](docs/ConfigRouteStepActionPass.md) + - [ConfigRouteStepActionProxy](docs/ConfigRouteStepActionProxy.md) + - [ConfigRouteStepActionReturn](docs/ConfigRouteStepActionReturn.md) + - [ConfigRouteStepActionShare](docs/ConfigRouteStepActionShare.md) + - [ConfigRouteStepMatch](docs/ConfigRouteStepMatch.md) + - [ConfigRouteStepMatchArguments](docs/ConfigRouteStepMatchArguments.md) + - [ConfigRouteStepMatchCookies](docs/ConfigRouteStepMatchCookies.md) + - [ConfigRouteStepMatchHeaders](docs/ConfigRouteStepMatchHeaders.md) + - [ConfigRoutes](docs/ConfigRoutes.md) + - [ConfigSettings](docs/ConfigSettings.md) + - [ConfigSettingsHttp](docs/ConfigSettingsHttp.md) + - [ConfigSettingsHttpStatic](docs/ConfigSettingsHttpStatic.md) + - [ConfigSettingsHttpStaticMimeType](docs/ConfigSettingsHttpStaticMimeType.md) + - [Status](docs/Status.md) + - [StatusApplicationsApp](docs/StatusApplicationsApp.md) + - [StatusApplicationsAppProcesses](docs/StatusApplicationsAppProcesses.md) + - [StatusApplicationsAppRequests](docs/StatusApplicationsAppRequests.md) + - [StatusConnections](docs/StatusConnections.md) + - [StatusRequests](docs/StatusRequests.md) + - [StringOrStringArray](docs/StringOrStringArray.md) + + +To get access to the crate's generated documentation, use: + +``` +cargo doc --open +``` + +## Author + +unit-owner@nginx.org + diff --git a/cli/unit-openapi/openapi-templates/Cargo.mustache b/cli/unit-openapi/openapi-templates/Cargo.mustache new file mode 100644 index 000000000..feca05ee1 --- /dev/null +++ b/cli/unit-openapi/openapi-templates/Cargo.mustache @@ -0,0 +1,65 @@ +[package] +name = "{{{packageName}}}" +version = "{{#lambdaVersion}}{{{packageVersion}}}{{/lambdaVersion}}" +{{#infoEmail}} +authors = ["{{{.}}}"] +{{/infoEmail}} +{{^infoEmail}} +authors = ["OpenAPI Generator team and contributors"] +{{/infoEmail}} +{{#appDescription}} +description = "{{{.}}}" +{{/appDescription}} +{{#licenseInfo}} +license = "{{.}}" +{{/licenseInfo}} +{{^licenseInfo}} +# Override this license by providing a License Object in the OpenAPI. +license = "Unlicense" +{{/licenseInfo}} +edition = "2018" +{{#publishRustRegistry}} +publish = ["{{.}}"] +{{/publishRustRegistry}} +{{#repositoryUrl}} +repository = "{{.}}" +{{/repositoryUrl}} +{{#documentationUrl}} +documentation = "{{.}}" +{{/documentationUrl}} +{{#homePageUrl}} +homepage = "{{.}} +{{/homePageUrl}} + +[dependencies] +serde = "1.0" +serde_derive = "1.0" +{{#serdeWith}} +serde_with = "^2.0" +{{/serdeWith}} +serde_json = "1.0" +url = "2.2" +{{#hyper}} +hyper = { version = "0.14" } +http = "0.2" +base64 = "0.21" +futures = "0.3" +{{/hyper}} +{{#withAWSV4Signature}} +aws-sigv4 = "0.3.0" +http = "0.2.5" +secrecy = "0.8.0" +{{/withAWSV4Signature}} +{{#reqwest}} +{{^supportAsync}} +reqwest = "~0.9" +{{/supportAsync}} +{{#supportAsync}} +{{#supportMiddleware}} +reqwest-middleware = "0.2.0" +{{/supportMiddleware}} +[dependencies.reqwest] +version = "^0.11" +features = ["json", "multipart"] +{{/supportAsync}} +{{/reqwest}} diff --git a/cli/unit-openapi/openapi-templates/request.rs b/cli/unit-openapi/openapi-templates/request.rs new file mode 100644 index 000000000..9cf480cc1 --- /dev/null +++ b/cli/unit-openapi/openapi-templates/request.rs @@ -0,0 +1,248 @@ +use std::collections::HashMap; +use std::pin::Pin; + +use base64::{alphabet, Engine}; +use base64::engine::general_purpose::NO_PAD; +use base64::engine::GeneralPurpose; + +use futures; +use futures::Future; +use futures::future::*; +use hyper; +use hyper::header::{AUTHORIZATION, CONTENT_LENGTH, CONTENT_TYPE, HeaderValue, USER_AGENT}; +use serde; +use serde_json; + +use super::{configuration, Error}; + +const MIME_ENCODER: GeneralPurpose = GeneralPurpose::new(&alphabet::STANDARD, NO_PAD); + +pub(crate) struct ApiKey { + pub in_header: bool, + pub in_query: bool, + pub param_name: String, +} + +impl ApiKey { + fn key(&self, prefix: &Option, key: &str) -> String { + match prefix { + None => key.to_owned(), + Some(ref prefix) => format!("{} {}", prefix, key), + } + } +} + +#[allow(dead_code)] +pub(crate) enum Auth { + None, + ApiKey(ApiKey), + Basic, + Oauth, +} + +/// If the authorization type is unspecified then it will be automatically detected based +/// on the configuration. This functionality is useful when the OpenAPI definition does not +/// include an authorization scheme. +pub(crate) struct Request { + auth: Option, + method: hyper::Method, + path: String, + query_params: HashMap, + no_return_type: bool, + path_params: HashMap, + form_params: HashMap, + header_params: HashMap, + // TODO: multiple body params are possible technically, but not supported here. + serialized_body: Option, +} + +#[allow(dead_code)] +impl Request { + pub fn new(method: hyper::Method, path: String) -> Self { + Request { + auth: None, + method, + path, + query_params: HashMap::new(), + path_params: HashMap::new(), + form_params: HashMap::new(), + header_params: HashMap::new(), + serialized_body: None, + no_return_type: false, + } + } + + pub fn with_body_param(mut self, param: T) -> Self { + self.serialized_body = Some(serde_json::to_string(¶m).unwrap()); + self + } + + pub fn with_header_param(mut self, basename: String, param: String) -> Self { + self.header_params.insert(basename, param); + self + } + + #[allow(unused)] + pub fn with_query_param(mut self, basename: String, param: String) -> Self { + self.query_params.insert(basename, param); + self + } + + #[allow(unused)] + pub fn with_path_param(mut self, basename: String, param: String) -> Self { + self.path_params.insert(basename, param); + self + } + + #[allow(unused)] + pub fn with_form_param(mut self, basename: String, param: String) -> Self { + self.form_params.insert(basename, param); + self + } + + pub fn returns_nothing(mut self) -> Self { + self.no_return_type = true; + self + } + + pub fn with_auth(mut self, auth: Auth) -> Self { + self.auth = Some(auth); + self + } + + pub fn execute<'a, C, U>( + self, + conf: &configuration::Configuration, + ) -> Pin> + 'a>> + where + C: hyper::client::connect::Connect + Clone + std::marker::Send + Sync, + U: Sized + std::marker::Send + 'a, + for<'de> U: serde::Deserialize<'de>, + { + let mut query_string = ::url::form_urlencoded::Serializer::new("".to_owned()); + + let mut path = self.path; + for (k, v) in self.path_params { + // replace {id} with the value of the id path param + path = path.replace(&format!("{{{}}}", k), &v); + } + + for (key, val) in self.query_params { + query_string.append_pair(&key, &val); + } + + let mut uri_str = format!("{}{}", conf.base_path, path); + + let query_string_str = query_string.finish(); + if query_string_str != "" { + uri_str += "?"; + uri_str += &query_string_str; + } + let uri: hyper::Uri = match uri_str.parse() { + Err(e) => return Box::pin(futures::future::err(Error::UriError(e))), + Ok(u) => u, + }; + + let mut req_builder = hyper::Request::builder() + .uri(uri) + .method(self.method); + + // Detect the authorization type if it hasn't been set. + let auth = self.auth.unwrap_or_else(|| + if conf.api_key.is_some() { + panic!("Cannot automatically set the API key from the configuration, it must be specified in the OpenAPI definition") + } else if conf.oauth_access_token.is_some() { + Auth::Oauth + } else if conf.basic_auth.is_some() { + Auth::Basic + } else { + Auth::None + } + ); + match auth { + Auth::ApiKey(apikey) => { + if let Some(ref key) = conf.api_key { + let val = apikey.key(&key.prefix, &key.key); + if apikey.in_query { + query_string.append_pair(&apikey.param_name, &val); + } + if apikey.in_header { + req_builder = req_builder.header(&apikey.param_name, val); + } + } + } + Auth::Basic => { + if let Some(ref auth_conf) = conf.basic_auth { + let mut text = auth_conf.0.clone(); + text.push(':'); + if let Some(ref pass) = auth_conf.1 { + text.push_str(&pass[..]); + } + let encoded = MIME_ENCODER.encode(&text); + req_builder = req_builder.header(AUTHORIZATION, encoded); + } + } + Auth::Oauth => { + if let Some(ref token) = conf.oauth_access_token { + let text = "Bearer ".to_owned() + token; + req_builder = req_builder.header(AUTHORIZATION, text); + } + } + Auth::None => {} + } + + if let Some(ref user_agent) = conf.user_agent { + req_builder = req_builder.header(USER_AGENT, match HeaderValue::from_str(user_agent) { + Ok(header_value) => header_value, + Err(e) => return Box::pin(futures::future::err(super::Error::Header(e))) + }); + } + + for (k, v) in self.header_params { + req_builder = req_builder.header(&k, v); + } + + let req_headers = req_builder.headers_mut().unwrap(); + let request_result = if self.form_params.len() > 0 { + req_headers.insert(CONTENT_TYPE, HeaderValue::from_static("application/x-www-form-urlencoded")); + let mut enc = ::url::form_urlencoded::Serializer::new("".to_owned()); + for (k, v) in self.form_params { + enc.append_pair(&k, &v); + } + req_builder.body(hyper::Body::from(enc.finish())) + } else if let Some(body) = self.serialized_body { + req_headers.insert(CONTENT_TYPE, HeaderValue::from_static("application/json")); + req_headers.insert(CONTENT_LENGTH, body.len().into()); + req_builder.body(hyper::Body::from(body)) + } else { + req_builder.body(hyper::Body::default()) + }; + let request = match request_result { + Ok(request) => request, + Err(e) => return Box::pin(futures::future::err(Error::from(e))) + }; + + let no_return_type = self.no_return_type; + Box::pin(conf.client + .request(request) + .map_err(|e| Error::from(e)) + .and_then(move |response| { + let status = response.status(); + if !status.is_success() { + futures::future::err::(Error::from((status, response.into_body()))).boxed() + } else if no_return_type { + // This is a hack; if there's no_ret_type, U is (), but serde_json gives an + // error when deserializing "" into (), so deserialize 'null' into it + // instead. + // An alternate option would be to require U: Default, and then return + // U::default() here instead since () implements that, but then we'd + // need to impl default for all models. + futures::future::ok::(serde_json::from_str("null").expect("serde null value")).boxed() + } else { + hyper::body::to_bytes(response.into_body()) + .map(|bytes| serde_json::from_slice(&bytes.unwrap())) + .map_err(|e| Error::from(e)).boxed() + } + })) + } +} diff --git a/cli/unit-openapi/src/apis/access_log_api.rs b/cli/unit-openapi/src/apis/access_log_api.rs new file mode 100644 index 000000000..432734109 --- /dev/null +++ b/cli/unit-openapi/src/apis/access_log_api.rs @@ -0,0 +1,150 @@ +/* + * NGINX Unit 1.31.1 + * + * NGINX Unit is a lightweight and versatile application runtime that provides the essential components for your web application as a single open-source server: running application code, serving static assets, handling TLS and request routing. **Important**: Ufnit's API is designed to expose any part of its configuration as an addressable endpoint. Suppose a JSON object is stored at `/config/listeners/`: ```json { \"*:8080\": { \"pass\": \"applications/wp_emea_dev\" } } ``` Here, `/config/listeners/_*:8080` and `/config/listeners/_*:8080/pass` are also endpoints. Generally, object options are addressable by their names, array items—by their indexes (`/array/0/`). **Note**: By default, Unit is configured through a UNIX domain socket. To use this specification with OpenAPI tools interactively, [start](https://unit.nginx.org/howto/source/#source-startup) Unit with a TCP port as the control socket. + * + * The version of the OpenAPI document: 0.2.0 + * Contact: unit-owner@nginx.org + * Generated by: https://openapi-generator.tech + */ + +use std::borrow::Borrow; +#[allow(unused_imports)] +use std::option::Option; +use std::pin::Pin; +use std::rc::Rc; + +use futures::Future; +use hyper; + +use super::request as __internal_request; +use super::{configuration, Error}; + +pub struct AccessLogApiClient +where + C: Clone + std::marker::Send + Sync + 'static, +{ + configuration: Rc>, +} + +impl AccessLogApiClient +where + C: Clone + std::marker::Send + Sync, +{ + pub fn new(configuration: Rc>) -> AccessLogApiClient { + AccessLogApiClient { configuration } + } +} + +pub trait AccessLogApi { + fn delete_access_log( + &self, + ) -> Pin, Error>>>>; + fn delete_access_log_format( + &self, + ) -> Pin, Error>>>>; + fn delete_access_log_path( + &self, + ) -> Pin, Error>>>>; + fn get_access_log(&self) -> Pin>>>; + fn get_access_log_format(&self) -> Pin>>>; + fn get_access_log_path(&self) -> Pin>>>; + fn update_access_log( + &self, + config_access_log: crate::models::ConfigAccessLog, + ) -> Pin, Error>>>>; + fn update_access_log_format( + &self, + body: &str, + ) -> Pin, Error>>>>; + fn update_access_log_path( + &self, + body: &str, + ) -> Pin, Error>>>>; +} + +impl AccessLogApi for AccessLogApiClient +where + C: Clone + std::marker::Send + Sync, +{ + #[allow(unused_mut)] + fn delete_access_log( + &self, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new(hyper::Method::DELETE, "/config/access_log".to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn delete_access_log_format( + &self, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new(hyper::Method::DELETE, "/config/access_log/format".to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn delete_access_log_path( + &self, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new(hyper::Method::DELETE, "/config/access_log/path".to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_access_log(&self) -> Pin>>> { + let mut req = __internal_request::Request::new(hyper::Method::GET, "/config/access_log".to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_access_log_format(&self) -> Pin>>> { + let mut req = __internal_request::Request::new(hyper::Method::GET, "/config/access_log/format".to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_access_log_path(&self) -> Pin>>> { + let mut req = __internal_request::Request::new(hyper::Method::GET, "/config/access_log/path".to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn update_access_log( + &self, + config_access_log: crate::models::ConfigAccessLog, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new(hyper::Method::PUT, "/config/access_log".to_string()); + req = req.with_body_param(config_access_log); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn update_access_log_format( + &self, + body: &str, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new(hyper::Method::PUT, "/config/access_log/format".to_string()); + req = req.with_body_param(body); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn update_access_log_path( + &self, + body: &str, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new(hyper::Method::PUT, "/config/access_log/path".to_string()); + req = req.with_body_param(body); + + req.execute(self.configuration.borrow()) + } +} diff --git a/cli/unit-openapi/src/apis/applications_api.rs b/cli/unit-openapi/src/apis/applications_api.rs new file mode 100644 index 000000000..6705f8cb5 --- /dev/null +++ b/cli/unit-openapi/src/apis/applications_api.rs @@ -0,0 +1,139 @@ +/* + * NGINX Unit 1.31.1 + * + * NGINX Unit is a lightweight and versatile application runtime that provides the essential components for your web application as a single open-source server: running application code, serving static assets, handling TLS and request routing. **Important**: Ufnit's API is designed to expose any part of its configuration as an addressable endpoint. Suppose a JSON object is stored at `/config/listeners/`: ```json { \"*:8080\": { \"pass\": \"applications/wp_emea_dev\" } } ``` Here, `/config/listeners/_*:8080` and `/config/listeners/_*:8080/pass` are also endpoints. Generally, object options are addressable by their names, array items—by their indexes (`/array/0/`). **Note**: By default, Unit is configured through a UNIX domain socket. To use this specification with OpenAPI tools interactively, [start](https://unit.nginx.org/howto/source/#source-startup) Unit with a TCP port as the control socket. + * + * The version of the OpenAPI document: 0.2.0 + * Contact: unit-owner@nginx.org + * Generated by: https://openapi-generator.tech + */ + +use std::borrow::Borrow; +#[allow(unused_imports)] +use std::option::Option; +use std::pin::Pin; +use std::rc::Rc; + +use futures::Future; +use hyper; + +use super::request as __internal_request; +use super::{configuration, Error}; + +pub struct ApplicationsApiClient +where + C: Clone + std::marker::Send + Sync + 'static, +{ + configuration: Rc>, +} + +impl ApplicationsApiClient +where + C: Clone + std::marker::Send + Sync, +{ + pub fn new(configuration: Rc>) -> ApplicationsApiClient { + ApplicationsApiClient { configuration } + } +} + +pub trait ApplicationsApi { + fn delete_application( + &self, + app_name: &str, + ) -> Pin, Error>>>>; + fn delete_applications( + &self, + ) -> Pin, Error>>>>; + fn get_application( + &self, + app_name: &str, + ) -> Pin>>>; + fn get_applications( + &self, + ) -> Pin< + Box, Error>>>, + >; + fn update_application( + &self, + app_name: &str, + config_application: crate::models::ConfigApplication, + ) -> Pin, Error>>>>; + fn update_applications( + &self, + request_body: ::std::collections::HashMap, + ) -> Pin, Error>>>>; +} + +impl ApplicationsApi for ApplicationsApiClient +where + C: Clone + std::marker::Send + Sync, +{ + #[allow(unused_mut)] + fn delete_application( + &self, + app_name: &str, + ) -> Pin, Error>>>> { + let mut req = + __internal_request::Request::new(hyper::Method::DELETE, "/config/applications/{appName}".to_string()); + req = req.with_path_param("appName".to_string(), app_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn delete_applications( + &self, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new(hyper::Method::DELETE, "/config/applications".to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_application( + &self, + app_name: &str, + ) -> Pin>>> { + let mut req = + __internal_request::Request::new(hyper::Method::GET, "/config/applications/{appName}".to_string()); + req = req.with_path_param("appName".to_string(), app_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_applications( + &self, + ) -> Pin< + Box, Error>>>, + > { + let mut req = __internal_request::Request::new(hyper::Method::GET, "/config/applications".to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn update_application( + &self, + app_name: &str, + config_application: crate::models::ConfigApplication, + ) -> Pin, Error>>>> { + let mut req = + __internal_request::Request::new(hyper::Method::PUT, "/config/applications/{appName}".to_string()); + req = req.with_path_param("appName".to_string(), app_name.to_string()); + req = req.with_body_param(config_application); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn update_applications( + &self, + request_body: ::std::collections::HashMap, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new(hyper::Method::PUT, "/config/applications".to_string()); + req = req.with_body_param(request_body); + + req.execute(self.configuration.borrow()) + } +} diff --git a/cli/unit-openapi/src/apis/apps_api.rs b/cli/unit-openapi/src/apis/apps_api.rs new file mode 100644 index 000000000..377836f9a --- /dev/null +++ b/cli/unit-openapi/src/apis/apps_api.rs @@ -0,0 +1,63 @@ +/* + * NGINX Unit 1.31.1 + * + * NGINX Unit is a lightweight and versatile application runtime that provides the essential components for your web application as a single open-source server: running application code, serving static assets, handling TLS and request routing. **Important**: Ufnit's API is designed to expose any part of its configuration as an addressable endpoint. Suppose a JSON object is stored at `/config/listeners/`: ```json { \"*:8080\": { \"pass\": \"applications/wp_emea_dev\" } } ``` Here, `/config/listeners/_*:8080` and `/config/listeners/_*:8080/pass` are also endpoints. Generally, object options are addressable by their names, array items—by their indexes (`/array/0/`). **Note**: By default, Unit is configured through a UNIX domain socket. To use this specification with OpenAPI tools interactively, [start](https://unit.nginx.org/howto/source/#source-startup) Unit with a TCP port as the control socket. + * + * The version of the OpenAPI document: 0.2.0 + * Contact: unit-owner@nginx.org + * Generated by: https://openapi-generator.tech + */ + +use std::borrow::Borrow; +#[allow(unused_imports)] +use std::option::Option; +use std::pin::Pin; +use std::rc::Rc; + +use futures::Future; +use hyper; + +use super::request as __internal_request; +use super::{configuration, Error}; + +pub struct AppsApiClient +where + C: Clone + std::marker::Send + Sync + 'static, +{ + configuration: Rc>, +} + +impl AppsApiClient +where + C: Clone + std::marker::Send + Sync, +{ + pub fn new(configuration: Rc>) -> AppsApiClient { + AppsApiClient { configuration } + } +} + +pub trait AppsApi { + fn get_app_restart( + &self, + app_name: &str, + ) -> Pin, Error>>>>; +} + +impl AppsApi for AppsApiClient +where + C: Clone + std::marker::Send + Sync, +{ + #[allow(unused_mut)] + fn get_app_restart( + &self, + app_name: &str, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::GET, + "/control/applications/{appName}/restart".to_string(), + ); + req = req.with_path_param("appName".to_string(), app_name.to_string()); + + req.execute(self.configuration.borrow()) + } +} diff --git a/cli/unit-openapi/src/apis/certificates_api.rs b/cli/unit-openapi/src/apis/certificates_api.rs new file mode 100644 index 000000000..203ec669c --- /dev/null +++ b/cli/unit-openapi/src/apis/certificates_api.rs @@ -0,0 +1,456 @@ +/* + * NGINX Unit 1.31.1 + * + * NGINX Unit is a lightweight and versatile application runtime that provides the essential components for your web application as a single open-source server: running application code, serving static assets, handling TLS and request routing. **Important**: Ufnit's API is designed to expose any part of its configuration as an addressable endpoint. Suppose a JSON object is stored at `/config/listeners/`: ```json { \"*:8080\": { \"pass\": \"applications/wp_emea_dev\" } } ``` Here, `/config/listeners/_*:8080` and `/config/listeners/_*:8080/pass` are also endpoints. Generally, object options are addressable by their names, array items—by their indexes (`/array/0/`). **Note**: By default, Unit is configured through a UNIX domain socket. To use this specification with OpenAPI tools interactively, [start](https://unit.nginx.org/howto/source/#source-startup) Unit with a TCP port as the control socket. + * + * The version of the OpenAPI document: 0.2.0 + * Contact: unit-owner@nginx.org + * Generated by: https://openapi-generator.tech + */ + +use std::borrow::Borrow; +#[allow(unused_imports)] +use std::option::Option; +use std::pin::Pin; +use std::rc::Rc; + +use futures::Future; +use hyper; + +use super::request as __internal_request; +use super::{configuration, Error}; + +pub struct CertificatesApiClient +where + C: Clone + std::marker::Send + Sync + 'static, +{ + configuration: Rc>, +} + +impl CertificatesApiClient +where + C: Clone + std::marker::Send + Sync, +{ + pub fn new(configuration: Rc>) -> CertificatesApiClient { + CertificatesApiClient { configuration } + } +} + +pub trait CertificatesApi { + fn get_cert_bundle( + &self, + bundle_name: &str, + ) -> Pin>>>; + fn get_cert_bundle_chain( + &self, + bundle_name: &str, + ) -> Pin, Error>>>>; + fn get_cert_bundle_chain_cert( + &self, + array_index: i32, + bundle_name: &str, + ) -> Pin>>>; + fn get_cert_bundle_chain_cert_issuer( + &self, + array_index: i32, + bundle_name: &str, + ) -> Pin>>>; + fn get_cert_bundle_chain_cert_issuer_cn( + &self, + array_index: i32, + bundle_name: &str, + ) -> Pin>>>; + fn get_cert_bundle_chain_cert_issuer_org( + &self, + array_index: i32, + bundle_name: &str, + ) -> Pin>>>; + fn get_cert_bundle_chain_cert_issuer_state( + &self, + array_index: i32, + bundle_name: &str, + ) -> Pin>>>; + fn get_cert_bundle_chain_cert_subj( + &self, + array_index: i32, + bundle_name: &str, + ) -> Pin>>>; + fn get_cert_bundle_chain_cert_subj_alt( + &self, + array_index: i32, + array_index2: i32, + bundle_name: &str, + ) -> Pin>>>; + fn get_cert_bundle_chain_cert_subj_alt_array( + &self, + array_index: i32, + bundle_name: &str, + ) -> Pin, Error>>>>; + fn get_cert_bundle_chain_cert_subj_cn( + &self, + array_index: i32, + bundle_name: &str, + ) -> Pin>>>; + fn get_cert_bundle_chain_cert_subj_country( + &self, + array_index: i32, + bundle_name: &str, + ) -> Pin>>>; + fn get_cert_bundle_chain_cert_subj_org( + &self, + array_index: i32, + bundle_name: &str, + ) -> Pin>>>; + fn get_cert_bundle_chain_cert_subj_state( + &self, + array_index: i32, + bundle_name: &str, + ) -> Pin>>>; + fn get_cert_bundle_chain_cert_valid( + &self, + array_index: i32, + bundle_name: &str, + ) -> Pin>>>; + fn get_cert_bundle_chain_cert_valid_since( + &self, + array_index: i32, + bundle_name: &str, + ) -> Pin>>>; + fn get_cert_bundle_chain_cert_valid_until( + &self, + array_index: i32, + bundle_name: &str, + ) -> Pin>>>; + fn get_cert_bundle_chain_certissuer_country( + &self, + array_index: i32, + bundle_name: &str, + ) -> Pin>>>; + fn get_cert_bundle_key(&self, bundle_name: &str) -> Pin>>>; + fn get_certs( + &self, + ) -> Pin, Error>>>>; + fn put_cert_bundle( + &self, + bundle_name: &str, + body: std::path::PathBuf, + ) -> Pin, Error>>>>; +} + +impl CertificatesApi for CertificatesApiClient +where + C: Clone + std::marker::Send + Sync, +{ + #[allow(unused_mut)] + fn get_cert_bundle( + &self, + bundle_name: &str, + ) -> Pin>>> { + let mut req = __internal_request::Request::new(hyper::Method::GET, "/certificates/{bundleName}".to_string()); + req = req.with_path_param("bundleName".to_string(), bundle_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_cert_bundle_chain( + &self, + bundle_name: &str, + ) -> Pin, Error>>>> { + let mut req = + __internal_request::Request::new(hyper::Method::GET, "/certificates/{bundleName}/chain".to_string()); + req = req.with_path_param("bundleName".to_string(), bundle_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_cert_bundle_chain_cert( + &self, + array_index: i32, + bundle_name: &str, + ) -> Pin>>> { + let mut req = __internal_request::Request::new( + hyper::Method::GET, + "/certificates/{bundleName}/chain/{arrayIndex}".to_string(), + ); + req = req.with_path_param("arrayIndex".to_string(), array_index.to_string()); + req = req.with_path_param("bundleName".to_string(), bundle_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_cert_bundle_chain_cert_issuer( + &self, + array_index: i32, + bundle_name: &str, + ) -> Pin>>> { + let mut req = __internal_request::Request::new( + hyper::Method::GET, + "/certificates/{bundleName}/chain/{arrayIndex}/issuer".to_string(), + ); + req = req.with_path_param("arrayIndex".to_string(), array_index.to_string()); + req = req.with_path_param("bundleName".to_string(), bundle_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_cert_bundle_chain_cert_issuer_cn( + &self, + array_index: i32, + bundle_name: &str, + ) -> Pin>>> { + let mut req = __internal_request::Request::new( + hyper::Method::GET, + "/certificates/{bundleName}/chain/{arrayIndex}/issuer/common_name".to_string(), + ); + req = req.with_path_param("arrayIndex".to_string(), array_index.to_string()); + req = req.with_path_param("bundleName".to_string(), bundle_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_cert_bundle_chain_cert_issuer_org( + &self, + array_index: i32, + bundle_name: &str, + ) -> Pin>>> { + let mut req = __internal_request::Request::new( + hyper::Method::GET, + "/certificates/{bundleName}/chain/{arrayIndex}/issuer/organization".to_string(), + ); + req = req.with_path_param("arrayIndex".to_string(), array_index.to_string()); + req = req.with_path_param("bundleName".to_string(), bundle_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_cert_bundle_chain_cert_issuer_state( + &self, + array_index: i32, + bundle_name: &str, + ) -> Pin>>> { + let mut req = __internal_request::Request::new( + hyper::Method::GET, + "/certificates/{bundleName}/chain/{arrayIndex}/issuer/state_or_province".to_string(), + ); + req = req.with_path_param("arrayIndex".to_string(), array_index.to_string()); + req = req.with_path_param("bundleName".to_string(), bundle_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_cert_bundle_chain_cert_subj( + &self, + array_index: i32, + bundle_name: &str, + ) -> Pin>>> { + let mut req = __internal_request::Request::new( + hyper::Method::GET, + "/certificates/{bundleName}/chain/{arrayIndex}/subject".to_string(), + ); + req = req.with_path_param("arrayIndex".to_string(), array_index.to_string()); + req = req.with_path_param("bundleName".to_string(), bundle_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_cert_bundle_chain_cert_subj_alt( + &self, + array_index: i32, + array_index2: i32, + bundle_name: &str, + ) -> Pin>>> { + let mut req = __internal_request::Request::new( + hyper::Method::GET, + "/certificates/{bundleName}/chain/{arrayIndex}/subject/alt_names/{arrayIndex2}".to_string(), + ); + req = req.with_path_param("arrayIndex".to_string(), array_index.to_string()); + req = req.with_path_param("arrayIndex2".to_string(), array_index2.to_string()); + req = req.with_path_param("bundleName".to_string(), bundle_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_cert_bundle_chain_cert_subj_alt_array( + &self, + array_index: i32, + bundle_name: &str, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::GET, + "/certificates/{bundleName}/chain/{arrayIndex}/subject/alt_names".to_string(), + ); + req = req.with_path_param("arrayIndex".to_string(), array_index.to_string()); + req = req.with_path_param("bundleName".to_string(), bundle_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_cert_bundle_chain_cert_subj_cn( + &self, + array_index: i32, + bundle_name: &str, + ) -> Pin>>> { + let mut req = __internal_request::Request::new( + hyper::Method::GET, + "/certificates/{bundleName}/chain/{arrayIndex}/subject/common_name".to_string(), + ); + req = req.with_path_param("arrayIndex".to_string(), array_index.to_string()); + req = req.with_path_param("bundleName".to_string(), bundle_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_cert_bundle_chain_cert_subj_country( + &self, + array_index: i32, + bundle_name: &str, + ) -> Pin>>> { + let mut req = __internal_request::Request::new( + hyper::Method::GET, + "/certificates/{bundleName}/chain/{arrayIndex}/subject/country".to_string(), + ); + req = req.with_path_param("arrayIndex".to_string(), array_index.to_string()); + req = req.with_path_param("bundleName".to_string(), bundle_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_cert_bundle_chain_cert_subj_org( + &self, + array_index: i32, + bundle_name: &str, + ) -> Pin>>> { + let mut req = __internal_request::Request::new( + hyper::Method::GET, + "/certificates/{bundleName}/chain/{arrayIndex}/subject/organization".to_string(), + ); + req = req.with_path_param("arrayIndex".to_string(), array_index.to_string()); + req = req.with_path_param("bundleName".to_string(), bundle_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_cert_bundle_chain_cert_subj_state( + &self, + array_index: i32, + bundle_name: &str, + ) -> Pin>>> { + let mut req = __internal_request::Request::new( + hyper::Method::GET, + "/certificates/{bundleName}/chain/{arrayIndex}/subject/state_or_province".to_string(), + ); + req = req.with_path_param("arrayIndex".to_string(), array_index.to_string()); + req = req.with_path_param("bundleName".to_string(), bundle_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_cert_bundle_chain_cert_valid( + &self, + array_index: i32, + bundle_name: &str, + ) -> Pin>>> { + let mut req = __internal_request::Request::new( + hyper::Method::GET, + "/certificates/{bundleName}/chain/{arrayIndex}/validity".to_string(), + ); + req = req.with_path_param("arrayIndex".to_string(), array_index.to_string()); + req = req.with_path_param("bundleName".to_string(), bundle_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_cert_bundle_chain_cert_valid_since( + &self, + array_index: i32, + bundle_name: &str, + ) -> Pin>>> { + let mut req = __internal_request::Request::new( + hyper::Method::GET, + "/certificates/{bundleName}/chain/{arrayIndex}/validity/since".to_string(), + ); + req = req.with_path_param("arrayIndex".to_string(), array_index.to_string()); + req = req.with_path_param("bundleName".to_string(), bundle_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_cert_bundle_chain_cert_valid_until( + &self, + array_index: i32, + bundle_name: &str, + ) -> Pin>>> { + let mut req = __internal_request::Request::new( + hyper::Method::GET, + "/certificates/{bundleName}/chain/{arrayIndex}/validity/until".to_string(), + ); + req = req.with_path_param("arrayIndex".to_string(), array_index.to_string()); + req = req.with_path_param("bundleName".to_string(), bundle_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_cert_bundle_chain_certissuer_country( + &self, + array_index: i32, + bundle_name: &str, + ) -> Pin>>> { + let mut req = __internal_request::Request::new( + hyper::Method::GET, + "/certificates/{bundleName}/chain/{arrayIndex}/issuer/country".to_string(), + ); + req = req.with_path_param("arrayIndex".to_string(), array_index.to_string()); + req = req.with_path_param("bundleName".to_string(), bundle_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_cert_bundle_key(&self, bundle_name: &str) -> Pin>>> { + let mut req = + __internal_request::Request::new(hyper::Method::GET, "/certificates/{bundleName}/key".to_string()); + req = req.with_path_param("bundleName".to_string(), bundle_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_certs( + &self, + ) -> Pin, Error>>>> + { + let mut req = __internal_request::Request::new(hyper::Method::GET, "/certificates".to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn put_cert_bundle( + &self, + bundle_name: &str, + body: std::path::PathBuf, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new(hyper::Method::PUT, "/certificates/{bundleName}".to_string()); + req = req.with_path_param("bundleName".to_string(), bundle_name.to_string()); + req = req.with_body_param(body); + + req.execute(self.configuration.borrow()) + } +} diff --git a/cli/unit-openapi/src/apis/client.rs b/cli/unit-openapi/src/apis/client.rs new file mode 100644 index 000000000..f1e85b4b4 --- /dev/null +++ b/cli/unit-openapi/src/apis/client.rs @@ -0,0 +1,91 @@ +use std::rc::Rc; + +use super::configuration::Configuration; +use hyper; + +pub struct APIClient { + access_log_api: Box, + applications_api: Box, + apps_api: Box, + certificates_api: Box, + config_api: Box, + control_api: Box, + listeners_api: Box, + routes_api: Box, + settings_api: Box, + status_api: Box, + tls_api: Box, + xff_api: Box, +} + +impl APIClient { + pub fn new(configuration: Configuration) -> APIClient + where + C: Clone + std::marker::Send + Sync + 'static, + { + let rc = Rc::new(configuration); + + APIClient { + access_log_api: Box::new(crate::apis::AccessLogApiClient::new(rc.clone())), + applications_api: Box::new(crate::apis::ApplicationsApiClient::new(rc.clone())), + apps_api: Box::new(crate::apis::AppsApiClient::new(rc.clone())), + certificates_api: Box::new(crate::apis::CertificatesApiClient::new(rc.clone())), + config_api: Box::new(crate::apis::ConfigApiClient::new(rc.clone())), + control_api: Box::new(crate::apis::ControlApiClient::new(rc.clone())), + listeners_api: Box::new(crate::apis::ListenersApiClient::new(rc.clone())), + routes_api: Box::new(crate::apis::RoutesApiClient::new(rc.clone())), + settings_api: Box::new(crate::apis::SettingsApiClient::new(rc.clone())), + status_api: Box::new(crate::apis::StatusApiClient::new(rc.clone())), + tls_api: Box::new(crate::apis::TlsApiClient::new(rc.clone())), + xff_api: Box::new(crate::apis::XffApiClient::new(rc.clone())), + } + } + + pub fn access_log_api(&self) -> &dyn crate::apis::AccessLogApi { + self.access_log_api.as_ref() + } + + pub fn applications_api(&self) -> &dyn crate::apis::ApplicationsApi { + self.applications_api.as_ref() + } + + pub fn apps_api(&self) -> &dyn crate::apis::AppsApi { + self.apps_api.as_ref() + } + + pub fn certificates_api(&self) -> &dyn crate::apis::CertificatesApi { + self.certificates_api.as_ref() + } + + pub fn config_api(&self) -> &dyn crate::apis::ConfigApi { + self.config_api.as_ref() + } + + pub fn control_api(&self) -> &dyn crate::apis::ControlApi { + self.control_api.as_ref() + } + + pub fn listeners_api(&self) -> &dyn crate::apis::ListenersApi { + self.listeners_api.as_ref() + } + + pub fn routes_api(&self) -> &dyn crate::apis::RoutesApi { + self.routes_api.as_ref() + } + + pub fn settings_api(&self) -> &dyn crate::apis::SettingsApi { + self.settings_api.as_ref() + } + + pub fn status_api(&self) -> &dyn crate::apis::StatusApi { + self.status_api.as_ref() + } + + pub fn tls_api(&self) -> &dyn crate::apis::TlsApi { + self.tls_api.as_ref() + } + + pub fn xff_api(&self) -> &dyn crate::apis::XffApi { + self.xff_api.as_ref() + } +} diff --git a/cli/unit-openapi/src/apis/config_api.rs b/cli/unit-openapi/src/apis/config_api.rs new file mode 100644 index 000000000..dced27811 --- /dev/null +++ b/cli/unit-openapi/src/apis/config_api.rs @@ -0,0 +1,1782 @@ +/* + * NGINX Unit 1.31.1 + * + * NGINX Unit is a lightweight and versatile application runtime that provides the essential components for your web application as a single open-source server: running application code, serving static assets, handling TLS and request routing. **Important**: Ufnit's API is designed to expose any part of its configuration as an addressable endpoint. Suppose a JSON object is stored at `/config/listeners/`: ```json { \"*:8080\": { \"pass\": \"applications/wp_emea_dev\" } } ``` Here, `/config/listeners/_*:8080` and `/config/listeners/_*:8080/pass` are also endpoints. Generally, object options are addressable by their names, array items—by their indexes (`/array/0/`). **Note**: By default, Unit is configured through a UNIX domain socket. To use this specification with OpenAPI tools interactively, [start](https://unit.nginx.org/howto/source/#source-startup) Unit with a TCP port as the control socket. + * + * The version of the OpenAPI document: 0.2.0 + * Contact: unit-owner@nginx.org + * Generated by: https://openapi-generator.tech + */ + +use std::borrow::Borrow; +#[allow(unused_imports)] +use std::option::Option; +use std::pin::Pin; +use std::rc::Rc; + +use futures::Future; +use hyper; + +use super::request as __internal_request; +use super::{configuration, Error}; + +pub struct ConfigApiClient +where + C: Clone + std::marker::Send + Sync + 'static, +{ + configuration: Rc>, +} + +impl ConfigApiClient +where + C: Clone + std::marker::Send + Sync, +{ + pub fn new(configuration: Rc>) -> ConfigApiClient { + ConfigApiClient { configuration } + } +} + +pub trait ConfigApi { + fn delete_access_log( + &self, + ) -> Pin, Error>>>>; + fn delete_access_log_format( + &self, + ) -> Pin, Error>>>>; + fn delete_access_log_path( + &self, + ) -> Pin, Error>>>>; + fn delete_application( + &self, + app_name: &str, + ) -> Pin, Error>>>>; + fn delete_applications( + &self, + ) -> Pin, Error>>>>; + fn delete_config( + &self, + ) -> Pin, Error>>>>; + fn delete_listener( + &self, + listener_name: &str, + ) -> Pin, Error>>>>; + fn delete_listener_forwarded_recursive( + &self, + listener_name: &str, + ) -> Pin, Error>>>>; + fn delete_listener_forwarded_source( + &self, + listener_name: &str, + array_index: i32, + ) -> Pin, Error>>>>; + fn delete_listener_forwarded_sources( + &self, + listener_name: &str, + ) -> Pin, Error>>>>; + fn delete_listener_forwared( + &self, + listener_name: &str, + ) -> Pin, Error>>>>; + fn delete_listener_tls( + &self, + listener_name: &str, + ) -> Pin, Error>>>>; + fn delete_listener_tls_certificate( + &self, + listener_name: &str, + array_index: i32, + ) -> Pin, Error>>>>; + fn delete_listener_tls_certificates( + &self, + listener_name: &str, + ) -> Pin, Error>>>>; + fn delete_listener_tls_conf_commands( + &self, + listener_name: &str, + ) -> Pin, Error>>>>; + fn delete_listener_tls_session( + &self, + listener_name: &str, + ) -> Pin, Error>>>>; + fn delete_listener_tls_session_ticket( + &self, + listener_name: &str, + array_index: i32, + ) -> Pin, Error>>>>; + fn delete_listener_tls_session_tickets( + &self, + listener_name: &str, + ) -> Pin, Error>>>>; + fn delete_listeners( + &self, + ) -> Pin, Error>>>>; + fn delete_routes( + &self, + ) -> Pin, Error>>>>; + fn delete_settings( + &self, + ) -> Pin, Error>>>>; + fn delete_settings_discard_unsafe_fields( + &self, + ) -> Pin, Error>>>>; + fn delete_settings_http( + &self, + ) -> Pin, Error>>>>; + fn delete_settings_http_body_read_timeout( + &self, + ) -> Pin, Error>>>>; + fn delete_settings_http_header_read_timeout( + &self, + ) -> Pin, Error>>>>; + fn delete_settings_http_idle_timeout( + &self, + ) -> Pin, Error>>>>; + fn delete_settings_http_max_body_size( + &self, + ) -> Pin, Error>>>>; + fn delete_settings_http_send_timeout( + &self, + ) -> Pin, Error>>>>; + fn delete_settings_http_static( + &self, + ) -> Pin, Error>>>>; + fn delete_settings_http_static_mime_type( + &self, + mime_type: &str, + ) -> Pin, Error>>>>; + fn delete_settings_http_static_mime_types( + &self, + ) -> Pin, Error>>>>; + fn delete_settings_log_route( + &self, + ) -> Pin, Error>>>>; + fn delete_settings_server_version( + &self, + ) -> Pin, Error>>>>; + fn get_access_log(&self) -> Pin>>>; + fn get_access_log_format(&self) -> Pin>>>; + fn get_access_log_path(&self) -> Pin>>>; + fn get_application( + &self, + app_name: &str, + ) -> Pin>>>; + fn get_applications( + &self, + ) -> Pin< + Box, Error>>>, + >; + fn get_config(&self) -> Pin>>>; + fn get_listener( + &self, + listener_name: &str, + ) -> Pin>>>; + fn get_listener_forwarded( + &self, + listener_name: &str, + ) -> Pin>>>; + fn get_listener_forwarded_client_ip( + &self, + listener_name: &str, + ) -> Pin>>>; + fn get_listener_forwarded_protocol( + &self, + listener_name: &str, + ) -> Pin>>>; + fn get_listener_forwarded_recursive( + &self, + listener_name: &str, + ) -> Pin>>>; + fn get_listener_forwarded_source( + &self, + listener_name: &str, + array_index: i32, + ) -> Pin>>>; + fn get_listener_pass(&self, listener_name: &str) -> Pin>>>; + fn get_listener_tls( + &self, + listener_name: &str, + ) -> Pin>>>; + fn get_listener_tls_certificate( + &self, + listener_name: &str, + array_index: i32, + ) -> Pin>>>; + fn get_listener_tls_session( + &self, + listener_name: &str, + ) -> Pin>>>; + fn get_listener_tls_session_ticket( + &self, + listener_name: &str, + array_index: i32, + ) -> Pin>>>; + fn get_listeners( + &self, + ) -> Pin, Error>>>>; + fn get_routes(&self) -> Pin>>>; + fn get_settings(&self) -> Pin>>>; + fn get_settings_discard_unsafe_fields(&self) -> Pin>>>; + fn get_settings_http(&self) -> Pin>>>; + fn get_settings_http_body_read_timeout(&self) -> Pin>>>; + fn get_settings_http_header_read_timeout(&self) -> Pin>>>; + fn get_settings_http_idle_timeout(&self) -> Pin>>>; + fn get_settings_http_max_body_size(&self) -> Pin>>>; + fn get_settings_http_send_timeout(&self) -> Pin>>>; + fn get_settings_http_static( + &self, + ) -> Pin>>>; + fn get_settings_http_static_mime_type( + &self, + mime_type: &str, + ) -> Pin>>>; + fn get_settings_http_static_mime_types( + &self, + ) -> Pin< + Box< + dyn Future< + Output = Result< + ::std::collections::HashMap, + Error, + >, + >, + >, + >; + fn get_settings_log_route(&self) -> Pin>>>; + fn get_settings_server_version(&self) -> Pin>>>; + fn insert_listener_forwarded_source( + &self, + listener_name: &str, + body: &str, + ) -> Pin, Error>>>>; + fn insert_listener_tls_certificate( + &self, + listener_name: &str, + body: &str, + ) -> Pin, Error>>>>; + fn insert_listener_tls_session_ticket( + &self, + listener_name: &str, + body: &str, + ) -> Pin, Error>>>>; + fn list_listener_forwarded_sources( + &self, + listener_name: &str, + ) -> Pin>>>; + fn list_listener_tls_certificates( + &self, + listener_name: &str, + ) -> Pin>>>; + fn list_listener_tls_conf_commands( + &self, + listener_name: &str, + ) -> Pin, Error>>>>; + fn list_listener_tls_session_tickets( + &self, + listener_name: &str, + ) -> Pin>>>; + fn update_access_log( + &self, + config_access_log: crate::models::ConfigAccessLog, + ) -> Pin, Error>>>>; + fn update_access_log_format( + &self, + body: &str, + ) -> Pin, Error>>>>; + fn update_access_log_path( + &self, + body: &str, + ) -> Pin, Error>>>>; + fn update_application( + &self, + app_name: &str, + config_application: crate::models::ConfigApplication, + ) -> Pin, Error>>>>; + fn update_applications( + &self, + request_body: ::std::collections::HashMap, + ) -> Pin, Error>>>>; + fn update_config( + &self, + config: crate::models::Config, + ) -> Pin, Error>>>>; + fn update_listener( + &self, + listener_name: &str, + config_listener: crate::models::ConfigListener, + ) -> Pin, Error>>>>; + fn update_listener_forwarded( + &self, + listener_name: &str, + config_listener_forwarded: crate::models::ConfigListenerForwarded, + ) -> Pin, Error>>>>; + fn update_listener_forwarded_client_ip( + &self, + listener_name: &str, + body: &str, + ) -> Pin, Error>>>>; + fn update_listener_forwarded_protocol( + &self, + listener_name: &str, + body: &str, + ) -> Pin, Error>>>>; + fn update_listener_forwarded_recursive( + &self, + listener_name: &str, + body: bool, + ) -> Pin, Error>>>>; + fn update_listener_forwarded_source( + &self, + listener_name: &str, + array_index: i32, + body: &str, + ) -> Pin, Error>>>>; + fn update_listener_forwarded_sources( + &self, + listener_name: &str, + string_or_string_array: Option, + ) -> Pin, Error>>>>; + fn update_listener_pass( + &self, + listener_name: &str, + body: &str, + ) -> Pin, Error>>>>; + fn update_listener_tls( + &self, + listener_name: &str, + config_listener_tls: crate::models::ConfigListenerTls, + ) -> Pin, Error>>>>; + fn update_listener_tls_certificate( + &self, + listener_name: &str, + array_index: i32, + body: &str, + ) -> Pin, Error>>>>; + fn update_listener_tls_certificates( + &self, + listener_name: &str, + string_or_string_array: Option, + ) -> Pin, Error>>>>; + fn update_listener_tls_conf_commands( + &self, + listener_name: &str, + request_body: ::std::collections::HashMap, + ) -> Pin, Error>>>>; + fn update_listener_tls_session( + &self, + listener_name: &str, + config_listener_tls_session: crate::models::ConfigListenerTlsSession, + ) -> Pin, Error>>>>; + fn update_listener_tls_session_ticket( + &self, + listener_name: &str, + array_index: i32, + body: &str, + ) -> Pin, Error>>>>; + fn update_listener_tls_session_tickets( + &self, + listener_name: &str, + config_listener_tls_session_tickets: Option, + ) -> Pin, Error>>>>; + fn update_listeners( + &self, + request_body: ::std::collections::HashMap, + ) -> Pin, Error>>>>; + fn update_routes( + &self, + config_routes: Option, + ) -> Pin, Error>>>>; + fn update_settings( + &self, + config_settings: crate::models::ConfigSettings, + ) -> Pin, Error>>>>; + fn update_settings_discard_unsafe_fields( + &self, + body: bool, + ) -> Pin, Error>>>>; + fn update_settings_http( + &self, + config_settings_http: crate::models::ConfigSettingsHttp, + ) -> Pin, Error>>>>; + fn update_settings_http_body_read_timeout( + &self, + body: i32, + ) -> Pin, Error>>>>; + fn update_settings_http_header_read_timeout( + &self, + body: i32, + ) -> Pin, Error>>>>; + fn update_settings_http_idle_timeout( + &self, + body: i32, + ) -> Pin, Error>>>>; + fn update_settings_http_max_body_size( + &self, + body: i32, + ) -> Pin, Error>>>>; + fn update_settings_http_send_timeout( + &self, + body: i32, + ) -> Pin, Error>>>>; + fn update_settings_http_static( + &self, + config_settings_http_static: crate::models::ConfigSettingsHttpStatic, + ) -> Pin, Error>>>>; + fn update_settings_http_static_mime_type( + &self, + mime_type: &str, + config_settings_http_static_mime_type: Option, + ) -> Pin, Error>>>>; + fn update_settings_http_static_mime_types( + &self, + request_body: ::std::collections::HashMap, + ) -> Pin, Error>>>>; + fn update_settings_log_route( + &self, + body: bool, + ) -> Pin, Error>>>>; + fn update_settings_server_version( + &self, + body: bool, + ) -> Pin, Error>>>>; +} + +impl ConfigApi for ConfigApiClient +where + C: Clone + std::marker::Send + Sync, +{ + #[allow(unused_mut)] + fn delete_access_log( + &self, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new(hyper::Method::DELETE, "/config/access_log".to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn delete_access_log_format( + &self, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new(hyper::Method::DELETE, "/config/access_log/format".to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn delete_access_log_path( + &self, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new(hyper::Method::DELETE, "/config/access_log/path".to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn delete_application( + &self, + app_name: &str, + ) -> Pin, Error>>>> { + let mut req = + __internal_request::Request::new(hyper::Method::DELETE, "/config/applications/{appName}".to_string()); + req = req.with_path_param("appName".to_string(), app_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn delete_applications( + &self, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new(hyper::Method::DELETE, "/config/applications".to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn delete_config( + &self, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new(hyper::Method::DELETE, "/config".to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn delete_listener( + &self, + listener_name: &str, + ) -> Pin, Error>>>> { + let mut req = + __internal_request::Request::new(hyper::Method::DELETE, "/config/listeners/{listenerName}".to_string()); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn delete_listener_forwarded_recursive( + &self, + listener_name: &str, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::DELETE, + "/config/listeners/{listenerName}/forwarded/recursive".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn delete_listener_forwarded_source( + &self, + listener_name: &str, + array_index: i32, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::DELETE, + "/config/listeners/{listenerName}/forwarded/source/{arrayIndex}".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + req = req.with_path_param("arrayIndex".to_string(), array_index.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn delete_listener_forwarded_sources( + &self, + listener_name: &str, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::DELETE, + "/config/listeners/{listenerName}/forwarded/source".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn delete_listener_forwared( + &self, + listener_name: &str, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::DELETE, + "/config/listeners/{listenerName}/forwarded".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn delete_listener_tls( + &self, + listener_name: &str, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::DELETE, + "/config/listeners/{listenerName}/tls".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn delete_listener_tls_certificate( + &self, + listener_name: &str, + array_index: i32, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::DELETE, + "/config/listeners/{listenerName}/tls/certificate/{arrayIndex}".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + req = req.with_path_param("arrayIndex".to_string(), array_index.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn delete_listener_tls_certificates( + &self, + listener_name: &str, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::DELETE, + "/config/listeners/{listenerName}/tls/certificate".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn delete_listener_tls_conf_commands( + &self, + listener_name: &str, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::DELETE, + "/config/listeners/{listenerName}/tls/conf_commands".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn delete_listener_tls_session( + &self, + listener_name: &str, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::DELETE, + "/config/listeners/{listenerName}/tls/session".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn delete_listener_tls_session_ticket( + &self, + listener_name: &str, + array_index: i32, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::DELETE, + "/config/listeners/{listenerName}/tls/session/tickets/{arrayIndex}".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + req = req.with_path_param("arrayIndex".to_string(), array_index.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn delete_listener_tls_session_tickets( + &self, + listener_name: &str, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::DELETE, + "/config/listeners/{listenerName}/tls/session/tickets".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn delete_listeners( + &self, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new(hyper::Method::DELETE, "/config/listeners".to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn delete_routes( + &self, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new(hyper::Method::DELETE, "/config/routes".to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn delete_settings( + &self, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new(hyper::Method::DELETE, "/config/settings".to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn delete_settings_discard_unsafe_fields( + &self, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::DELETE, + "/config/settings/http/discard_unsafe_fields".to_string(), + ); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn delete_settings_http( + &self, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new(hyper::Method::DELETE, "/config/settings/http".to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn delete_settings_http_body_read_timeout( + &self, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::DELETE, + "/config/settings/http/body_read_timeout".to_string(), + ); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn delete_settings_http_header_read_timeout( + &self, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::DELETE, + "/config/settings/http/header_read_timeout".to_string(), + ); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn delete_settings_http_idle_timeout( + &self, + ) -> Pin, Error>>>> { + let mut req = + __internal_request::Request::new(hyper::Method::DELETE, "/config/settings/http/idle_timeout".to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn delete_settings_http_max_body_size( + &self, + ) -> Pin, Error>>>> { + let mut req = + __internal_request::Request::new(hyper::Method::DELETE, "/config/settings/http/max_body_size".to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn delete_settings_http_send_timeout( + &self, + ) -> Pin, Error>>>> { + let mut req = + __internal_request::Request::new(hyper::Method::DELETE, "/config/settings/http/send_timeout".to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn delete_settings_http_static( + &self, + ) -> Pin, Error>>>> { + let mut req = + __internal_request::Request::new(hyper::Method::DELETE, "/config/settings/http/static".to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn delete_settings_http_static_mime_type( + &self, + mime_type: &str, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::DELETE, + "/config/settings/http/static/mime_types/{mimeType}".to_string(), + ); + req = req.with_path_param("mimeType".to_string(), mime_type.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn delete_settings_http_static_mime_types( + &self, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::DELETE, + "/config/settings/http/static/mime_types".to_string(), + ); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn delete_settings_log_route( + &self, + ) -> Pin, Error>>>> { + let mut req = + __internal_request::Request::new(hyper::Method::DELETE, "/config/settings/http/log_route".to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn delete_settings_server_version( + &self, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::DELETE, + "/config/settings/http/server_version".to_string(), + ); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_access_log(&self) -> Pin>>> { + let mut req = __internal_request::Request::new(hyper::Method::GET, "/config/access_log".to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_access_log_format(&self) -> Pin>>> { + let mut req = __internal_request::Request::new(hyper::Method::GET, "/config/access_log/format".to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_access_log_path(&self) -> Pin>>> { + let mut req = __internal_request::Request::new(hyper::Method::GET, "/config/access_log/path".to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_application( + &self, + app_name: &str, + ) -> Pin>>> { + let mut req = + __internal_request::Request::new(hyper::Method::GET, "/config/applications/{appName}".to_string()); + req = req.with_path_param("appName".to_string(), app_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_applications( + &self, + ) -> Pin< + Box, Error>>>, + > { + let mut req = __internal_request::Request::new(hyper::Method::GET, "/config/applications".to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_config(&self) -> Pin>>> { + let mut req = __internal_request::Request::new(hyper::Method::GET, "/config".to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_listener( + &self, + listener_name: &str, + ) -> Pin>>> { + let mut req = + __internal_request::Request::new(hyper::Method::GET, "/config/listeners/{listenerName}".to_string()); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_listener_forwarded( + &self, + listener_name: &str, + ) -> Pin>>> { + let mut req = __internal_request::Request::new( + hyper::Method::GET, + "/config/listeners/{listenerName}/forwarded".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_listener_forwarded_client_ip( + &self, + listener_name: &str, + ) -> Pin>>> { + let mut req = __internal_request::Request::new( + hyper::Method::GET, + "/config/listeners/{listenerName}/forwarded/client_ip".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_listener_forwarded_protocol( + &self, + listener_name: &str, + ) -> Pin>>> { + let mut req = __internal_request::Request::new( + hyper::Method::GET, + "/config/listeners/{listenerName}/forwarded/protocol".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_listener_forwarded_recursive( + &self, + listener_name: &str, + ) -> Pin>>> { + let mut req = __internal_request::Request::new( + hyper::Method::GET, + "/config/listeners/{listenerName}/forwarded/recursive".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_listener_forwarded_source( + &self, + listener_name: &str, + array_index: i32, + ) -> Pin>>> { + let mut req = __internal_request::Request::new( + hyper::Method::GET, + "/config/listeners/{listenerName}/forwarded/source/{arrayIndex}".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + req = req.with_path_param("arrayIndex".to_string(), array_index.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_listener_pass(&self, listener_name: &str) -> Pin>>> { + let mut req = + __internal_request::Request::new(hyper::Method::GET, "/config/listeners/{listenerName}/pass".to_string()); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_listener_tls( + &self, + listener_name: &str, + ) -> Pin>>> { + let mut req = + __internal_request::Request::new(hyper::Method::GET, "/config/listeners/{listenerName}/tls".to_string()); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_listener_tls_certificate( + &self, + listener_name: &str, + array_index: i32, + ) -> Pin>>> { + let mut req = __internal_request::Request::new( + hyper::Method::GET, + "/config/listeners/{listenerName}/tls/certificate/{arrayIndex}".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + req = req.with_path_param("arrayIndex".to_string(), array_index.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_listener_tls_session( + &self, + listener_name: &str, + ) -> Pin>>> { + let mut req = __internal_request::Request::new( + hyper::Method::GET, + "/config/listeners/{listenerName}/tls/session".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_listener_tls_session_ticket( + &self, + listener_name: &str, + array_index: i32, + ) -> Pin>>> { + let mut req = __internal_request::Request::new( + hyper::Method::GET, + "/config/listeners/{listenerName}/tls/session/tickets/{arrayIndex}".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + req = req.with_path_param("arrayIndex".to_string(), array_index.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_listeners( + &self, + ) -> Pin, Error>>>> + { + let mut req = __internal_request::Request::new(hyper::Method::GET, "/config/listeners".to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_routes(&self) -> Pin>>> { + let mut req = __internal_request::Request::new(hyper::Method::GET, "/config/routes".to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_settings(&self) -> Pin>>> { + let mut req = __internal_request::Request::new(hyper::Method::GET, "/config/settings".to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_settings_discard_unsafe_fields(&self) -> Pin>>> { + let mut req = __internal_request::Request::new( + hyper::Method::GET, + "/config/settings/http/discard_unsafe_fields".to_string(), + ); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_settings_http(&self) -> Pin>>> { + let mut req = __internal_request::Request::new(hyper::Method::GET, "/config/settings/http".to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_settings_http_body_read_timeout(&self) -> Pin>>> { + let mut req = __internal_request::Request::new( + hyper::Method::GET, + "/config/settings/http/body_read_timeout".to_string(), + ); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_settings_http_header_read_timeout(&self) -> Pin>>> { + let mut req = __internal_request::Request::new( + hyper::Method::GET, + "/config/settings/http/header_read_timeout".to_string(), + ); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_settings_http_idle_timeout(&self) -> Pin>>> { + let mut req = + __internal_request::Request::new(hyper::Method::GET, "/config/settings/http/idle_timeout".to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_settings_http_max_body_size(&self) -> Pin>>> { + let mut req = + __internal_request::Request::new(hyper::Method::GET, "/config/settings/http/max_body_size".to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_settings_http_send_timeout(&self) -> Pin>>> { + let mut req = + __internal_request::Request::new(hyper::Method::GET, "/config/settings/http/send_timeout".to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_settings_http_static( + &self, + ) -> Pin>>> { + let mut req = __internal_request::Request::new(hyper::Method::GET, "/config/settings/http/static".to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_settings_http_static_mime_type( + &self, + mime_type: &str, + ) -> Pin>>> { + let mut req = __internal_request::Request::new( + hyper::Method::GET, + "/config/settings/http/static/mime_types/{mimeType}".to_string(), + ); + req = req.with_path_param("mimeType".to_string(), mime_type.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_settings_http_static_mime_types( + &self, + ) -> Pin< + Box< + dyn Future< + Output = Result< + ::std::collections::HashMap, + Error, + >, + >, + >, + > { + let mut req = __internal_request::Request::new( + hyper::Method::GET, + "/config/settings/http/static/mime_types".to_string(), + ); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_settings_log_route(&self) -> Pin>>> { + let mut req = + __internal_request::Request::new(hyper::Method::GET, "/config/settings/http/log_route".to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_settings_server_version(&self) -> Pin>>> { + let mut req = + __internal_request::Request::new(hyper::Method::GET, "/config/settings/http/server_version".to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn insert_listener_forwarded_source( + &self, + listener_name: &str, + body: &str, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::POST, + "/config/listeners/{listenerName}/forwarded/source".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + req = req.with_body_param(body); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn insert_listener_tls_certificate( + &self, + listener_name: &str, + body: &str, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::POST, + "/config/listeners/{listenerName}/tls/certificate".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + req = req.with_body_param(body); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn insert_listener_tls_session_ticket( + &self, + listener_name: &str, + body: &str, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::POST, + "/config/listeners/{listenerName}/tls/session/tickets".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + req = req.with_body_param(body); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn list_listener_forwarded_sources( + &self, + listener_name: &str, + ) -> Pin>>> { + let mut req = __internal_request::Request::new( + hyper::Method::GET, + "/config/listeners/{listenerName}/forwarded/source".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn list_listener_tls_certificates( + &self, + listener_name: &str, + ) -> Pin>>> { + let mut req = __internal_request::Request::new( + hyper::Method::GET, + "/config/listeners/{listenerName}/tls/certificate".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn list_listener_tls_conf_commands( + &self, + listener_name: &str, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::GET, + "/config/listeners/{listenerName}/tls/conf_commands".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn list_listener_tls_session_tickets( + &self, + listener_name: &str, + ) -> Pin>>> { + let mut req = __internal_request::Request::new( + hyper::Method::GET, + "/config/listeners/{listenerName}/tls/session/tickets".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn update_access_log( + &self, + config_access_log: crate::models::ConfigAccessLog, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new(hyper::Method::PUT, "/config/access_log".to_string()); + req = req.with_body_param(config_access_log); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn update_access_log_format( + &self, + body: &str, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new(hyper::Method::PUT, "/config/access_log/format".to_string()); + req = req.with_body_param(body); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn update_access_log_path( + &self, + body: &str, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new(hyper::Method::PUT, "/config/access_log/path".to_string()); + req = req.with_body_param(body); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn update_application( + &self, + app_name: &str, + config_application: crate::models::ConfigApplication, + ) -> Pin, Error>>>> { + let mut req = + __internal_request::Request::new(hyper::Method::PUT, "/config/applications/{appName}".to_string()); + req = req.with_path_param("appName".to_string(), app_name.to_string()); + req = req.with_body_param(config_application); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn update_applications( + &self, + request_body: ::std::collections::HashMap, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new(hyper::Method::PUT, "/config/applications".to_string()); + req = req.with_body_param(request_body); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn update_config( + &self, + config: crate::models::Config, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new(hyper::Method::PUT, "/config".to_string()); + req = req.with_body_param(config); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn update_listener( + &self, + listener_name: &str, + config_listener: crate::models::ConfigListener, + ) -> Pin, Error>>>> { + let mut req = + __internal_request::Request::new(hyper::Method::PUT, "/config/listeners/{listenerName}".to_string()); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + req = req.with_body_param(config_listener); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn update_listener_forwarded( + &self, + listener_name: &str, + config_listener_forwarded: crate::models::ConfigListenerForwarded, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::PUT, + "/config/listeners/{listenerName}/forwarded".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + req = req.with_body_param(config_listener_forwarded); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn update_listener_forwarded_client_ip( + &self, + listener_name: &str, + body: &str, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::PUT, + "/config/listeners/{listenerName}/forwarded/client_ip".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + req = req.with_body_param(body); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn update_listener_forwarded_protocol( + &self, + listener_name: &str, + body: &str, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::PUT, + "/config/listeners/{listenerName}/forwarded/protocol".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + req = req.with_body_param(body); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn update_listener_forwarded_recursive( + &self, + listener_name: &str, + body: bool, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::PUT, + "/config/listeners/{listenerName}/forwarded/recursive".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + req = req.with_body_param(body); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn update_listener_forwarded_source( + &self, + listener_name: &str, + array_index: i32, + body: &str, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::PUT, + "/config/listeners/{listenerName}/forwarded/source/{arrayIndex}".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + req = req.with_path_param("arrayIndex".to_string(), array_index.to_string()); + req = req.with_body_param(body); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn update_listener_forwarded_sources( + &self, + listener_name: &str, + string_or_string_array: Option, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::PUT, + "/config/listeners/{listenerName}/forwarded/source".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + req = req.with_body_param(string_or_string_array); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn update_listener_pass( + &self, + listener_name: &str, + body: &str, + ) -> Pin, Error>>>> { + let mut req = + __internal_request::Request::new(hyper::Method::PUT, "/config/listeners/{listenerName}/pass".to_string()); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + req = req.with_body_param(body); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn update_listener_tls( + &self, + listener_name: &str, + config_listener_tls: crate::models::ConfigListenerTls, + ) -> Pin, Error>>>> { + let mut req = + __internal_request::Request::new(hyper::Method::PUT, "/config/listeners/{listenerName}/tls".to_string()); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + req = req.with_body_param(config_listener_tls); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn update_listener_tls_certificate( + &self, + listener_name: &str, + array_index: i32, + body: &str, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::PUT, + "/config/listeners/{listenerName}/tls/certificate/{arrayIndex}".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + req = req.with_path_param("arrayIndex".to_string(), array_index.to_string()); + req = req.with_body_param(body); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn update_listener_tls_certificates( + &self, + listener_name: &str, + string_or_string_array: Option, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::PUT, + "/config/listeners/{listenerName}/tls/certificate".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + req = req.with_body_param(string_or_string_array); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn update_listener_tls_conf_commands( + &self, + listener_name: &str, + request_body: ::std::collections::HashMap, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::PUT, + "/config/listeners/{listenerName}/tls/conf_commands".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + req = req.with_body_param(request_body); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn update_listener_tls_session( + &self, + listener_name: &str, + config_listener_tls_session: crate::models::ConfigListenerTlsSession, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::PUT, + "/config/listeners/{listenerName}/tls/session".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + req = req.with_body_param(config_listener_tls_session); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn update_listener_tls_session_ticket( + &self, + listener_name: &str, + array_index: i32, + body: &str, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::PUT, + "/config/listeners/{listenerName}/tls/session/tickets/{arrayIndex}".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + req = req.with_path_param("arrayIndex".to_string(), array_index.to_string()); + req = req.with_body_param(body); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn update_listener_tls_session_tickets( + &self, + listener_name: &str, + config_listener_tls_session_tickets: Option, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::PUT, + "/config/listeners/{listenerName}/tls/session/tickets".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + req = req.with_body_param(config_listener_tls_session_tickets); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn update_listeners( + &self, + request_body: ::std::collections::HashMap, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new(hyper::Method::PUT, "/config/listeners".to_string()); + req = req.with_body_param(request_body); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn update_routes( + &self, + config_routes: Option, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new(hyper::Method::PUT, "/config/routes".to_string()); + req = req.with_body_param(config_routes); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn update_settings( + &self, + config_settings: crate::models::ConfigSettings, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new(hyper::Method::PUT, "/config/settings".to_string()); + req = req.with_body_param(config_settings); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn update_settings_discard_unsafe_fields( + &self, + body: bool, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::PUT, + "/config/settings/http/discard_unsafe_fields".to_string(), + ); + req = req.with_body_param(body); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn update_settings_http( + &self, + config_settings_http: crate::models::ConfigSettingsHttp, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new(hyper::Method::PUT, "/config/settings/http".to_string()); + req = req.with_body_param(config_settings_http); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn update_settings_http_body_read_timeout( + &self, + body: i32, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::PUT, + "/config/settings/http/body_read_timeout".to_string(), + ); + req = req.with_body_param(body); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn update_settings_http_header_read_timeout( + &self, + body: i32, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::PUT, + "/config/settings/http/header_read_timeout".to_string(), + ); + req = req.with_body_param(body); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn update_settings_http_idle_timeout( + &self, + body: i32, + ) -> Pin, Error>>>> { + let mut req = + __internal_request::Request::new(hyper::Method::PUT, "/config/settings/http/idle_timeout".to_string()); + req = req.with_body_param(body); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn update_settings_http_max_body_size( + &self, + body: i32, + ) -> Pin, Error>>>> { + let mut req = + __internal_request::Request::new(hyper::Method::PUT, "/config/settings/http/max_body_size".to_string()); + req = req.with_body_param(body); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn update_settings_http_send_timeout( + &self, + body: i32, + ) -> Pin, Error>>>> { + let mut req = + __internal_request::Request::new(hyper::Method::PUT, "/config/settings/http/send_timeout".to_string()); + req = req.with_body_param(body); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn update_settings_http_static( + &self, + config_settings_http_static: crate::models::ConfigSettingsHttpStatic, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new(hyper::Method::PUT, "/config/settings/http/static".to_string()); + req = req.with_body_param(config_settings_http_static); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn update_settings_http_static_mime_type( + &self, + mime_type: &str, + config_settings_http_static_mime_type: Option, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::PUT, + "/config/settings/http/static/mime_types/{mimeType}".to_string(), + ); + req = req.with_path_param("mimeType".to_string(), mime_type.to_string()); + req = req.with_body_param(config_settings_http_static_mime_type); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn update_settings_http_static_mime_types( + &self, + request_body: ::std::collections::HashMap, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::PUT, + "/config/settings/http/static/mime_types".to_string(), + ); + req = req.with_body_param(request_body); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn update_settings_log_route( + &self, + body: bool, + ) -> Pin, Error>>>> { + let mut req = + __internal_request::Request::new(hyper::Method::PUT, "/config/settings/http/log_route".to_string()); + req = req.with_body_param(body); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn update_settings_server_version( + &self, + body: bool, + ) -> Pin, Error>>>> { + let mut req = + __internal_request::Request::new(hyper::Method::PUT, "/config/settings/http/server_version".to_string()); + req = req.with_body_param(body); + + req.execute(self.configuration.borrow()) + } +} diff --git a/cli/unit-openapi/src/apis/configuration.rs b/cli/unit-openapi/src/apis/configuration.rs new file mode 100644 index 000000000..82643fa02 --- /dev/null +++ b/cli/unit-openapi/src/apis/configuration.rs @@ -0,0 +1,47 @@ +/* + * NGINX Unit 1.31.1 + * + * NGINX Unit is a lightweight and versatile application runtime that provides the essential components for your web application as a single open-source server: running application code, serving static assets, handling TLS and request routing. **Important**: Ufnit's API is designed to expose any part of its configuration as an addressable endpoint. Suppose a JSON object is stored at `/config/listeners/`: ```json { \"*:8080\": { \"pass\": \"applications/wp_emea_dev\" } } ``` Here, `/config/listeners/_*:8080` and `/config/listeners/_*:8080/pass` are also endpoints. Generally, object options are addressable by their names, array items—by their indexes (`/array/0/`). **Note**: By default, Unit is configured through a UNIX domain socket. To use this specification with OpenAPI tools interactively, [start](https://unit.nginx.org/howto/source/#source-startup) Unit with a TCP port as the control socket. + * + * The version of the OpenAPI document: 0.2.0 + * Contact: unit-owner@nginx.org + * Generated by: https://openapi-generator.tech + */ + +use hyper; + +pub struct Configuration +where + C: Clone + std::marker::Send + Sync + 'static, +{ + pub base_path: String, + pub user_agent: Option, + pub client: hyper::client::Client, + pub basic_auth: Option, + pub oauth_access_token: Option, + pub api_key: Option, + // TODO: take an oauth2 token source, similar to the go one +} + +pub type BasicAuth = (String, Option); + +pub struct ApiKey { + pub prefix: Option, + pub key: String, +} + +impl Configuration +where + C: Clone + std::marker::Send + Sync, +{ + pub fn new(client: hyper::client::Client) -> Configuration { + Configuration { + base_path: "http://localhost:8080".to_owned(), + user_agent: Some("OpenAPI-Generator/0.2.0/rust".to_owned()), + client, + basic_auth: None, + oauth_access_token: None, + api_key: None, + } + } +} diff --git a/cli/unit-openapi/src/apis/control_api.rs b/cli/unit-openapi/src/apis/control_api.rs new file mode 100644 index 000000000..a027a6bf5 --- /dev/null +++ b/cli/unit-openapi/src/apis/control_api.rs @@ -0,0 +1,63 @@ +/* + * NGINX Unit 1.31.1 + * + * NGINX Unit is a lightweight and versatile application runtime that provides the essential components for your web application as a single open-source server: running application code, serving static assets, handling TLS and request routing. **Important**: Ufnit's API is designed to expose any part of its configuration as an addressable endpoint. Suppose a JSON object is stored at `/config/listeners/`: ```json { \"*:8080\": { \"pass\": \"applications/wp_emea_dev\" } } ``` Here, `/config/listeners/_*:8080` and `/config/listeners/_*:8080/pass` are also endpoints. Generally, object options are addressable by their names, array items—by their indexes (`/array/0/`). **Note**: By default, Unit is configured through a UNIX domain socket. To use this specification with OpenAPI tools interactively, [start](https://unit.nginx.org/howto/source/#source-startup) Unit with a TCP port as the control socket. + * + * The version of the OpenAPI document: 0.2.0 + * Contact: unit-owner@nginx.org + * Generated by: https://openapi-generator.tech + */ + +use std::borrow::Borrow; +#[allow(unused_imports)] +use std::option::Option; +use std::pin::Pin; +use std::rc::Rc; + +use futures::Future; +use hyper; + +use super::request as __internal_request; +use super::{configuration, Error}; + +pub struct ControlApiClient +where + C: Clone + std::marker::Send + Sync + 'static, +{ + configuration: Rc>, +} + +impl ControlApiClient +where + C: Clone + std::marker::Send + Sync, +{ + pub fn new(configuration: Rc>) -> ControlApiClient { + ControlApiClient { configuration } + } +} + +pub trait ControlApi { + fn get_app_restart( + &self, + app_name: &str, + ) -> Pin, Error>>>>; +} + +impl ControlApi for ControlApiClient +where + C: Clone + std::marker::Send + Sync, +{ + #[allow(unused_mut)] + fn get_app_restart( + &self, + app_name: &str, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::GET, + "/control/applications/{appName}/restart".to_string(), + ); + req = req.with_path_param("appName".to_string(), app_name.to_string()); + + req.execute(self.configuration.borrow()) + } +} diff --git a/cli/unit-openapi/src/apis/error.rs b/cli/unit-openapi/src/apis/error.rs new file mode 100644 index 000000000..a4a1e3541 --- /dev/null +++ b/cli/unit-openapi/src/apis/error.rs @@ -0,0 +1,18 @@ +use crate::apis::Error; +use std::error::Error as StdError; +use std::fmt::{Display, Formatter}; + +impl Display for Error { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + Error::Api(e) => write!(f, "ApiError: {:#?}", e), + Error::Header(e) => write!(f, "HeaderError: {}", e), + Error::Http(e) => write!(f, "HttpError: {:#?}", e), + Error::Hyper(e) => write!(f, "HyperError: {:#?}", e), + Error::Serde(e) => write!(f, "SerdeError: {:#?}", e), + Error::UriError(e) => write!(f, "UriError: {:#?}", e), + } + } +} + +impl StdError for Error {} diff --git a/cli/unit-openapi/src/apis/listeners_api.rs b/cli/unit-openapi/src/apis/listeners_api.rs new file mode 100644 index 000000000..b44c4ff80 --- /dev/null +++ b/cli/unit-openapi/src/apis/listeners_api.rs @@ -0,0 +1,956 @@ +/* + * NGINX Unit 1.31.1 + * + * NGINX Unit is a lightweight and versatile application runtime that provides the essential components for your web application as a single open-source server: running application code, serving static assets, handling TLS and request routing. **Important**: Ufnit's API is designed to expose any part of its configuration as an addressable endpoint. Suppose a JSON object is stored at `/config/listeners/`: ```json { \"*:8080\": { \"pass\": \"applications/wp_emea_dev\" } } ``` Here, `/config/listeners/_*:8080` and `/config/listeners/_*:8080/pass` are also endpoints. Generally, object options are addressable by their names, array items—by their indexes (`/array/0/`). **Note**: By default, Unit is configured through a UNIX domain socket. To use this specification with OpenAPI tools interactively, [start](https://unit.nginx.org/howto/source/#source-startup) Unit with a TCP port as the control socket. + * + * The version of the OpenAPI document: 0.2.0 + * Contact: unit-owner@nginx.org + * Generated by: https://openapi-generator.tech + */ + +use std::borrow::Borrow; +#[allow(unused_imports)] +use std::option::Option; +use std::pin::Pin; +use std::rc::Rc; + +use futures::Future; +use hyper; + +use super::request as __internal_request; +use super::{configuration, Error}; + +pub struct ListenersApiClient +where + C: Clone + std::marker::Send + Sync + 'static, +{ + configuration: Rc>, +} + +impl ListenersApiClient +where + C: Clone + std::marker::Send + Sync, +{ + pub fn new(configuration: Rc>) -> ListenersApiClient { + ListenersApiClient { configuration } + } +} + +pub trait ListenersApi { + fn delete_listener( + &self, + listener_name: &str, + ) -> Pin, Error>>>>; + fn delete_listener_forwarded_recursive( + &self, + listener_name: &str, + ) -> Pin, Error>>>>; + fn delete_listener_forwarded_source( + &self, + listener_name: &str, + array_index: i32, + ) -> Pin, Error>>>>; + fn delete_listener_forwarded_sources( + &self, + listener_name: &str, + ) -> Pin, Error>>>>; + fn delete_listener_forwared( + &self, + listener_name: &str, + ) -> Pin, Error>>>>; + fn delete_listener_tls( + &self, + listener_name: &str, + ) -> Pin, Error>>>>; + fn delete_listener_tls_certificate( + &self, + listener_name: &str, + array_index: i32, + ) -> Pin, Error>>>>; + fn delete_listener_tls_certificates( + &self, + listener_name: &str, + ) -> Pin, Error>>>>; + fn delete_listener_tls_conf_commands( + &self, + listener_name: &str, + ) -> Pin, Error>>>>; + fn delete_listener_tls_session( + &self, + listener_name: &str, + ) -> Pin, Error>>>>; + fn delete_listener_tls_session_ticket( + &self, + listener_name: &str, + array_index: i32, + ) -> Pin, Error>>>>; + fn delete_listener_tls_session_tickets( + &self, + listener_name: &str, + ) -> Pin, Error>>>>; + fn delete_listeners( + &self, + ) -> Pin, Error>>>>; + fn get_listener( + &self, + listener_name: &str, + ) -> Pin>>>; + fn get_listener_forwarded( + &self, + listener_name: &str, + ) -> Pin>>>; + fn get_listener_forwarded_client_ip( + &self, + listener_name: &str, + ) -> Pin>>>; + fn get_listener_forwarded_protocol( + &self, + listener_name: &str, + ) -> Pin>>>; + fn get_listener_forwarded_recursive( + &self, + listener_name: &str, + ) -> Pin>>>; + fn get_listener_forwarded_source( + &self, + listener_name: &str, + array_index: i32, + ) -> Pin>>>; + fn get_listener_pass(&self, listener_name: &str) -> Pin>>>; + fn get_listener_tls( + &self, + listener_name: &str, + ) -> Pin>>>; + fn get_listener_tls_certificate( + &self, + listener_name: &str, + array_index: i32, + ) -> Pin>>>; + fn get_listener_tls_session( + &self, + listener_name: &str, + ) -> Pin>>>; + fn get_listener_tls_session_ticket( + &self, + listener_name: &str, + array_index: i32, + ) -> Pin>>>; + fn get_listeners( + &self, + ) -> Pin, Error>>>>; + fn insert_listener_forwarded_source( + &self, + listener_name: &str, + body: &str, + ) -> Pin, Error>>>>; + fn insert_listener_tls_certificate( + &self, + listener_name: &str, + body: &str, + ) -> Pin, Error>>>>; + fn insert_listener_tls_session_ticket( + &self, + listener_name: &str, + body: &str, + ) -> Pin, Error>>>>; + fn list_listener_forwarded_sources( + &self, + listener_name: &str, + ) -> Pin>>>; + fn list_listener_tls_certificates( + &self, + listener_name: &str, + ) -> Pin>>>; + fn list_listener_tls_conf_commands( + &self, + listener_name: &str, + ) -> Pin, Error>>>>; + fn list_listener_tls_session_tickets( + &self, + listener_name: &str, + ) -> Pin>>>; + fn update_listener( + &self, + listener_name: &str, + config_listener: crate::models::ConfigListener, + ) -> Pin, Error>>>>; + fn update_listener_forwarded( + &self, + listener_name: &str, + config_listener_forwarded: crate::models::ConfigListenerForwarded, + ) -> Pin, Error>>>>; + fn update_listener_forwarded_client_ip( + &self, + listener_name: &str, + body: &str, + ) -> Pin, Error>>>>; + fn update_listener_forwarded_protocol( + &self, + listener_name: &str, + body: &str, + ) -> Pin, Error>>>>; + fn update_listener_forwarded_recursive( + &self, + listener_name: &str, + body: bool, + ) -> Pin, Error>>>>; + fn update_listener_forwarded_source( + &self, + listener_name: &str, + array_index: i32, + body: &str, + ) -> Pin, Error>>>>; + fn update_listener_forwarded_sources( + &self, + listener_name: &str, + string_or_string_array: Option, + ) -> Pin, Error>>>>; + fn update_listener_pass( + &self, + listener_name: &str, + body: &str, + ) -> Pin, Error>>>>; + fn update_listener_tls( + &self, + listener_name: &str, + config_listener_tls: crate::models::ConfigListenerTls, + ) -> Pin, Error>>>>; + fn update_listener_tls_certificate( + &self, + listener_name: &str, + array_index: i32, + body: &str, + ) -> Pin, Error>>>>; + fn update_listener_tls_certificates( + &self, + listener_name: &str, + string_or_string_array: Option, + ) -> Pin, Error>>>>; + fn update_listener_tls_conf_commands( + &self, + listener_name: &str, + request_body: ::std::collections::HashMap, + ) -> Pin, Error>>>>; + fn update_listener_tls_session( + &self, + listener_name: &str, + config_listener_tls_session: crate::models::ConfigListenerTlsSession, + ) -> Pin, Error>>>>; + fn update_listener_tls_session_ticket( + &self, + listener_name: &str, + array_index: i32, + body: &str, + ) -> Pin, Error>>>>; + fn update_listener_tls_session_tickets( + &self, + listener_name: &str, + config_listener_tls_session_tickets: Option, + ) -> Pin, Error>>>>; + fn update_listeners( + &self, + request_body: ::std::collections::HashMap, + ) -> Pin, Error>>>>; +} + +impl ListenersApi for ListenersApiClient +where + C: Clone + std::marker::Send + Sync, +{ + #[allow(unused_mut)] + fn delete_listener( + &self, + listener_name: &str, + ) -> Pin, Error>>>> { + let mut req = + __internal_request::Request::new(hyper::Method::DELETE, "/config/listeners/{listenerName}".to_string()); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn delete_listener_forwarded_recursive( + &self, + listener_name: &str, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::DELETE, + "/config/listeners/{listenerName}/forwarded/recursive".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn delete_listener_forwarded_source( + &self, + listener_name: &str, + array_index: i32, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::DELETE, + "/config/listeners/{listenerName}/forwarded/source/{arrayIndex}".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + req = req.with_path_param("arrayIndex".to_string(), array_index.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn delete_listener_forwarded_sources( + &self, + listener_name: &str, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::DELETE, + "/config/listeners/{listenerName}/forwarded/source".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn delete_listener_forwared( + &self, + listener_name: &str, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::DELETE, + "/config/listeners/{listenerName}/forwarded".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn delete_listener_tls( + &self, + listener_name: &str, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::DELETE, + "/config/listeners/{listenerName}/tls".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn delete_listener_tls_certificate( + &self, + listener_name: &str, + array_index: i32, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::DELETE, + "/config/listeners/{listenerName}/tls/certificate/{arrayIndex}".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + req = req.with_path_param("arrayIndex".to_string(), array_index.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn delete_listener_tls_certificates( + &self, + listener_name: &str, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::DELETE, + "/config/listeners/{listenerName}/tls/certificate".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn delete_listener_tls_conf_commands( + &self, + listener_name: &str, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::DELETE, + "/config/listeners/{listenerName}/tls/conf_commands".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn delete_listener_tls_session( + &self, + listener_name: &str, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::DELETE, + "/config/listeners/{listenerName}/tls/session".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn delete_listener_tls_session_ticket( + &self, + listener_name: &str, + array_index: i32, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::DELETE, + "/config/listeners/{listenerName}/tls/session/tickets/{arrayIndex}".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + req = req.with_path_param("arrayIndex".to_string(), array_index.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn delete_listener_tls_session_tickets( + &self, + listener_name: &str, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::DELETE, + "/config/listeners/{listenerName}/tls/session/tickets".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn delete_listeners( + &self, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new(hyper::Method::DELETE, "/config/listeners".to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_listener( + &self, + listener_name: &str, + ) -> Pin>>> { + let mut req = + __internal_request::Request::new(hyper::Method::GET, "/config/listeners/{listenerName}".to_string()); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_listener_forwarded( + &self, + listener_name: &str, + ) -> Pin>>> { + let mut req = __internal_request::Request::new( + hyper::Method::GET, + "/config/listeners/{listenerName}/forwarded".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_listener_forwarded_client_ip( + &self, + listener_name: &str, + ) -> Pin>>> { + let mut req = __internal_request::Request::new( + hyper::Method::GET, + "/config/listeners/{listenerName}/forwarded/client_ip".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_listener_forwarded_protocol( + &self, + listener_name: &str, + ) -> Pin>>> { + let mut req = __internal_request::Request::new( + hyper::Method::GET, + "/config/listeners/{listenerName}/forwarded/protocol".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_listener_forwarded_recursive( + &self, + listener_name: &str, + ) -> Pin>>> { + let mut req = __internal_request::Request::new( + hyper::Method::GET, + "/config/listeners/{listenerName}/forwarded/recursive".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_listener_forwarded_source( + &self, + listener_name: &str, + array_index: i32, + ) -> Pin>>> { + let mut req = __internal_request::Request::new( + hyper::Method::GET, + "/config/listeners/{listenerName}/forwarded/source/{arrayIndex}".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + req = req.with_path_param("arrayIndex".to_string(), array_index.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_listener_pass(&self, listener_name: &str) -> Pin>>> { + let mut req = + __internal_request::Request::new(hyper::Method::GET, "/config/listeners/{listenerName}/pass".to_string()); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_listener_tls( + &self, + listener_name: &str, + ) -> Pin>>> { + let mut req = + __internal_request::Request::new(hyper::Method::GET, "/config/listeners/{listenerName}/tls".to_string()); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_listener_tls_certificate( + &self, + listener_name: &str, + array_index: i32, + ) -> Pin>>> { + let mut req = __internal_request::Request::new( + hyper::Method::GET, + "/config/listeners/{listenerName}/tls/certificate/{arrayIndex}".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + req = req.with_path_param("arrayIndex".to_string(), array_index.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_listener_tls_session( + &self, + listener_name: &str, + ) -> Pin>>> { + let mut req = __internal_request::Request::new( + hyper::Method::GET, + "/config/listeners/{listenerName}/tls/session".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_listener_tls_session_ticket( + &self, + listener_name: &str, + array_index: i32, + ) -> Pin>>> { + let mut req = __internal_request::Request::new( + hyper::Method::GET, + "/config/listeners/{listenerName}/tls/session/tickets/{arrayIndex}".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + req = req.with_path_param("arrayIndex".to_string(), array_index.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_listeners( + &self, + ) -> Pin, Error>>>> + { + let mut req = __internal_request::Request::new(hyper::Method::GET, "/config/listeners".to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn insert_listener_forwarded_source( + &self, + listener_name: &str, + body: &str, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::POST, + "/config/listeners/{listenerName}/forwarded/source".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + req = req.with_body_param(body); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn insert_listener_tls_certificate( + &self, + listener_name: &str, + body: &str, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::POST, + "/config/listeners/{listenerName}/tls/certificate".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + req = req.with_body_param(body); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn insert_listener_tls_session_ticket( + &self, + listener_name: &str, + body: &str, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::POST, + "/config/listeners/{listenerName}/tls/session/tickets".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + req = req.with_body_param(body); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn list_listener_forwarded_sources( + &self, + listener_name: &str, + ) -> Pin>>> { + let mut req = __internal_request::Request::new( + hyper::Method::GET, + "/config/listeners/{listenerName}/forwarded/source".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn list_listener_tls_certificates( + &self, + listener_name: &str, + ) -> Pin>>> { + let mut req = __internal_request::Request::new( + hyper::Method::GET, + "/config/listeners/{listenerName}/tls/certificate".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn list_listener_tls_conf_commands( + &self, + listener_name: &str, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::GET, + "/config/listeners/{listenerName}/tls/conf_commands".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn list_listener_tls_session_tickets( + &self, + listener_name: &str, + ) -> Pin>>> { + let mut req = __internal_request::Request::new( + hyper::Method::GET, + "/config/listeners/{listenerName}/tls/session/tickets".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn update_listener( + &self, + listener_name: &str, + config_listener: crate::models::ConfigListener, + ) -> Pin, Error>>>> { + let mut req = + __internal_request::Request::new(hyper::Method::PUT, "/config/listeners/{listenerName}".to_string()); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + req = req.with_body_param(config_listener); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn update_listener_forwarded( + &self, + listener_name: &str, + config_listener_forwarded: crate::models::ConfigListenerForwarded, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::PUT, + "/config/listeners/{listenerName}/forwarded".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + req = req.with_body_param(config_listener_forwarded); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn update_listener_forwarded_client_ip( + &self, + listener_name: &str, + body: &str, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::PUT, + "/config/listeners/{listenerName}/forwarded/client_ip".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + req = req.with_body_param(body); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn update_listener_forwarded_protocol( + &self, + listener_name: &str, + body: &str, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::PUT, + "/config/listeners/{listenerName}/forwarded/protocol".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + req = req.with_body_param(body); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn update_listener_forwarded_recursive( + &self, + listener_name: &str, + body: bool, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::PUT, + "/config/listeners/{listenerName}/forwarded/recursive".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + req = req.with_body_param(body); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn update_listener_forwarded_source( + &self, + listener_name: &str, + array_index: i32, + body: &str, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::PUT, + "/config/listeners/{listenerName}/forwarded/source/{arrayIndex}".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + req = req.with_path_param("arrayIndex".to_string(), array_index.to_string()); + req = req.with_body_param(body); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn update_listener_forwarded_sources( + &self, + listener_name: &str, + string_or_string_array: Option, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::PUT, + "/config/listeners/{listenerName}/forwarded/source".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + req = req.with_body_param(string_or_string_array); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn update_listener_pass( + &self, + listener_name: &str, + body: &str, + ) -> Pin, Error>>>> { + let mut req = + __internal_request::Request::new(hyper::Method::PUT, "/config/listeners/{listenerName}/pass".to_string()); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + req = req.with_body_param(body); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn update_listener_tls( + &self, + listener_name: &str, + config_listener_tls: crate::models::ConfigListenerTls, + ) -> Pin, Error>>>> { + let mut req = + __internal_request::Request::new(hyper::Method::PUT, "/config/listeners/{listenerName}/tls".to_string()); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + req = req.with_body_param(config_listener_tls); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn update_listener_tls_certificate( + &self, + listener_name: &str, + array_index: i32, + body: &str, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::PUT, + "/config/listeners/{listenerName}/tls/certificate/{arrayIndex}".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + req = req.with_path_param("arrayIndex".to_string(), array_index.to_string()); + req = req.with_body_param(body); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn update_listener_tls_certificates( + &self, + listener_name: &str, + string_or_string_array: Option, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::PUT, + "/config/listeners/{listenerName}/tls/certificate".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + req = req.with_body_param(string_or_string_array); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn update_listener_tls_conf_commands( + &self, + listener_name: &str, + request_body: ::std::collections::HashMap, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::PUT, + "/config/listeners/{listenerName}/tls/conf_commands".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + req = req.with_body_param(request_body); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn update_listener_tls_session( + &self, + listener_name: &str, + config_listener_tls_session: crate::models::ConfigListenerTlsSession, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::PUT, + "/config/listeners/{listenerName}/tls/session".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + req = req.with_body_param(config_listener_tls_session); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn update_listener_tls_session_ticket( + &self, + listener_name: &str, + array_index: i32, + body: &str, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::PUT, + "/config/listeners/{listenerName}/tls/session/tickets/{arrayIndex}".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + req = req.with_path_param("arrayIndex".to_string(), array_index.to_string()); + req = req.with_body_param(body); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn update_listener_tls_session_tickets( + &self, + listener_name: &str, + config_listener_tls_session_tickets: Option, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::PUT, + "/config/listeners/{listenerName}/tls/session/tickets".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + req = req.with_body_param(config_listener_tls_session_tickets); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn update_listeners( + &self, + request_body: ::std::collections::HashMap, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new(hyper::Method::PUT, "/config/listeners".to_string()); + req = req.with_body_param(request_body); + + req.execute(self.configuration.borrow()) + } +} diff --git a/cli/unit-openapi/src/apis/mod.rs b/cli/unit-openapi/src/apis/mod.rs new file mode 100644 index 000000000..530e992fa --- /dev/null +++ b/cli/unit-openapi/src/apis/mod.rs @@ -0,0 +1,74 @@ +use http; +use hyper; +use serde_json; + +#[derive(Debug)] +pub enum Error { + Api(ApiError), + Header(hyper::http::header::InvalidHeaderValue), + Http(http::Error), + Hyper(hyper::Error), + Serde(serde_json::Error), + UriError(http::uri::InvalidUri), +} + +#[derive(Debug)] +pub struct ApiError { + pub code: hyper::StatusCode, + pub body: hyper::body::Body, +} + +impl From<(hyper::StatusCode, hyper::body::Body)> for Error { + fn from(e: (hyper::StatusCode, hyper::body::Body)) -> Self { + Error::Api(ApiError { code: e.0, body: e.1 }) + } +} + +impl From for Error { + fn from(e: http::Error) -> Self { + return Error::Http(e); + } +} + +impl From for Error { + fn from(e: hyper::Error) -> Self { + return Error::Hyper(e); + } +} + +impl From for Error { + fn from(e: serde_json::Error) -> Self { + return Error::Serde(e); + } +} + +mod request; + +mod access_log_api; +pub use self::access_log_api::{AccessLogApi, AccessLogApiClient}; +mod applications_api; +pub use self::applications_api::{ApplicationsApi, ApplicationsApiClient}; +mod apps_api; +pub use self::apps_api::{AppsApi, AppsApiClient}; +mod certificates_api; +pub use self::certificates_api::{CertificatesApi, CertificatesApiClient}; +mod config_api; +pub use self::config_api::{ConfigApi, ConfigApiClient}; +mod control_api; +pub use self::control_api::{ControlApi, ControlApiClient}; +mod listeners_api; +pub use self::listeners_api::{ListenersApi, ListenersApiClient}; +mod routes_api; +pub use self::routes_api::{RoutesApi, RoutesApiClient}; +mod settings_api; +pub use self::settings_api::{SettingsApi, SettingsApiClient}; +mod status_api; +pub use self::status_api::{StatusApi, StatusApiClient}; +mod tls_api; +pub use self::tls_api::{TlsApi, TlsApiClient}; +mod xff_api; +pub use self::xff_api::{XffApi, XffApiClient}; + +pub mod client; +pub mod configuration; +mod error; diff --git a/cli/unit-openapi/src/apis/request.rs b/cli/unit-openapi/src/apis/request.rs new file mode 100644 index 000000000..139d3258e --- /dev/null +++ b/cli/unit-openapi/src/apis/request.rs @@ -0,0 +1,255 @@ +use std::collections::HashMap; +use std::pin::Pin; + +use base64::engine::general_purpose::NO_PAD; +use base64::engine::GeneralPurpose; +use base64::{alphabet, Engine}; + +use futures; +use futures::future::*; +use futures::Future; +use hyper; +use hyper::header::{HeaderValue, AUTHORIZATION, CONTENT_LENGTH, CONTENT_TYPE, USER_AGENT}; +use serde; +use serde_json; + +use super::{configuration, Error}; + +const MIME_ENCODER: GeneralPurpose = GeneralPurpose::new(&alphabet::STANDARD, NO_PAD); + +pub(crate) struct ApiKey { + pub in_header: bool, + pub in_query: bool, + pub param_name: String, +} + +impl ApiKey { + fn key(&self, prefix: &Option, key: &str) -> String { + match prefix { + None => key.to_owned(), + Some(ref prefix) => format!("{} {}", prefix, key), + } + } +} + +#[allow(dead_code)] +pub(crate) enum Auth { + None, + ApiKey(ApiKey), + Basic, + Oauth, +} + +/// If the authorization type is unspecified then it will be automatically detected based +/// on the configuration. This functionality is useful when the OpenAPI definition does not +/// include an authorization scheme. +pub(crate) struct Request { + auth: Option, + method: hyper::Method, + path: String, + query_params: HashMap, + no_return_type: bool, + path_params: HashMap, + form_params: HashMap, + header_params: HashMap, + // TODO: multiple body params are possible technically, but not supported here. + serialized_body: Option, +} + +#[allow(dead_code)] +impl Request { + pub fn new(method: hyper::Method, path: String) -> Self { + Request { + auth: None, + method, + path, + query_params: HashMap::new(), + path_params: HashMap::new(), + form_params: HashMap::new(), + header_params: HashMap::new(), + serialized_body: None, + no_return_type: false, + } + } + + pub fn with_body_param(mut self, param: T) -> Self { + self.serialized_body = Some(serde_json::to_string(¶m).unwrap()); + self + } + + pub fn with_header_param(mut self, basename: String, param: String) -> Self { + self.header_params.insert(basename, param); + self + } + + #[allow(unused)] + pub fn with_query_param(mut self, basename: String, param: String) -> Self { + self.query_params.insert(basename, param); + self + } + + #[allow(unused)] + pub fn with_path_param(mut self, basename: String, param: String) -> Self { + self.path_params.insert(basename, param); + self + } + + #[allow(unused)] + pub fn with_form_param(mut self, basename: String, param: String) -> Self { + self.form_params.insert(basename, param); + self + } + + pub fn returns_nothing(mut self) -> Self { + self.no_return_type = true; + self + } + + pub fn with_auth(mut self, auth: Auth) -> Self { + self.auth = Some(auth); + self + } + + pub fn execute<'a, C, U>( + self, + conf: &configuration::Configuration, + ) -> Pin> + 'a>> + where + C: hyper::client::connect::Connect + Clone + std::marker::Send + Sync, + U: Sized + std::marker::Send + 'a, + for<'de> U: serde::Deserialize<'de>, + { + let mut query_string = ::url::form_urlencoded::Serializer::new("".to_owned()); + + let mut path = self.path; + for (k, v) in self.path_params { + // replace {id} with the value of the id path param + path = path.replace(&format!("{{{}}}", k), &v); + } + + for (key, val) in self.query_params { + query_string.append_pair(&key, &val); + } + + let mut uri_str = format!("{}{}", conf.base_path, path); + + let query_string_str = query_string.finish(); + if query_string_str != "" { + uri_str += "?"; + uri_str += &query_string_str; + } + let uri: hyper::Uri = match uri_str.parse() { + Err(e) => return Box::pin(futures::future::err(Error::UriError(e))), + Ok(u) => u, + }; + + let mut req_builder = hyper::Request::builder().uri(uri).method(self.method); + + // Detect the authorization type if it hasn't been set. + let auth = self.auth.unwrap_or_else(|| + if conf.api_key.is_some() { + panic!("Cannot automatically set the API key from the configuration, it must be specified in the OpenAPI definition") + } else if conf.oauth_access_token.is_some() { + Auth::Oauth + } else if conf.basic_auth.is_some() { + Auth::Basic + } else { + Auth::None + } + ); + match auth { + Auth::ApiKey(apikey) => { + if let Some(ref key) = conf.api_key { + let val = apikey.key(&key.prefix, &key.key); + if apikey.in_query { + query_string.append_pair(&apikey.param_name, &val); + } + if apikey.in_header { + req_builder = req_builder.header(&apikey.param_name, val); + } + } + } + Auth::Basic => { + if let Some(ref auth_conf) = conf.basic_auth { + let mut text = auth_conf.0.clone(); + text.push(':'); + if let Some(ref pass) = auth_conf.1 { + text.push_str(&pass[..]); + } + let encoded = MIME_ENCODER.encode(&text); + req_builder = req_builder.header(AUTHORIZATION, encoded); + } + } + Auth::Oauth => { + if let Some(ref token) = conf.oauth_access_token { + let text = "Bearer ".to_owned() + token; + req_builder = req_builder.header(AUTHORIZATION, text); + } + } + Auth::None => {} + } + + if let Some(ref user_agent) = conf.user_agent { + req_builder = req_builder.header( + USER_AGENT, + match HeaderValue::from_str(user_agent) { + Ok(header_value) => header_value, + Err(e) => return Box::pin(futures::future::err(super::Error::Header(e))), + }, + ); + } + + for (k, v) in self.header_params { + req_builder = req_builder.header(&k, v); + } + + let req_headers = req_builder.headers_mut().unwrap(); + let request_result = if self.form_params.len() > 0 { + req_headers.insert( + CONTENT_TYPE, + HeaderValue::from_static("application/x-www-form-urlencoded"), + ); + let mut enc = ::url::form_urlencoded::Serializer::new("".to_owned()); + for (k, v) in self.form_params { + enc.append_pair(&k, &v); + } + req_builder.body(hyper::Body::from(enc.finish())) + } else if let Some(body) = self.serialized_body { + req_headers.insert(CONTENT_TYPE, HeaderValue::from_static("application/json")); + req_headers.insert(CONTENT_LENGTH, body.len().into()); + req_builder.body(hyper::Body::from(body)) + } else { + req_builder.body(hyper::Body::default()) + }; + let request = match request_result { + Ok(request) => request, + Err(e) => return Box::pin(futures::future::err(Error::from(e))), + }; + + let no_return_type = self.no_return_type; + Box::pin( + conf.client + .request(request) + .map_err(|e| Error::from(e)) + .and_then(move |response| { + let status = response.status(); + if !status.is_success() { + futures::future::err::(Error::from((status, response.into_body()))).boxed() + } else if no_return_type { + // This is a hack; if there's no_ret_type, U is (), but serde_json gives an + // error when deserializing "" into (), so deserialize 'null' into it + // instead. + // An alternate option would be to require U: Default, and then return + // U::default() here instead since () implements that, but then we'd + // need to impl default for all models. + futures::future::ok::(serde_json::from_str("null").expect("serde null value")).boxed() + } else { + hyper::body::to_bytes(response.into_body()) + .map(|bytes| serde_json::from_slice(&bytes.unwrap())) + .map_err(|e| Error::from(e)) + .boxed() + } + }), + ) + } +} diff --git a/cli/unit-openapi/src/apis/routes_api.rs b/cli/unit-openapi/src/apis/routes_api.rs new file mode 100644 index 000000000..4c36d6006 --- /dev/null +++ b/cli/unit-openapi/src/apis/routes_api.rs @@ -0,0 +1,80 @@ +/* + * NGINX Unit 1.31.1 + * + * NGINX Unit is a lightweight and versatile application runtime that provides the essential components for your web application as a single open-source server: running application code, serving static assets, handling TLS and request routing. **Important**: Ufnit's API is designed to expose any part of its configuration as an addressable endpoint. Suppose a JSON object is stored at `/config/listeners/`: ```json { \"*:8080\": { \"pass\": \"applications/wp_emea_dev\" } } ``` Here, `/config/listeners/_*:8080` and `/config/listeners/_*:8080/pass` are also endpoints. Generally, object options are addressable by their names, array items—by their indexes (`/array/0/`). **Note**: By default, Unit is configured through a UNIX domain socket. To use this specification with OpenAPI tools interactively, [start](https://unit.nginx.org/howto/source/#source-startup) Unit with a TCP port as the control socket. + * + * The version of the OpenAPI document: 0.2.0 + * Contact: unit-owner@nginx.org + * Generated by: https://openapi-generator.tech + */ + +use std::borrow::Borrow; +#[allow(unused_imports)] +use std::option::Option; +use std::pin::Pin; +use std::rc::Rc; + +use futures::Future; +use hyper; + +use super::request as __internal_request; +use super::{configuration, Error}; + +pub struct RoutesApiClient +where + C: Clone + std::marker::Send + Sync + 'static, +{ + configuration: Rc>, +} + +impl RoutesApiClient +where + C: Clone + std::marker::Send + Sync, +{ + pub fn new(configuration: Rc>) -> RoutesApiClient { + RoutesApiClient { configuration } + } +} + +pub trait RoutesApi { + fn delete_routes( + &self, + ) -> Pin, Error>>>>; + fn get_routes(&self) -> Pin>>>; + fn update_routes( + &self, + config_routes: Option, + ) -> Pin, Error>>>>; +} + +impl RoutesApi for RoutesApiClient +where + C: Clone + std::marker::Send + Sync, +{ + #[allow(unused_mut)] + fn delete_routes( + &self, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new(hyper::Method::DELETE, "/config/routes".to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_routes(&self) -> Pin>>> { + let mut req = __internal_request::Request::new(hyper::Method::GET, "/config/routes".to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn update_routes( + &self, + config_routes: Option, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new(hyper::Method::PUT, "/config/routes".to_string()); + req = req.with_body_param(config_routes); + + req.execute(self.configuration.borrow()) + } +} diff --git a/cli/unit-openapi/src/apis/settings_api.rs b/cli/unit-openapi/src/apis/settings_api.rs new file mode 100644 index 000000000..b729ea01f --- /dev/null +++ b/cli/unit-openapi/src/apis/settings_api.rs @@ -0,0 +1,602 @@ +/* + * NGINX Unit 1.31.1 + * + * NGINX Unit is a lightweight and versatile application runtime that provides the essential components for your web application as a single open-source server: running application code, serving static assets, handling TLS and request routing. **Important**: Ufnit's API is designed to expose any part of its configuration as an addressable endpoint. Suppose a JSON object is stored at `/config/listeners/`: ```json { \"*:8080\": { \"pass\": \"applications/wp_emea_dev\" } } ``` Here, `/config/listeners/_*:8080` and `/config/listeners/_*:8080/pass` are also endpoints. Generally, object options are addressable by their names, array items—by their indexes (`/array/0/`). **Note**: By default, Unit is configured through a UNIX domain socket. To use this specification with OpenAPI tools interactively, [start](https://unit.nginx.org/howto/source/#source-startup) Unit with a TCP port as the control socket. + * + * The version of the OpenAPI document: 0.2.0 + * Contact: unit-owner@nginx.org + * Generated by: https://openapi-generator.tech + */ + +use std::borrow::Borrow; +#[allow(unused_imports)] +use std::option::Option; +use std::pin::Pin; +use std::rc::Rc; + +use futures::Future; +use hyper; + +use super::request as __internal_request; +use super::{configuration, Error}; + +pub struct SettingsApiClient +where + C: Clone + std::marker::Send + Sync + 'static, +{ + configuration: Rc>, +} + +impl SettingsApiClient +where + C: Clone + std::marker::Send + Sync, +{ + pub fn new(configuration: Rc>) -> SettingsApiClient { + SettingsApiClient { configuration } + } +} + +pub trait SettingsApi { + fn delete_settings( + &self, + ) -> Pin, Error>>>>; + fn delete_settings_discard_unsafe_fields( + &self, + ) -> Pin, Error>>>>; + fn delete_settings_http( + &self, + ) -> Pin, Error>>>>; + fn delete_settings_http_body_read_timeout( + &self, + ) -> Pin, Error>>>>; + fn delete_settings_http_header_read_timeout( + &self, + ) -> Pin, Error>>>>; + fn delete_settings_http_idle_timeout( + &self, + ) -> Pin, Error>>>>; + fn delete_settings_http_max_body_size( + &self, + ) -> Pin, Error>>>>; + fn delete_settings_http_send_timeout( + &self, + ) -> Pin, Error>>>>; + fn delete_settings_http_static( + &self, + ) -> Pin, Error>>>>; + fn delete_settings_http_static_mime_type( + &self, + mime_type: &str, + ) -> Pin, Error>>>>; + fn delete_settings_http_static_mime_types( + &self, + ) -> Pin, Error>>>>; + fn delete_settings_log_route( + &self, + ) -> Pin, Error>>>>; + fn delete_settings_server_version( + &self, + ) -> Pin, Error>>>>; + fn get_settings(&self) -> Pin>>>; + fn get_settings_discard_unsafe_fields(&self) -> Pin>>>; + fn get_settings_http(&self) -> Pin>>>; + fn get_settings_http_body_read_timeout(&self) -> Pin>>>; + fn get_settings_http_header_read_timeout(&self) -> Pin>>>; + fn get_settings_http_idle_timeout(&self) -> Pin>>>; + fn get_settings_http_max_body_size(&self) -> Pin>>>; + fn get_settings_http_send_timeout(&self) -> Pin>>>; + fn get_settings_http_static( + &self, + ) -> Pin>>>; + fn get_settings_http_static_mime_type( + &self, + mime_type: &str, + ) -> Pin>>>; + fn get_settings_http_static_mime_types( + &self, + ) -> Pin< + Box< + dyn Future< + Output = Result< + ::std::collections::HashMap, + Error, + >, + >, + >, + >; + fn get_settings_log_route(&self) -> Pin>>>; + fn get_settings_server_version(&self) -> Pin>>>; + fn update_settings( + &self, + config_settings: crate::models::ConfigSettings, + ) -> Pin, Error>>>>; + fn update_settings_discard_unsafe_fields( + &self, + body: bool, + ) -> Pin, Error>>>>; + fn update_settings_http( + &self, + config_settings_http: crate::models::ConfigSettingsHttp, + ) -> Pin, Error>>>>; + fn update_settings_http_body_read_timeout( + &self, + body: i32, + ) -> Pin, Error>>>>; + fn update_settings_http_header_read_timeout( + &self, + body: i32, + ) -> Pin, Error>>>>; + fn update_settings_http_idle_timeout( + &self, + body: i32, + ) -> Pin, Error>>>>; + fn update_settings_http_max_body_size( + &self, + body: i32, + ) -> Pin, Error>>>>; + fn update_settings_http_send_timeout( + &self, + body: i32, + ) -> Pin, Error>>>>; + fn update_settings_http_static( + &self, + config_settings_http_static: crate::models::ConfigSettingsHttpStatic, + ) -> Pin, Error>>>>; + fn update_settings_http_static_mime_type( + &self, + mime_type: &str, + config_settings_http_static_mime_type: Option, + ) -> Pin, Error>>>>; + fn update_settings_http_static_mime_types( + &self, + request_body: ::std::collections::HashMap, + ) -> Pin, Error>>>>; + fn update_settings_log_route( + &self, + body: bool, + ) -> Pin, Error>>>>; + fn update_settings_server_version( + &self, + body: bool, + ) -> Pin, Error>>>>; +} + +impl SettingsApi for SettingsApiClient +where + C: Clone + std::marker::Send + Sync, +{ + #[allow(unused_mut)] + fn delete_settings( + &self, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new(hyper::Method::DELETE, "/config/settings".to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn delete_settings_discard_unsafe_fields( + &self, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::DELETE, + "/config/settings/http/discard_unsafe_fields".to_string(), + ); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn delete_settings_http( + &self, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new(hyper::Method::DELETE, "/config/settings/http".to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn delete_settings_http_body_read_timeout( + &self, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::DELETE, + "/config/settings/http/body_read_timeout".to_string(), + ); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn delete_settings_http_header_read_timeout( + &self, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::DELETE, + "/config/settings/http/header_read_timeout".to_string(), + ); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn delete_settings_http_idle_timeout( + &self, + ) -> Pin, Error>>>> { + let mut req = + __internal_request::Request::new(hyper::Method::DELETE, "/config/settings/http/idle_timeout".to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn delete_settings_http_max_body_size( + &self, + ) -> Pin, Error>>>> { + let mut req = + __internal_request::Request::new(hyper::Method::DELETE, "/config/settings/http/max_body_size".to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn delete_settings_http_send_timeout( + &self, + ) -> Pin, Error>>>> { + let mut req = + __internal_request::Request::new(hyper::Method::DELETE, "/config/settings/http/send_timeout".to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn delete_settings_http_static( + &self, + ) -> Pin, Error>>>> { + let mut req = + __internal_request::Request::new(hyper::Method::DELETE, "/config/settings/http/static".to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn delete_settings_http_static_mime_type( + &self, + mime_type: &str, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::DELETE, + "/config/settings/http/static/mime_types/{mimeType}".to_string(), + ); + req = req.with_path_param("mimeType".to_string(), mime_type.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn delete_settings_http_static_mime_types( + &self, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::DELETE, + "/config/settings/http/static/mime_types".to_string(), + ); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn delete_settings_log_route( + &self, + ) -> Pin, Error>>>> { + let mut req = + __internal_request::Request::new(hyper::Method::DELETE, "/config/settings/http/log_route".to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn delete_settings_server_version( + &self, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::DELETE, + "/config/settings/http/server_version".to_string(), + ); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_settings(&self) -> Pin>>> { + let mut req = __internal_request::Request::new(hyper::Method::GET, "/config/settings".to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_settings_discard_unsafe_fields(&self) -> Pin>>> { + let mut req = __internal_request::Request::new( + hyper::Method::GET, + "/config/settings/http/discard_unsafe_fields".to_string(), + ); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_settings_http(&self) -> Pin>>> { + let mut req = __internal_request::Request::new(hyper::Method::GET, "/config/settings/http".to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_settings_http_body_read_timeout(&self) -> Pin>>> { + let mut req = __internal_request::Request::new( + hyper::Method::GET, + "/config/settings/http/body_read_timeout".to_string(), + ); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_settings_http_header_read_timeout(&self) -> Pin>>> { + let mut req = __internal_request::Request::new( + hyper::Method::GET, + "/config/settings/http/header_read_timeout".to_string(), + ); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_settings_http_idle_timeout(&self) -> Pin>>> { + let mut req = + __internal_request::Request::new(hyper::Method::GET, "/config/settings/http/idle_timeout".to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_settings_http_max_body_size(&self) -> Pin>>> { + let mut req = + __internal_request::Request::new(hyper::Method::GET, "/config/settings/http/max_body_size".to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_settings_http_send_timeout(&self) -> Pin>>> { + let mut req = + __internal_request::Request::new(hyper::Method::GET, "/config/settings/http/send_timeout".to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_settings_http_static( + &self, + ) -> Pin>>> { + let mut req = __internal_request::Request::new(hyper::Method::GET, "/config/settings/http/static".to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_settings_http_static_mime_type( + &self, + mime_type: &str, + ) -> Pin>>> { + let mut req = __internal_request::Request::new( + hyper::Method::GET, + "/config/settings/http/static/mime_types/{mimeType}".to_string(), + ); + req = req.with_path_param("mimeType".to_string(), mime_type.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_settings_http_static_mime_types( + &self, + ) -> Pin< + Box< + dyn Future< + Output = Result< + ::std::collections::HashMap, + Error, + >, + >, + >, + > { + let mut req = __internal_request::Request::new( + hyper::Method::GET, + "/config/settings/http/static/mime_types".to_string(), + ); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_settings_log_route(&self) -> Pin>>> { + let mut req = + __internal_request::Request::new(hyper::Method::GET, "/config/settings/http/log_route".to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_settings_server_version(&self) -> Pin>>> { + let mut req = + __internal_request::Request::new(hyper::Method::GET, "/config/settings/http/server_version".to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn update_settings( + &self, + config_settings: crate::models::ConfigSettings, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new(hyper::Method::PUT, "/config/settings".to_string()); + req = req.with_body_param(config_settings); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn update_settings_discard_unsafe_fields( + &self, + body: bool, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::PUT, + "/config/settings/http/discard_unsafe_fields".to_string(), + ); + req = req.with_body_param(body); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn update_settings_http( + &self, + config_settings_http: crate::models::ConfigSettingsHttp, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new(hyper::Method::PUT, "/config/settings/http".to_string()); + req = req.with_body_param(config_settings_http); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn update_settings_http_body_read_timeout( + &self, + body: i32, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::PUT, + "/config/settings/http/body_read_timeout".to_string(), + ); + req = req.with_body_param(body); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn update_settings_http_header_read_timeout( + &self, + body: i32, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::PUT, + "/config/settings/http/header_read_timeout".to_string(), + ); + req = req.with_body_param(body); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn update_settings_http_idle_timeout( + &self, + body: i32, + ) -> Pin, Error>>>> { + let mut req = + __internal_request::Request::new(hyper::Method::PUT, "/config/settings/http/idle_timeout".to_string()); + req = req.with_body_param(body); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn update_settings_http_max_body_size( + &self, + body: i32, + ) -> Pin, Error>>>> { + let mut req = + __internal_request::Request::new(hyper::Method::PUT, "/config/settings/http/max_body_size".to_string()); + req = req.with_body_param(body); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn update_settings_http_send_timeout( + &self, + body: i32, + ) -> Pin, Error>>>> { + let mut req = + __internal_request::Request::new(hyper::Method::PUT, "/config/settings/http/send_timeout".to_string()); + req = req.with_body_param(body); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn update_settings_http_static( + &self, + config_settings_http_static: crate::models::ConfigSettingsHttpStatic, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new(hyper::Method::PUT, "/config/settings/http/static".to_string()); + req = req.with_body_param(config_settings_http_static); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn update_settings_http_static_mime_type( + &self, + mime_type: &str, + config_settings_http_static_mime_type: Option, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::PUT, + "/config/settings/http/static/mime_types/{mimeType}".to_string(), + ); + req = req.with_path_param("mimeType".to_string(), mime_type.to_string()); + req = req.with_body_param(config_settings_http_static_mime_type); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn update_settings_http_static_mime_types( + &self, + request_body: ::std::collections::HashMap, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::PUT, + "/config/settings/http/static/mime_types".to_string(), + ); + req = req.with_body_param(request_body); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn update_settings_log_route( + &self, + body: bool, + ) -> Pin, Error>>>> { + let mut req = + __internal_request::Request::new(hyper::Method::PUT, "/config/settings/http/log_route".to_string()); + req = req.with_body_param(body); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn update_settings_server_version( + &self, + body: bool, + ) -> Pin, Error>>>> { + let mut req = + __internal_request::Request::new(hyper::Method::PUT, "/config/settings/http/server_version".to_string()); + req = req.with_body_param(body); + + req.execute(self.configuration.borrow()) + } +} diff --git a/cli/unit-openapi/src/apis/status_api.rs b/cli/unit-openapi/src/apis/status_api.rs new file mode 100644 index 000000000..9cb61d4d5 --- /dev/null +++ b/cli/unit-openapi/src/apis/status_api.rs @@ -0,0 +1,257 @@ +/* + * NGINX Unit 1.31.1 + * + * NGINX Unit is a lightweight and versatile application runtime that provides the essential components for your web application as a single open-source server: running application code, serving static assets, handling TLS and request routing. **Important**: Ufnit's API is designed to expose any part of its configuration as an addressable endpoint. Suppose a JSON object is stored at `/config/listeners/`: ```json { \"*:8080\": { \"pass\": \"applications/wp_emea_dev\" } } ``` Here, `/config/listeners/_*:8080` and `/config/listeners/_*:8080/pass` are also endpoints. Generally, object options are addressable by their names, array items—by their indexes (`/array/0/`). **Note**: By default, Unit is configured through a UNIX domain socket. To use this specification with OpenAPI tools interactively, [start](https://unit.nginx.org/howto/source/#source-startup) Unit with a TCP port as the control socket. + * + * The version of the OpenAPI document: 0.2.0 + * Contact: unit-owner@nginx.org + * Generated by: https://openapi-generator.tech + */ + +use std::borrow::Borrow; +#[allow(unused_imports)] +use std::option::Option; +use std::pin::Pin; +use std::rc::Rc; + +use futures::Future; +use hyper; + +use super::request as __internal_request; +use super::{configuration, Error}; + +pub struct StatusApiClient +where + C: Clone + std::marker::Send + Sync + 'static, +{ + configuration: Rc>, +} + +impl StatusApiClient +where + C: Clone + std::marker::Send + Sync, +{ + pub fn new(configuration: Rc>) -> StatusApiClient { + StatusApiClient { configuration } + } +} + +pub trait StatusApi { + fn get_status(&self) -> Pin>>>; + fn get_status_applications( + &self, + ) -> Pin< + Box< + dyn Future< + Output = Result<::std::collections::HashMap, Error>, + >, + >, + >; + fn get_status_applications_app( + &self, + app_name: &str, + ) -> Pin>>>; + fn get_status_applications_app_processes( + &self, + app_name: &str, + ) -> Pin>>>; + fn get_status_applications_app_processes_idle( + &self, + app_name: &str, + ) -> Pin>>>; + fn get_status_applications_app_processes_running( + &self, + app_name: &str, + ) -> Pin>>>; + fn get_status_applications_app_processes_starting( + &self, + app_name: &str, + ) -> Pin>>>; + fn get_status_applications_app_requests( + &self, + app_name: &str, + ) -> Pin>>>; + fn get_status_applications_app_requests_active( + &self, + app_name: &str, + ) -> Pin>>>; + fn get_status_connections(&self) -> Pin>>>; + fn get_status_connections_accepted(&self) -> Pin>>>; + fn get_status_connections_active(&self) -> Pin>>>; + fn get_status_connections_closed(&self) -> Pin>>>; + fn get_status_connections_idle(&self) -> Pin>>>; + fn get_status_requests(&self) -> Pin>>>; + fn get_status_requests_total(&self) -> Pin>>>; +} + +impl StatusApi for StatusApiClient +where + C: Clone + std::marker::Send + Sync, +{ + #[allow(unused_mut)] + fn get_status(&self) -> Pin>>> { + let mut req = __internal_request::Request::new(hyper::Method::GET, "/status".to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_status_applications( + &self, + ) -> Pin< + Box< + dyn Future< + Output = Result<::std::collections::HashMap, Error>, + >, + >, + > { + let mut req = __internal_request::Request::new(hyper::Method::GET, "/status/applications".to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_status_applications_app( + &self, + app_name: &str, + ) -> Pin>>> { + let mut req = + __internal_request::Request::new(hyper::Method::GET, "/status/applications/{appName}".to_string()); + req = req.with_path_param("appName".to_string(), app_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_status_applications_app_processes( + &self, + app_name: &str, + ) -> Pin>>> { + let mut req = __internal_request::Request::new( + hyper::Method::GET, + "/status/applications/{appName}/processes".to_string(), + ); + req = req.with_path_param("appName".to_string(), app_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_status_applications_app_processes_idle( + &self, + app_name: &str, + ) -> Pin>>> { + let mut req = __internal_request::Request::new( + hyper::Method::GET, + "/status/applications/{appName}/processes/idle".to_string(), + ); + req = req.with_path_param("appName".to_string(), app_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_status_applications_app_processes_running( + &self, + app_name: &str, + ) -> Pin>>> { + let mut req = __internal_request::Request::new( + hyper::Method::GET, + "/status/applications/{appName}/processes/running".to_string(), + ); + req = req.with_path_param("appName".to_string(), app_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_status_applications_app_processes_starting( + &self, + app_name: &str, + ) -> Pin>>> { + let mut req = __internal_request::Request::new( + hyper::Method::GET, + "/status/applications/{appName}/processes/starting".to_string(), + ); + req = req.with_path_param("appName".to_string(), app_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_status_applications_app_requests( + &self, + app_name: &str, + ) -> Pin>>> { + let mut req = __internal_request::Request::new( + hyper::Method::GET, + "/status/applications/{appName}/requests".to_string(), + ); + req = req.with_path_param("appName".to_string(), app_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_status_applications_app_requests_active( + &self, + app_name: &str, + ) -> Pin>>> { + let mut req = __internal_request::Request::new( + hyper::Method::GET, + "/status/applications/{appName}/requests/active".to_string(), + ); + req = req.with_path_param("appName".to_string(), app_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_status_connections(&self) -> Pin>>> { + let mut req = __internal_request::Request::new(hyper::Method::GET, "/status/connections".to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_status_connections_accepted(&self) -> Pin>>> { + let mut req = __internal_request::Request::new(hyper::Method::GET, "/status/connections/accepted".to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_status_connections_active(&self) -> Pin>>> { + let mut req = __internal_request::Request::new(hyper::Method::GET, "/status/connections/active".to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_status_connections_closed(&self) -> Pin>>> { + let mut req = __internal_request::Request::new(hyper::Method::GET, "/status/connections/closed".to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_status_connections_idle(&self) -> Pin>>> { + let mut req = __internal_request::Request::new(hyper::Method::GET, "/status/connections/idle".to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_status_requests(&self) -> Pin>>> { + let mut req = __internal_request::Request::new(hyper::Method::GET, "/status/requests".to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_status_requests_total(&self) -> Pin>>> { + let mut req = __internal_request::Request::new(hyper::Method::GET, "/status/requests/total".to_string()); + + req.execute(self.configuration.borrow()) + } +} diff --git a/cli/unit-openapi/src/apis/tls_api.rs b/cli/unit-openapi/src/apis/tls_api.rs new file mode 100644 index 000000000..2bba6365f --- /dev/null +++ b/cli/unit-openapi/src/apis/tls_api.rs @@ -0,0 +1,500 @@ +/* + * NGINX Unit 1.31.1 + * + * NGINX Unit is a lightweight and versatile application runtime that provides the essential components for your web application as a single open-source server: running application code, serving static assets, handling TLS and request routing. **Important**: Ufnit's API is designed to expose any part of its configuration as an addressable endpoint. Suppose a JSON object is stored at `/config/listeners/`: ```json { \"*:8080\": { \"pass\": \"applications/wp_emea_dev\" } } ``` Here, `/config/listeners/_*:8080` and `/config/listeners/_*:8080/pass` are also endpoints. Generally, object options are addressable by their names, array items—by their indexes (`/array/0/`). **Note**: By default, Unit is configured through a UNIX domain socket. To use this specification with OpenAPI tools interactively, [start](https://unit.nginx.org/howto/source/#source-startup) Unit with a TCP port as the control socket. + * + * The version of the OpenAPI document: 0.2.0 + * Contact: unit-owner@nginx.org + * Generated by: https://openapi-generator.tech + */ + +use std::borrow::Borrow; +#[allow(unused_imports)] +use std::option::Option; +use std::pin::Pin; +use std::rc::Rc; + +use futures::Future; +use hyper; + +use super::request as __internal_request; +use super::{configuration, Error}; + +pub struct TlsApiClient +where + C: Clone + std::marker::Send + Sync + 'static, +{ + configuration: Rc>, +} + +impl TlsApiClient +where + C: Clone + std::marker::Send + Sync, +{ + pub fn new(configuration: Rc>) -> TlsApiClient { + TlsApiClient { configuration } + } +} + +pub trait TlsApi { + fn delete_listener_tls( + &self, + listener_name: &str, + ) -> Pin, Error>>>>; + fn delete_listener_tls_certificate( + &self, + listener_name: &str, + array_index: i32, + ) -> Pin, Error>>>>; + fn delete_listener_tls_certificates( + &self, + listener_name: &str, + ) -> Pin, Error>>>>; + fn delete_listener_tls_conf_commands( + &self, + listener_name: &str, + ) -> Pin, Error>>>>; + fn delete_listener_tls_session( + &self, + listener_name: &str, + ) -> Pin, Error>>>>; + fn delete_listener_tls_session_ticket( + &self, + listener_name: &str, + array_index: i32, + ) -> Pin, Error>>>>; + fn delete_listener_tls_session_tickets( + &self, + listener_name: &str, + ) -> Pin, Error>>>>; + fn get_listener_tls( + &self, + listener_name: &str, + ) -> Pin>>>; + fn get_listener_tls_certificate( + &self, + listener_name: &str, + array_index: i32, + ) -> Pin>>>; + fn get_listener_tls_session( + &self, + listener_name: &str, + ) -> Pin>>>; + fn get_listener_tls_session_ticket( + &self, + listener_name: &str, + array_index: i32, + ) -> Pin>>>; + fn insert_listener_tls_certificate( + &self, + listener_name: &str, + body: &str, + ) -> Pin, Error>>>>; + fn insert_listener_tls_session_ticket( + &self, + listener_name: &str, + body: &str, + ) -> Pin, Error>>>>; + fn list_listener_tls_certificates( + &self, + listener_name: &str, + ) -> Pin>>>; + fn list_listener_tls_conf_commands( + &self, + listener_name: &str, + ) -> Pin, Error>>>>; + fn list_listener_tls_session_tickets( + &self, + listener_name: &str, + ) -> Pin>>>; + fn update_listener_tls( + &self, + listener_name: &str, + config_listener_tls: crate::models::ConfigListenerTls, + ) -> Pin, Error>>>>; + fn update_listener_tls_certificate( + &self, + listener_name: &str, + array_index: i32, + body: &str, + ) -> Pin, Error>>>>; + fn update_listener_tls_certificates( + &self, + listener_name: &str, + string_or_string_array: Option, + ) -> Pin, Error>>>>; + fn update_listener_tls_conf_commands( + &self, + listener_name: &str, + request_body: ::std::collections::HashMap, + ) -> Pin, Error>>>>; + fn update_listener_tls_session( + &self, + listener_name: &str, + config_listener_tls_session: crate::models::ConfigListenerTlsSession, + ) -> Pin, Error>>>>; + fn update_listener_tls_session_ticket( + &self, + listener_name: &str, + array_index: i32, + body: &str, + ) -> Pin, Error>>>>; + fn update_listener_tls_session_tickets( + &self, + listener_name: &str, + config_listener_tls_session_tickets: Option, + ) -> Pin, Error>>>>; +} + +impl TlsApi for TlsApiClient +where + C: Clone + std::marker::Send + Sync, +{ + #[allow(unused_mut)] + fn delete_listener_tls( + &self, + listener_name: &str, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::DELETE, + "/config/listeners/{listenerName}/tls".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn delete_listener_tls_certificate( + &self, + listener_name: &str, + array_index: i32, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::DELETE, + "/config/listeners/{listenerName}/tls/certificate/{arrayIndex}".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + req = req.with_path_param("arrayIndex".to_string(), array_index.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn delete_listener_tls_certificates( + &self, + listener_name: &str, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::DELETE, + "/config/listeners/{listenerName}/tls/certificate".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn delete_listener_tls_conf_commands( + &self, + listener_name: &str, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::DELETE, + "/config/listeners/{listenerName}/tls/conf_commands".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn delete_listener_tls_session( + &self, + listener_name: &str, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::DELETE, + "/config/listeners/{listenerName}/tls/session".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn delete_listener_tls_session_ticket( + &self, + listener_name: &str, + array_index: i32, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::DELETE, + "/config/listeners/{listenerName}/tls/session/tickets/{arrayIndex}".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + req = req.with_path_param("arrayIndex".to_string(), array_index.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn delete_listener_tls_session_tickets( + &self, + listener_name: &str, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::DELETE, + "/config/listeners/{listenerName}/tls/session/tickets".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_listener_tls( + &self, + listener_name: &str, + ) -> Pin>>> { + let mut req = + __internal_request::Request::new(hyper::Method::GET, "/config/listeners/{listenerName}/tls".to_string()); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_listener_tls_certificate( + &self, + listener_name: &str, + array_index: i32, + ) -> Pin>>> { + let mut req = __internal_request::Request::new( + hyper::Method::GET, + "/config/listeners/{listenerName}/tls/certificate/{arrayIndex}".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + req = req.with_path_param("arrayIndex".to_string(), array_index.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_listener_tls_session( + &self, + listener_name: &str, + ) -> Pin>>> { + let mut req = __internal_request::Request::new( + hyper::Method::GET, + "/config/listeners/{listenerName}/tls/session".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_listener_tls_session_ticket( + &self, + listener_name: &str, + array_index: i32, + ) -> Pin>>> { + let mut req = __internal_request::Request::new( + hyper::Method::GET, + "/config/listeners/{listenerName}/tls/session/tickets/{arrayIndex}".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + req = req.with_path_param("arrayIndex".to_string(), array_index.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn insert_listener_tls_certificate( + &self, + listener_name: &str, + body: &str, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::POST, + "/config/listeners/{listenerName}/tls/certificate".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + req = req.with_body_param(body); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn insert_listener_tls_session_ticket( + &self, + listener_name: &str, + body: &str, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::POST, + "/config/listeners/{listenerName}/tls/session/tickets".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + req = req.with_body_param(body); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn list_listener_tls_certificates( + &self, + listener_name: &str, + ) -> Pin>>> { + let mut req = __internal_request::Request::new( + hyper::Method::GET, + "/config/listeners/{listenerName}/tls/certificate".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn list_listener_tls_conf_commands( + &self, + listener_name: &str, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::GET, + "/config/listeners/{listenerName}/tls/conf_commands".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn list_listener_tls_session_tickets( + &self, + listener_name: &str, + ) -> Pin>>> { + let mut req = __internal_request::Request::new( + hyper::Method::GET, + "/config/listeners/{listenerName}/tls/session/tickets".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn update_listener_tls( + &self, + listener_name: &str, + config_listener_tls: crate::models::ConfigListenerTls, + ) -> Pin, Error>>>> { + let mut req = + __internal_request::Request::new(hyper::Method::PUT, "/config/listeners/{listenerName}/tls".to_string()); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + req = req.with_body_param(config_listener_tls); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn update_listener_tls_certificate( + &self, + listener_name: &str, + array_index: i32, + body: &str, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::PUT, + "/config/listeners/{listenerName}/tls/certificate/{arrayIndex}".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + req = req.with_path_param("arrayIndex".to_string(), array_index.to_string()); + req = req.with_body_param(body); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn update_listener_tls_certificates( + &self, + listener_name: &str, + string_or_string_array: Option, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::PUT, + "/config/listeners/{listenerName}/tls/certificate".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + req = req.with_body_param(string_or_string_array); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn update_listener_tls_conf_commands( + &self, + listener_name: &str, + request_body: ::std::collections::HashMap, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::PUT, + "/config/listeners/{listenerName}/tls/conf_commands".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + req = req.with_body_param(request_body); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn update_listener_tls_session( + &self, + listener_name: &str, + config_listener_tls_session: crate::models::ConfigListenerTlsSession, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::PUT, + "/config/listeners/{listenerName}/tls/session".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + req = req.with_body_param(config_listener_tls_session); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn update_listener_tls_session_ticket( + &self, + listener_name: &str, + array_index: i32, + body: &str, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::PUT, + "/config/listeners/{listenerName}/tls/session/tickets/{arrayIndex}".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + req = req.with_path_param("arrayIndex".to_string(), array_index.to_string()); + req = req.with_body_param(body); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn update_listener_tls_session_tickets( + &self, + listener_name: &str, + config_listener_tls_session_tickets: Option, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::PUT, + "/config/listeners/{listenerName}/tls/session/tickets".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + req = req.with_body_param(config_listener_tls_session_tickets); + + req.execute(self.configuration.borrow()) + } +} diff --git a/cli/unit-openapi/src/apis/xff_api.rs b/cli/unit-openapi/src/apis/xff_api.rs new file mode 100644 index 000000000..7951aca59 --- /dev/null +++ b/cli/unit-openapi/src/apis/xff_api.rs @@ -0,0 +1,381 @@ +/* + * NGINX Unit 1.31.1 + * + * NGINX Unit is a lightweight and versatile application runtime that provides the essential components for your web application as a single open-source server: running application code, serving static assets, handling TLS and request routing. **Important**: Ufnit's API is designed to expose any part of its configuration as an addressable endpoint. Suppose a JSON object is stored at `/config/listeners/`: ```json { \"*:8080\": { \"pass\": \"applications/wp_emea_dev\" } } ``` Here, `/config/listeners/_*:8080` and `/config/listeners/_*:8080/pass` are also endpoints. Generally, object options are addressable by their names, array items—by their indexes (`/array/0/`). **Note**: By default, Unit is configured through a UNIX domain socket. To use this specification with OpenAPI tools interactively, [start](https://unit.nginx.org/howto/source/#source-startup) Unit with a TCP port as the control socket. + * + * The version of the OpenAPI document: 0.2.0 + * Contact: unit-owner@nginx.org + * Generated by: https://openapi-generator.tech + */ + +use std::borrow::Borrow; +#[allow(unused_imports)] +use std::option::Option; +use std::pin::Pin; +use std::rc::Rc; + +use futures::Future; +use hyper; + +use super::request as __internal_request; +use super::{configuration, Error}; + +pub struct XffApiClient +where + C: Clone + std::marker::Send + Sync + 'static, +{ + configuration: Rc>, +} + +impl XffApiClient +where + C: Clone + std::marker::Send + Sync, +{ + pub fn new(configuration: Rc>) -> XffApiClient { + XffApiClient { configuration } + } +} + +pub trait XffApi { + fn delete_listener_forwarded_recursive( + &self, + listener_name: &str, + ) -> Pin, Error>>>>; + fn delete_listener_forwarded_source( + &self, + listener_name: &str, + array_index: i32, + ) -> Pin, Error>>>>; + fn delete_listener_forwarded_sources( + &self, + listener_name: &str, + ) -> Pin, Error>>>>; + fn delete_listener_forwared( + &self, + listener_name: &str, + ) -> Pin, Error>>>>; + fn get_listener_forwarded( + &self, + listener_name: &str, + ) -> Pin>>>; + fn get_listener_forwarded_client_ip( + &self, + listener_name: &str, + ) -> Pin>>>; + fn get_listener_forwarded_protocol( + &self, + listener_name: &str, + ) -> Pin>>>; + fn get_listener_forwarded_recursive( + &self, + listener_name: &str, + ) -> Pin>>>; + fn get_listener_forwarded_source( + &self, + listener_name: &str, + array_index: i32, + ) -> Pin>>>; + fn insert_listener_forwarded_source( + &self, + listener_name: &str, + body: &str, + ) -> Pin, Error>>>>; + fn list_listener_forwarded_sources( + &self, + listener_name: &str, + ) -> Pin>>>; + fn update_listener_forwarded( + &self, + listener_name: &str, + config_listener_forwarded: crate::models::ConfigListenerForwarded, + ) -> Pin, Error>>>>; + fn update_listener_forwarded_client_ip( + &self, + listener_name: &str, + body: &str, + ) -> Pin, Error>>>>; + fn update_listener_forwarded_protocol( + &self, + listener_name: &str, + body: &str, + ) -> Pin, Error>>>>; + fn update_listener_forwarded_recursive( + &self, + listener_name: &str, + body: bool, + ) -> Pin, Error>>>>; + fn update_listener_forwarded_source( + &self, + listener_name: &str, + array_index: i32, + body: &str, + ) -> Pin, Error>>>>; + fn update_listener_forwarded_sources( + &self, + listener_name: &str, + string_or_string_array: Option, + ) -> Pin, Error>>>>; +} + +impl XffApi for XffApiClient +where + C: Clone + std::marker::Send + Sync, +{ + #[allow(unused_mut)] + fn delete_listener_forwarded_recursive( + &self, + listener_name: &str, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::DELETE, + "/config/listeners/{listenerName}/forwarded/recursive".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn delete_listener_forwarded_source( + &self, + listener_name: &str, + array_index: i32, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::DELETE, + "/config/listeners/{listenerName}/forwarded/source/{arrayIndex}".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + req = req.with_path_param("arrayIndex".to_string(), array_index.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn delete_listener_forwarded_sources( + &self, + listener_name: &str, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::DELETE, + "/config/listeners/{listenerName}/forwarded/source".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn delete_listener_forwared( + &self, + listener_name: &str, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::DELETE, + "/config/listeners/{listenerName}/forwarded".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_listener_forwarded( + &self, + listener_name: &str, + ) -> Pin>>> { + let mut req = __internal_request::Request::new( + hyper::Method::GET, + "/config/listeners/{listenerName}/forwarded".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_listener_forwarded_client_ip( + &self, + listener_name: &str, + ) -> Pin>>> { + let mut req = __internal_request::Request::new( + hyper::Method::GET, + "/config/listeners/{listenerName}/forwarded/client_ip".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_listener_forwarded_protocol( + &self, + listener_name: &str, + ) -> Pin>>> { + let mut req = __internal_request::Request::new( + hyper::Method::GET, + "/config/listeners/{listenerName}/forwarded/protocol".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_listener_forwarded_recursive( + &self, + listener_name: &str, + ) -> Pin>>> { + let mut req = __internal_request::Request::new( + hyper::Method::GET, + "/config/listeners/{listenerName}/forwarded/recursive".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn get_listener_forwarded_source( + &self, + listener_name: &str, + array_index: i32, + ) -> Pin>>> { + let mut req = __internal_request::Request::new( + hyper::Method::GET, + "/config/listeners/{listenerName}/forwarded/source/{arrayIndex}".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + req = req.with_path_param("arrayIndex".to_string(), array_index.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn insert_listener_forwarded_source( + &self, + listener_name: &str, + body: &str, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::POST, + "/config/listeners/{listenerName}/forwarded/source".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + req = req.with_body_param(body); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn list_listener_forwarded_sources( + &self, + listener_name: &str, + ) -> Pin>>> { + let mut req = __internal_request::Request::new( + hyper::Method::GET, + "/config/listeners/{listenerName}/forwarded/source".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn update_listener_forwarded( + &self, + listener_name: &str, + config_listener_forwarded: crate::models::ConfigListenerForwarded, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::PUT, + "/config/listeners/{listenerName}/forwarded".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + req = req.with_body_param(config_listener_forwarded); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn update_listener_forwarded_client_ip( + &self, + listener_name: &str, + body: &str, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::PUT, + "/config/listeners/{listenerName}/forwarded/client_ip".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + req = req.with_body_param(body); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn update_listener_forwarded_protocol( + &self, + listener_name: &str, + body: &str, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::PUT, + "/config/listeners/{listenerName}/forwarded/protocol".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + req = req.with_body_param(body); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn update_listener_forwarded_recursive( + &self, + listener_name: &str, + body: bool, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::PUT, + "/config/listeners/{listenerName}/forwarded/recursive".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + req = req.with_body_param(body); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn update_listener_forwarded_source( + &self, + listener_name: &str, + array_index: i32, + body: &str, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::PUT, + "/config/listeners/{listenerName}/forwarded/source/{arrayIndex}".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + req = req.with_path_param("arrayIndex".to_string(), array_index.to_string()); + req = req.with_body_param(body); + + req.execute(self.configuration.borrow()) + } + + #[allow(unused_mut)] + fn update_listener_forwarded_sources( + &self, + listener_name: &str, + string_or_string_array: Option, + ) -> Pin, Error>>>> { + let mut req = __internal_request::Request::new( + hyper::Method::PUT, + "/config/listeners/{listenerName}/forwarded/source".to_string(), + ); + req = req.with_path_param("listenerName".to_string(), listener_name.to_string()); + req = req.with_body_param(string_or_string_array); + + req.execute(self.configuration.borrow()) + } +} diff --git a/cli/unit-openapi/src/lib.rs b/cli/unit-openapi/src/lib.rs new file mode 100644 index 000000000..a71f18d6e --- /dev/null +++ b/cli/unit-openapi/src/lib.rs @@ -0,0 +1,12 @@ +#![allow(clippy::all)] +#[macro_use] +extern crate serde_derive; + +extern crate futures; +extern crate hyper; +extern crate serde; +extern crate serde_json; +extern crate url; + +pub mod apis; +pub mod models; diff --git a/cli/unit-openapi/src/models/cert_bundle.rs b/cli/unit-openapi/src/models/cert_bundle.rs new file mode 100644 index 000000000..d1255a6ec --- /dev/null +++ b/cli/unit-openapi/src/models/cert_bundle.rs @@ -0,0 +1,28 @@ +/* + * NGINX Unit 1.31.1 + * + * NGINX Unit is a lightweight and versatile application runtime that provides the essential components for your web application as a single open-source server: running application code, serving static assets, handling TLS and request routing. **Important**: Ufnit's API is designed to expose any part of its configuration as an addressable endpoint. Suppose a JSON object is stored at `/config/listeners/`: ```json { \"*:8080\": { \"pass\": \"applications/wp_emea_dev\" } } ``` Here, `/config/listeners/_*:8080` and `/config/listeners/_*:8080/pass` are also endpoints. Generally, object options are addressable by their names, array items—by their indexes (`/array/0/`). **Note**: By default, Unit is configured through a UNIX domain socket. To use this specification with OpenAPI tools interactively, [start](https://unit.nginx.org/howto/source/#source-startup) Unit with a TCP port as the control socket. + * + * The version of the OpenAPI document: 0.2.0 + * Contact: unit-owner@nginx.org + * Generated by: https://openapi-generator.tech + */ + +/// CertBundle : An object whose options represent a certificate bundle. + +#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] +pub struct CertBundle { + /// Certificate bundle's key type, i. e. RSA, ECDSA, etc. + #[serde(rename = "key", skip_serializing_if = "Option::is_none")] + pub key: Option, + /// An array whose items represent certificates in a bundle. + #[serde(rename = "chain", skip_serializing_if = "Option::is_none")] + pub chain: Option>, +} + +impl CertBundle { + /// An object whose options represent a certificate bundle. + pub fn new() -> CertBundle { + CertBundle { key: None, chain: None } + } +} diff --git a/cli/unit-openapi/src/models/cert_bundle_chain_cert.rs b/cli/unit-openapi/src/models/cert_bundle_chain_cert.rs new file mode 100644 index 000000000..a0f5f5a95 --- /dev/null +++ b/cli/unit-openapi/src/models/cert_bundle_chain_cert.rs @@ -0,0 +1,32 @@ +/* + * NGINX Unit 1.31.1 + * + * NGINX Unit is a lightweight and versatile application runtime that provides the essential components for your web application as a single open-source server: running application code, serving static assets, handling TLS and request routing. **Important**: Ufnit's API is designed to expose any part of its configuration as an addressable endpoint. Suppose a JSON object is stored at `/config/listeners/`: ```json { \"*:8080\": { \"pass\": \"applications/wp_emea_dev\" } } ``` Here, `/config/listeners/_*:8080` and `/config/listeners/_*:8080/pass` are also endpoints. Generally, object options are addressable by their names, array items—by their indexes (`/array/0/`). **Note**: By default, Unit is configured through a UNIX domain socket. To use this specification with OpenAPI tools interactively, [start](https://unit.nginx.org/howto/source/#source-startup) Unit with a TCP port as the control socket. + * + * The version of the OpenAPI document: 0.2.0 + * Contact: unit-owner@nginx.org + * Generated by: https://openapi-generator.tech + */ + +/// CertBundleChainCert : An object that represents an individual certificate. + +#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] +pub struct CertBundleChainCert { + #[serde(rename = "subject", skip_serializing_if = "Option::is_none")] + pub subject: Option>, + #[serde(rename = "issuer", skip_serializing_if = "Option::is_none")] + pub issuer: Option>, + #[serde(rename = "validity", skip_serializing_if = "Option::is_none")] + pub validity: Option>, +} + +impl CertBundleChainCert { + /// An object that represents an individual certificate. + pub fn new() -> CertBundleChainCert { + CertBundleChainCert { + subject: None, + issuer: None, + validity: None, + } + } +} diff --git a/cli/unit-openapi/src/models/cert_bundle_chain_cert_issuer.rs b/cli/unit-openapi/src/models/cert_bundle_chain_cert_issuer.rs new file mode 100644 index 000000000..b86ca7810 --- /dev/null +++ b/cli/unit-openapi/src/models/cert_bundle_chain_cert_issuer.rs @@ -0,0 +1,35 @@ +/* + * NGINX Unit 1.31.1 + * + * NGINX Unit is a lightweight and versatile application runtime that provides the essential components for your web application as a single open-source server: running application code, serving static assets, handling TLS and request routing. **Important**: Ufnit's API is designed to expose any part of its configuration as an addressable endpoint. Suppose a JSON object is stored at `/config/listeners/`: ```json { \"*:8080\": { \"pass\": \"applications/wp_emea_dev\" } } ``` Here, `/config/listeners/_*:8080` and `/config/listeners/_*:8080/pass` are also endpoints. Generally, object options are addressable by their names, array items—by their indexes (`/array/0/`). **Note**: By default, Unit is configured through a UNIX domain socket. To use this specification with OpenAPI tools interactively, [start](https://unit.nginx.org/howto/source/#source-startup) Unit with a TCP port as the control socket. + * + * The version of the OpenAPI document: 0.2.0 + * Contact: unit-owner@nginx.org + * Generated by: https://openapi-generator.tech + */ + +/// CertBundleChainCertIssuer : An object that represents a certificate's issuer. + +#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] +pub struct CertBundleChainCertIssuer { + #[serde(rename = "common_name", skip_serializing_if = "Option::is_none")] + pub common_name: Option, + #[serde(rename = "country", skip_serializing_if = "Option::is_none")] + pub country: Option, + #[serde(rename = "state_or_province", skip_serializing_if = "Option::is_none")] + pub state_or_province: Option, + #[serde(rename = "organization", skip_serializing_if = "Option::is_none")] + pub organization: Option, +} + +impl CertBundleChainCertIssuer { + /// An object that represents a certificate's issuer. + pub fn new() -> CertBundleChainCertIssuer { + CertBundleChainCertIssuer { + common_name: None, + country: None, + state_or_province: None, + organization: None, + } + } +} diff --git a/cli/unit-openapi/src/models/cert_bundle_chain_cert_subj.rs b/cli/unit-openapi/src/models/cert_bundle_chain_cert_subj.rs new file mode 100644 index 000000000..4d2518db2 --- /dev/null +++ b/cli/unit-openapi/src/models/cert_bundle_chain_cert_subj.rs @@ -0,0 +1,39 @@ +/* + * NGINX Unit 1.31.1 + * + * NGINX Unit is a lightweight and versatile application runtime that provides the essential components for your web application as a single open-source server: running application code, serving static assets, handling TLS and request routing. **Important**: Ufnit's API is designed to expose any part of its configuration as an addressable endpoint. Suppose a JSON object is stored at `/config/listeners/`: ```json { \"*:8080\": { \"pass\": \"applications/wp_emea_dev\" } } ``` Here, `/config/listeners/_*:8080` and `/config/listeners/_*:8080/pass` are also endpoints. Generally, object options are addressable by their names, array items—by their indexes (`/array/0/`). **Note**: By default, Unit is configured through a UNIX domain socket. To use this specification with OpenAPI tools interactively, [start](https://unit.nginx.org/howto/source/#source-startup) Unit with a TCP port as the control socket. + * + * The version of the OpenAPI document: 0.2.0 + * Contact: unit-owner@nginx.org + * Generated by: https://openapi-generator.tech + */ + +/// CertBundleChainCertSubj : An object that represents a certificate's subject. + +#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] +pub struct CertBundleChainCertSubj { + #[serde(rename = "common_name", skip_serializing_if = "Option::is_none")] + pub common_name: Option, + #[serde(rename = "country", skip_serializing_if = "Option::is_none")] + pub country: Option, + #[serde(rename = "state_or_province", skip_serializing_if = "Option::is_none")] + pub state_or_province: Option, + #[serde(rename = "organization", skip_serializing_if = "Option::is_none")] + pub organization: Option, + /// An array of strings. + #[serde(rename = "alt_names", skip_serializing_if = "Option::is_none")] + pub alt_names: Option>, +} + +impl CertBundleChainCertSubj { + /// An object that represents a certificate's subject. + pub fn new() -> CertBundleChainCertSubj { + CertBundleChainCertSubj { + common_name: None, + country: None, + state_or_province: None, + organization: None, + alt_names: None, + } + } +} diff --git a/cli/unit-openapi/src/models/cert_bundle_chain_cert_validity.rs b/cli/unit-openapi/src/models/cert_bundle_chain_cert_validity.rs new file mode 100644 index 000000000..4992c2641 --- /dev/null +++ b/cli/unit-openapi/src/models/cert_bundle_chain_cert_validity.rs @@ -0,0 +1,29 @@ +/* + * NGINX Unit 1.31.1 + * + * NGINX Unit is a lightweight and versatile application runtime that provides the essential components for your web application as a single open-source server: running application code, serving static assets, handling TLS and request routing. **Important**: Ufnit's API is designed to expose any part of its configuration as an addressable endpoint. Suppose a JSON object is stored at `/config/listeners/`: ```json { \"*:8080\": { \"pass\": \"applications/wp_emea_dev\" } } ``` Here, `/config/listeners/_*:8080` and `/config/listeners/_*:8080/pass` are also endpoints. Generally, object options are addressable by their names, array items—by their indexes (`/array/0/`). **Note**: By default, Unit is configured through a UNIX domain socket. To use this specification with OpenAPI tools interactively, [start](https://unit.nginx.org/howto/source/#source-startup) Unit with a TCP port as the control socket. + * + * The version of the OpenAPI document: 0.2.0 + * Contact: unit-owner@nginx.org + * Generated by: https://openapi-generator.tech + */ + +/// CertBundleChainCertValidity : An object that represents the validity of a certificate. + +#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] +pub struct CertBundleChainCertValidity { + #[serde(rename = "since", skip_serializing_if = "Option::is_none")] + pub since: Option, + #[serde(rename = "until", skip_serializing_if = "Option::is_none")] + pub until: Option, +} + +impl CertBundleChainCertValidity { + /// An object that represents the validity of a certificate. + pub fn new() -> CertBundleChainCertValidity { + CertBundleChainCertValidity { + since: None, + until: None, + } + } +} diff --git a/cli/unit-openapi/src/models/config.rs b/cli/unit-openapi/src/models/config.rs new file mode 100644 index 000000000..2cd081545 --- /dev/null +++ b/cli/unit-openapi/src/models/config.rs @@ -0,0 +1,40 @@ +/* + * NGINX Unit 1.31.1 + * + * NGINX Unit is a lightweight and versatile application runtime that provides the essential components for your web application as a single open-source server: running application code, serving static assets, handling TLS and request routing. **Important**: Ufnit's API is designed to expose any part of its configuration as an addressable endpoint. Suppose a JSON object is stored at `/config/listeners/`: ```json { \"*:8080\": { \"pass\": \"applications/wp_emea_dev\" } } ``` Here, `/config/listeners/_*:8080` and `/config/listeners/_*:8080/pass` are also endpoints. Generally, object options are addressable by their names, array items—by their indexes (`/array/0/`). **Note**: By default, Unit is configured through a UNIX domain socket. To use this specification with OpenAPI tools interactively, [start](https://unit.nginx.org/howto/source/#source-startup) Unit with a TCP port as the control socket. + * + * The version of the OpenAPI document: 0.2.0 + * Contact: unit-owner@nginx.org + * Generated by: https://openapi-generator.tech + */ + +/// Config : The entire /config section of the API. + +#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] +pub struct Config { + #[serde(rename = "access_log", skip_serializing_if = "Option::is_none")] + pub access_log: Option>, + /// An object whose options define individual applications. + #[serde(rename = "applications", skip_serializing_if = "Option::is_none")] + pub applications: Option<::std::collections::HashMap>, + #[serde(rename = "routes", skip_serializing_if = "Option::is_none")] + pub routes: Option>, + /// An object whose options are listeners. + #[serde(rename = "listeners", skip_serializing_if = "Option::is_none")] + pub listeners: Option<::std::collections::HashMap>, + #[serde(rename = "settings", skip_serializing_if = "Option::is_none")] + pub settings: Option>, +} + +impl Config { + /// The entire /config section of the API. + pub fn new() -> Config { + Config { + access_log: None, + applications: None, + routes: None, + listeners: None, + settings: None, + } + } +} diff --git a/cli/unit-openapi/src/models/config_access_log.rs b/cli/unit-openapi/src/models/config_access_log.rs new file mode 100644 index 000000000..fec596fd3 --- /dev/null +++ b/cli/unit-openapi/src/models/config_access_log.rs @@ -0,0 +1,31 @@ +/* + * NGINX Unit 1.31.1 + * + * NGINX Unit is a lightweight and versatile application runtime that provides the essential components for your web application as a single open-source server: running application code, serving static assets, handling TLS and request routing. **Important**: Ufnit's API is designed to expose any part of its configuration as an addressable endpoint. Suppose a JSON object is stored at `/config/listeners/`: ```json { \"*:8080\": { \"pass\": \"applications/wp_emea_dev\" } } ``` Here, `/config/listeners/_*:8080` and `/config/listeners/_*:8080/pass` are also endpoints. Generally, object options are addressable by their names, array items—by their indexes (`/array/0/`). **Note**: By default, Unit is configured through a UNIX domain socket. To use this specification with OpenAPI tools interactively, [start](https://unit.nginx.org/howto/source/#source-startup) Unit with a TCP port as the control socket. + * + * The version of the OpenAPI document: 0.2.0 + * Contact: unit-owner@nginx.org + * Generated by: https://openapi-generator.tech + */ + +/// ConfigAccessLog : Configures the access log. + +#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] +pub struct ConfigAccessLog { + /// Sets the log format. Besides arbitrary text, can contain any variables Unit supports. + #[serde(rename = "format", skip_serializing_if = "Option::is_none")] + pub format: Option, + /// Pathname of the access log file. + #[serde(rename = "path", skip_serializing_if = "Option::is_none")] + pub path: Option, +} + +impl ConfigAccessLog { + /// Configures the access log. + pub fn new() -> ConfigAccessLog { + ConfigAccessLog { + format: None, + path: None, + } + } +} diff --git a/cli/unit-openapi/src/models/config_access_log_object.rs b/cli/unit-openapi/src/models/config_access_log_object.rs new file mode 100644 index 000000000..a20425ac0 --- /dev/null +++ b/cli/unit-openapi/src/models/config_access_log_object.rs @@ -0,0 +1,31 @@ +/* + * NGINX Unit 1.31.1 + * + * NGINX Unit is a lightweight and versatile application runtime that provides the essential components for your web application as a single open-source server: running application code, serving static assets, handling TLS and request routing. **Important**: Ufnit's API is designed to expose any part of its configuration as an addressable endpoint. Suppose a JSON object is stored at `/config/listeners/`: ```json { \"*:8080\": { \"pass\": \"applications/wp_emea_dev\" } } ``` Here, `/config/listeners/_*:8080` and `/config/listeners/_*:8080/pass` are also endpoints. Generally, object options are addressable by their names, array items—by their indexes (`/array/0/`). **Note**: By default, Unit is configured through a UNIX domain socket. To use this specification with OpenAPI tools interactively, [start](https://unit.nginx.org/howto/source/#source-startup) Unit with a TCP port as the control socket. + * + * The version of the OpenAPI document: 0.2.0 + * Contact: unit-owner@nginx.org + * Generated by: https://openapi-generator.tech + */ + +/// ConfigAccessLogObject : Configures the access log. + +#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] +pub struct ConfigAccessLogObject { + /// Sets the log format. Besides arbitrary text, can contain any variables Unit supports. + #[serde(rename = "format", skip_serializing_if = "Option::is_none")] + pub format: Option, + /// Pathname of the access log file. + #[serde(rename = "path", skip_serializing_if = "Option::is_none")] + pub path: Option, +} + +impl ConfigAccessLogObject { + /// Configures the access log. + pub fn new() -> ConfigAccessLogObject { + ConfigAccessLogObject { + format: None, + path: None, + } + } +} diff --git a/cli/unit-openapi/src/models/config_application.rs b/cli/unit-openapi/src/models/config_application.rs new file mode 100644 index 000000000..2d964154d --- /dev/null +++ b/cli/unit-openapi/src/models/config_application.rs @@ -0,0 +1,294 @@ +/* + * NGINX Unit 1.31.1 + * + * NGINX Unit is a lightweight and versatile application runtime that provides the essential components for your web application as a single open-source server: running application code, serving static assets, handling TLS and request routing. **Important**: Ufnit's API is designed to expose any part of its configuration as an addressable endpoint. Suppose a JSON object is stored at `/config/listeners/`: ```json { \"*:8080\": { \"pass\": \"applications/wp_emea_dev\" } } ``` Here, `/config/listeners/_*:8080` and `/config/listeners/_*:8080/pass` are also endpoints. Generally, object options are addressable by their names, array items—by their indexes (`/array/0/`). **Note**: By default, Unit is configured through a UNIX domain socket. To use this specification with OpenAPI tools interactively, [start](https://unit.nginx.org/howto/source/#source-startup) Unit with a TCP port as the control socket. + * + * The version of the OpenAPI document: 0.2.0 + * Contact: unit-owner@nginx.org + * Generated by: https://openapi-generator.tech + */ + +/// ConfigApplication : An object that defines an individual application. + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[serde(tag = "r#type")] +pub enum ConfigApplication { + #[serde(rename = "external")] + ConfigApplicationExternal { + /// Environment variables to be passed to the app. + #[serde(rename = "environment", skip_serializing_if = "Option::is_none")] + environment: Option<::std::collections::HashMap>, + /// Group name that runs the app process. + #[serde(rename = "group", skip_serializing_if = "Option::is_none")] + group: Option, + #[serde(rename = "isolation", skip_serializing_if = "Option::is_none")] + isolation: Option>, + #[serde(rename = "limits", skip_serializing_if = "Option::is_none")] + limits: Option>, + #[serde(rename = "processes", skip_serializing_if = "Option::is_none")] + processes: Option>, + /// Username that runs the app process. + #[serde(rename = "user", skip_serializing_if = "Option::is_none")] + user: Option, + /// Filename where Unit redirects the app's stderr stream. + #[serde(rename = "stderr", skip_serializing_if = "Option::is_none")] + stderr: Option, + /// Filename where Unit redirects the app's stdout stream. + #[serde(rename = "stdout", skip_serializing_if = "Option::is_none")] + stdout: Option, + /// The app’s working directory. + #[serde(rename = "working_directory", skip_serializing_if = "Option::is_none")] + working_directory: Option, + /// Pathname of the app, absolute or relative to `working_directory`. + #[serde(rename = "executable")] + executable: String, + /// An array of strings. + #[serde(rename = "arguments", skip_serializing_if = "Option::is_none")] + arguments: Option>, + }, + #[serde(rename = "java")] + ConfigApplicationJava { + /// Environment variables to be passed to the app. + #[serde(rename = "environment", skip_serializing_if = "Option::is_none")] + environment: Option<::std::collections::HashMap>, + /// Group name that runs the app process. + #[serde(rename = "group", skip_serializing_if = "Option::is_none")] + group: Option, + #[serde(rename = "isolation", skip_serializing_if = "Option::is_none")] + isolation: Option>, + #[serde(rename = "limits", skip_serializing_if = "Option::is_none")] + limits: Option>, + #[serde(rename = "processes", skip_serializing_if = "Option::is_none")] + processes: Option>, + /// Username that runs the app process. + #[serde(rename = "user", skip_serializing_if = "Option::is_none")] + user: Option, + /// Filename where Unit redirects the app's stderr stream. + #[serde(rename = "stderr", skip_serializing_if = "Option::is_none")] + stderr: Option, + /// Filename where Unit redirects the app's stdout stream. + #[serde(rename = "stdout", skip_serializing_if = "Option::is_none")] + stdout: Option, + /// The app’s working directory. + #[serde(rename = "working_directory", skip_serializing_if = "Option::is_none")] + working_directory: Option, + /// Pathname of the application’s .war file (packaged or unpackaged). + #[serde(rename = "webapp")] + webapp: String, + /// An array of strings. + #[serde(rename = "classpath", skip_serializing_if = "Option::is_none")] + classpath: Option>, + /// An array of strings. + #[serde(rename = "options", skip_serializing_if = "Option::is_none")] + options: Option>, + /// Stack size of a worker thread in bytes. + #[serde(rename = "thread_stack_size", skip_serializing_if = "Option::is_none")] + thread_stack_size: Option, + /// Number of worker threads per app process. + #[serde(rename = "threads", skip_serializing_if = "Option::is_none")] + threads: Option, + }, + #[serde(rename = "perl")] + ConfigApplicationPerl { + /// Environment variables to be passed to the app. + #[serde(rename = "environment", skip_serializing_if = "Option::is_none")] + environment: Option<::std::collections::HashMap>, + /// Group name that runs the app process. + #[serde(rename = "group", skip_serializing_if = "Option::is_none")] + group: Option, + #[serde(rename = "isolation", skip_serializing_if = "Option::is_none")] + isolation: Option>, + #[serde(rename = "limits", skip_serializing_if = "Option::is_none")] + limits: Option>, + #[serde(rename = "processes", skip_serializing_if = "Option::is_none")] + processes: Option>, + /// Username that runs the app process. + #[serde(rename = "user", skip_serializing_if = "Option::is_none")] + user: Option, + /// Filename where Unit redirects the app's stderr stream. + #[serde(rename = "stderr", skip_serializing_if = "Option::is_none")] + stderr: Option, + /// Filename where Unit redirects the app's stdout stream. + #[serde(rename = "stdout", skip_serializing_if = "Option::is_none")] + stdout: Option, + /// The app’s working directory. + #[serde(rename = "working_directory", skip_serializing_if = "Option::is_none")] + working_directory: Option, + /// PSGI script path. + #[serde(rename = "script")] + script: String, + /// Stack size of a worker thread in bytes. + #[serde(rename = "thread_stack_size", skip_serializing_if = "Option::is_none")] + thread_stack_size: Option, + /// Number of worker threads per app process. + #[serde(rename = "threads", skip_serializing_if = "Option::is_none")] + threads: Option, + }, + #[serde(rename = "php")] + ConfigApplicationPhp { + /// Environment variables to be passed to the app. + #[serde(rename = "environment", skip_serializing_if = "Option::is_none")] + environment: Option<::std::collections::HashMap>, + /// Group name that runs the app process. + #[serde(rename = "group", skip_serializing_if = "Option::is_none")] + group: Option, + #[serde(rename = "isolation", skip_serializing_if = "Option::is_none")] + isolation: Option>, + #[serde(rename = "limits", skip_serializing_if = "Option::is_none")] + limits: Option>, + #[serde(rename = "processes", skip_serializing_if = "Option::is_none")] + processes: Option>, + /// Username that runs the app process. + #[serde(rename = "user", skip_serializing_if = "Option::is_none")] + user: Option, + /// Filename where Unit redirects the app's stderr stream. + #[serde(rename = "stderr", skip_serializing_if = "Option::is_none")] + stderr: Option, + /// Filename where Unit redirects the app's stdout stream. + #[serde(rename = "stdout", skip_serializing_if = "Option::is_none")] + stdout: Option, + /// The app’s working directory. + #[serde(rename = "working_directory", skip_serializing_if = "Option::is_none")] + working_directory: Option, + /// Base directory of the app’s file structure. + #[serde(rename = "root")] + root: String, + /// Filename added to URI paths that point to directories if no `script` is set. + #[serde(rename = "index", skip_serializing_if = "Option::is_none")] + index: Option, + #[serde(rename = "options", skip_serializing_if = "Option::is_none")] + options: Option>, + /// Filename of a `root`-based PHP script that serves all requests to the app. + #[serde(rename = "script", skip_serializing_if = "Option::is_none")] + script: Option, + /// Application sections with custom `root`, `script`, and `index` values. + #[serde(rename = "targets", skip_serializing_if = "Option::is_none")] + targets: Option<::std::collections::HashMap>, + }, + #[serde(rename = "python")] + ConfigApplicationPython { + /// Environment variables to be passed to the app. + #[serde(rename = "environment", skip_serializing_if = "Option::is_none")] + environment: Option<::std::collections::HashMap>, + /// Group name that runs the app process. + #[serde(rename = "group", skip_serializing_if = "Option::is_none")] + group: Option, + #[serde(rename = "isolation", skip_serializing_if = "Option::is_none")] + isolation: Option>, + #[serde(rename = "limits", skip_serializing_if = "Option::is_none")] + limits: Option>, + #[serde(rename = "processes", skip_serializing_if = "Option::is_none")] + processes: Option>, + /// Username that runs the app process. + #[serde(rename = "user", skip_serializing_if = "Option::is_none")] + user: Option, + /// Filename where Unit redirects the app's stderr stream. + #[serde(rename = "stderr", skip_serializing_if = "Option::is_none")] + stderr: Option, + /// Filename where Unit redirects the app's stdout stream. + #[serde(rename = "stdout", skip_serializing_if = "Option::is_none")] + stdout: Option, + /// The app’s working directory. + #[serde(rename = "working_directory", skip_serializing_if = "Option::is_none")] + working_directory: Option, + /// App’s module name. + #[serde(rename = "module")] + module: String, + /// Name of the `module`-based callable that Unit runs as the app. + #[serde(rename = "callable", skip_serializing_if = "Option::is_none")] + callable: Option, + /// Path to the app’s virtual environment, absolute or relative to `working_directory`. + #[serde(rename = "home", skip_serializing_if = "Option::is_none")] + home: Option, + #[serde(rename = "path", skip_serializing_if = "Option::is_none")] + path: Option>, + /// SCRIPT_NAME context value for WSGI or the root_path context value for ASGI. + #[serde(rename = "prefix", skip_serializing_if = "Option::is_none")] + prefix: Option, + /// Hints Unit that the app uses a certain interface. + #[serde(rename = "protocol", skip_serializing_if = "Option::is_none")] + protocol: Option, + /// App sections with custom `module` and `callable` values. + #[serde(rename = "targets", skip_serializing_if = "Option::is_none")] + targets: Option<::std::collections::HashMap>, + /// Stack size of a worker thread in bytes. + #[serde(rename = "thread_stack_size", skip_serializing_if = "Option::is_none")] + thread_stack_size: Option, + /// Number of worker threads per app process. + #[serde(rename = "threads", skip_serializing_if = "Option::is_none")] + threads: Option, + }, + #[serde(rename = "ruby")] + ConfigApplicationRuby { + /// Environment variables to be passed to the app. + #[serde(rename = "environment", skip_serializing_if = "Option::is_none")] + environment: Option<::std::collections::HashMap>, + /// Group name that runs the app process. + #[serde(rename = "group", skip_serializing_if = "Option::is_none")] + group: Option, + #[serde(rename = "isolation", skip_serializing_if = "Option::is_none")] + isolation: Option>, + #[serde(rename = "limits", skip_serializing_if = "Option::is_none")] + limits: Option>, + #[serde(rename = "processes", skip_serializing_if = "Option::is_none")] + processes: Option>, + /// Username that runs the app process. + #[serde(rename = "user", skip_serializing_if = "Option::is_none")] + user: Option, + /// Filename where Unit redirects the app's stderr stream. + #[serde(rename = "stderr", skip_serializing_if = "Option::is_none")] + stderr: Option, + /// Filename where Unit redirects the app's stdout stream. + #[serde(rename = "stdout", skip_serializing_if = "Option::is_none")] + stdout: Option, + /// The app’s working directory. + #[serde(rename = "working_directory", skip_serializing_if = "Option::is_none")] + working_directory: Option, + /// Rack script pathname, including the .ru extension. + #[serde(rename = "script")] + script: String, + /// Pathname of the .rb file setting the event hooks invoked during the app’s lifecycle. + #[serde(rename = "hooks", skip_serializing_if = "Option::is_none")] + hooks: Option, + /// Number of worker threads per app process. + #[serde(rename = "threads", skip_serializing_if = "Option::is_none")] + threads: Option, + }, +} + +/// Application type and language version. +#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)] +pub enum RHashType { + #[serde(rename = "external")] + External, + #[serde(rename = "java")] + Java, + #[serde(rename = "perl")] + Perl, + #[serde(rename = "php")] + Php, + #[serde(rename = "python")] + Python, + #[serde(rename = "ruby")] + Ruby, +} + +impl Default for RHashType { + fn default() -> RHashType { + Self::External + } +} +/// Hints Unit that the app uses a certain interface. +#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)] +pub enum Protocol { + #[serde(rename = "asgi")] + Asgi, + #[serde(rename = "wsgi")] + Wsgi, +} + +impl Default for Protocol { + fn default() -> Protocol { + Self::Asgi + } +} diff --git a/cli/unit-openapi/src/models/config_application_common.rs b/cli/unit-openapi/src/models/config_application_common.rs new file mode 100644 index 000000000..f74bd8e70 --- /dev/null +++ b/cli/unit-openapi/src/models/config_application_common.rs @@ -0,0 +1,83 @@ +/* + * NGINX Unit 1.31.1 + * + * NGINX Unit is a lightweight and versatile application runtime that provides the essential components for your web application as a single open-source server: running application code, serving static assets, handling TLS and request routing. **Important**: Ufnit's API is designed to expose any part of its configuration as an addressable endpoint. Suppose a JSON object is stored at `/config/listeners/`: ```json { \"*:8080\": { \"pass\": \"applications/wp_emea_dev\" } } ``` Here, `/config/listeners/_*:8080` and `/config/listeners/_*:8080/pass` are also endpoints. Generally, object options are addressable by their names, array items—by their indexes (`/array/0/`). **Note**: By default, Unit is configured through a UNIX domain socket. To use this specification with OpenAPI tools interactively, [start](https://unit.nginx.org/howto/source/#source-startup) Unit with a TCP port as the control socket. + * + * The version of the OpenAPI document: 0.2.0 + * Contact: unit-owner@nginx.org + * Generated by: https://openapi-generator.tech + */ + +/// ConfigApplicationCommon : Common application object options. + +#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] +pub struct ConfigApplicationCommon { + /// Application type and language version. + #[serde(rename = "type")] + pub r#type: RHashType, + /// Environment variables to be passed to the app. + #[serde(rename = "environment", skip_serializing_if = "Option::is_none")] + pub environment: Option<::std::collections::HashMap>, + /// Group name that runs the app process. + #[serde(rename = "group", skip_serializing_if = "Option::is_none")] + pub group: Option, + #[serde(rename = "isolation", skip_serializing_if = "Option::is_none")] + pub isolation: Option>, + #[serde(rename = "limits", skip_serializing_if = "Option::is_none")] + pub limits: Option>, + #[serde(rename = "processes", skip_serializing_if = "Option::is_none")] + pub processes: Option>, + /// Username that runs the app process. + #[serde(rename = "user", skip_serializing_if = "Option::is_none")] + pub user: Option, + /// Filename where Unit redirects the app's stderr stream. + #[serde(rename = "stderr", skip_serializing_if = "Option::is_none")] + pub stderr: Option, + /// Filename where Unit redirects the app's stdout stream. + #[serde(rename = "stdout", skip_serializing_if = "Option::is_none")] + pub stdout: Option, + /// The app’s working directory. + #[serde(rename = "working_directory", skip_serializing_if = "Option::is_none")] + pub working_directory: Option, +} + +impl ConfigApplicationCommon { + /// Common application object options. + pub fn new(r#type: RHashType) -> ConfigApplicationCommon { + ConfigApplicationCommon { + r#type, + environment: None, + group: None, + isolation: None, + limits: None, + processes: None, + user: None, + stderr: None, + stdout: None, + working_directory: None, + } + } +} + +/// Application type and language version. +#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)] +pub enum RHashType { + #[serde(rename = "external")] + External, + #[serde(rename = "java")] + Java, + #[serde(rename = "perl")] + Perl, + #[serde(rename = "php")] + Php, + #[serde(rename = "python")] + Python, + #[serde(rename = "ruby")] + Ruby, +} + +impl Default for RHashType { + fn default() -> RHashType { + Self::External + } +} diff --git a/cli/unit-openapi/src/models/config_application_common_isolation.rs b/cli/unit-openapi/src/models/config_application_common_isolation.rs new file mode 100644 index 000000000..db9271abe --- /dev/null +++ b/cli/unit-openapi/src/models/config_application_common_isolation.rs @@ -0,0 +1,44 @@ +/* + * NGINX Unit 1.31.1 + * + * NGINX Unit is a lightweight and versatile application runtime that provides the essential components for your web application as a single open-source server: running application code, serving static assets, handling TLS and request routing. **Important**: Ufnit's API is designed to expose any part of its configuration as an addressable endpoint. Suppose a JSON object is stored at `/config/listeners/`: ```json { \"*:8080\": { \"pass\": \"applications/wp_emea_dev\" } } ``` Here, `/config/listeners/_*:8080` and `/config/listeners/_*:8080/pass` are also endpoints. Generally, object options are addressable by their names, array items—by their indexes (`/array/0/`). **Note**: By default, Unit is configured through a UNIX domain socket. To use this specification with OpenAPI tools interactively, [start](https://unit.nginx.org/howto/source/#source-startup) Unit with a TCP port as the control socket. + * + * The version of the OpenAPI document: 0.2.0 + * Contact: unit-owner@nginx.org + * Generated by: https://openapi-generator.tech + */ + +/// ConfigApplicationCommonIsolation : Manages the isolation of an application process. + +#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] +pub struct ConfigApplicationCommonIsolation { + #[serde(rename = "automount", skip_serializing_if = "Option::is_none")] + pub automount: Option>, + #[serde(rename = "cgroup", skip_serializing_if = "Option::is_none")] + pub cgroup: Option>, + /// Array of group ID mapping objects. + #[serde(rename = "gidmap", skip_serializing_if = "Option::is_none")] + pub gidmap: Option>, + #[serde(rename = "namespaces", skip_serializing_if = "Option::is_none")] + pub namespaces: Option>, + /// pathname of the directory to be used as the new file system root for the app. + #[serde(rename = "rootfs", skip_serializing_if = "Option::is_none")] + pub rootfs: Option, + /// Array of user ID mapping objects. + #[serde(rename = "uidmap", skip_serializing_if = "Option::is_none")] + pub uidmap: Option>, +} + +impl ConfigApplicationCommonIsolation { + /// Manages the isolation of an application process. + pub fn new() -> ConfigApplicationCommonIsolation { + ConfigApplicationCommonIsolation { + automount: None, + cgroup: None, + gidmap: None, + namespaces: None, + rootfs: None, + uidmap: None, + } + } +} diff --git a/cli/unit-openapi/src/models/config_application_common_isolation_automount.rs b/cli/unit-openapi/src/models/config_application_common_isolation_automount.rs new file mode 100644 index 000000000..f1d85ffe7 --- /dev/null +++ b/cli/unit-openapi/src/models/config_application_common_isolation_automount.rs @@ -0,0 +1,35 @@ +/* + * NGINX Unit 1.31.1 + * + * NGINX Unit is a lightweight and versatile application runtime that provides the essential components for your web application as a single open-source server: running application code, serving static assets, handling TLS and request routing. **Important**: Ufnit's API is designed to expose any part of its configuration as an addressable endpoint. Suppose a JSON object is stored at `/config/listeners/`: ```json { \"*:8080\": { \"pass\": \"applications/wp_emea_dev\" } } ``` Here, `/config/listeners/_*:8080` and `/config/listeners/_*:8080/pass` are also endpoints. Generally, object options are addressable by their names, array items—by their indexes (`/array/0/`). **Note**: By default, Unit is configured through a UNIX domain socket. To use this specification with OpenAPI tools interactively, [start](https://unit.nginx.org/howto/source/#source-startup) Unit with a TCP port as the control socket. + * + * The version of the OpenAPI document: 0.2.0 + * Contact: unit-owner@nginx.org + * Generated by: https://openapi-generator.tech + */ + +/// ConfigApplicationCommonIsolationAutomount : Controls mount behavior if rootfs is enabled. + +#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] +pub struct ConfigApplicationCommonIsolationAutomount { + /// Controls whether the language runtime dependencies are automounted. + #[serde(rename = "language_deps", skip_serializing_if = "Option::is_none")] + pub language_deps: Option, + /// Controls whether the procfs is automounted. + #[serde(rename = "procfs", skip_serializing_if = "Option::is_none")] + pub procfs: Option, + /// Controls whether the tmpfs is automounted. + #[serde(rename = "tmpfs", skip_serializing_if = "Option::is_none")] + pub tmpfs: Option, +} + +impl ConfigApplicationCommonIsolationAutomount { + /// Controls mount behavior if rootfs is enabled. + pub fn new() -> ConfigApplicationCommonIsolationAutomount { + ConfigApplicationCommonIsolationAutomount { + language_deps: None, + procfs: None, + tmpfs: None, + } + } +} diff --git a/cli/unit-openapi/src/models/config_application_common_isolation_cgroup.rs b/cli/unit-openapi/src/models/config_application_common_isolation_cgroup.rs new file mode 100644 index 000000000..8370795ab --- /dev/null +++ b/cli/unit-openapi/src/models/config_application_common_isolation_cgroup.rs @@ -0,0 +1,25 @@ +/* + * NGINX Unit 1.31.1 + * + * NGINX Unit is a lightweight and versatile application runtime that provides the essential components for your web application as a single open-source server: running application code, serving static assets, handling TLS and request routing. **Important**: Ufnit's API is designed to expose any part of its configuration as an addressable endpoint. Suppose a JSON object is stored at `/config/listeners/`: ```json { \"*:8080\": { \"pass\": \"applications/wp_emea_dev\" } } ``` Here, `/config/listeners/_*:8080` and `/config/listeners/_*:8080/pass` are also endpoints. Generally, object options are addressable by their names, array items—by their indexes (`/array/0/`). **Note**: By default, Unit is configured through a UNIX domain socket. To use this specification with OpenAPI tools interactively, [start](https://unit.nginx.org/howto/source/#source-startup) Unit with a TCP port as the control socket. + * + * The version of the OpenAPI document: 0.2.0 + * Contact: unit-owner@nginx.org + * Generated by: https://openapi-generator.tech + */ + +/// ConfigApplicationCommonIsolationCgroup : Defines the app’s cgroup. + +#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] +pub struct ConfigApplicationCommonIsolationCgroup { + /// Configures absolute or relative path of the app in the cgroups v2 hierarchy. + #[serde(rename = "path")] + pub path: String, +} + +impl ConfigApplicationCommonIsolationCgroup { + /// Defines the app’s cgroup. + pub fn new(path: String) -> ConfigApplicationCommonIsolationCgroup { + ConfigApplicationCommonIsolationCgroup { path } + } +} diff --git a/cli/unit-openapi/src/models/config_application_common_isolation_gidmap_inner.rs b/cli/unit-openapi/src/models/config_application_common_isolation_gidmap_inner.rs new file mode 100644 index 000000000..4f3ba4674 --- /dev/null +++ b/cli/unit-openapi/src/models/config_application_common_isolation_gidmap_inner.rs @@ -0,0 +1,31 @@ +/* + * NGINX Unit 1.31.1 + * + * NGINX Unit is a lightweight and versatile application runtime that provides the essential components for your web application as a single open-source server: running application code, serving static assets, handling TLS and request routing. **Important**: Ufnit's API is designed to expose any part of its configuration as an addressable endpoint. Suppose a JSON object is stored at `/config/listeners/`: ```json { \"*:8080\": { \"pass\": \"applications/wp_emea_dev\" } } ``` Here, `/config/listeners/_*:8080` and `/config/listeners/_*:8080/pass` are also endpoints. Generally, object options are addressable by their names, array items—by their indexes (`/array/0/`). **Note**: By default, Unit is configured through a UNIX domain socket. To use this specification with OpenAPI tools interactively, [start](https://unit.nginx.org/howto/source/#source-startup) Unit with a TCP port as the control socket. + * + * The version of the OpenAPI document: 0.2.0 + * Contact: unit-owner@nginx.org + * Generated by: https://openapi-generator.tech + */ + +/// ConfigApplicationCommonIsolationGidmapInner : Group ID mapping object. + +#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] +pub struct ConfigApplicationCommonIsolationGidmapInner { + /// Starts the group ID mapping range in the app’s namespace. + #[serde(rename = "container")] + pub container: i32, + /// Starts the group ID mapping range in the OS namespace. + #[serde(rename = "host")] + pub host: i32, + /// Size of the ID range in both namespaces. + #[serde(rename = "size")] + pub size: i32, +} + +impl ConfigApplicationCommonIsolationGidmapInner { + /// Group ID mapping object. + pub fn new(container: i32, host: i32, size: i32) -> ConfigApplicationCommonIsolationGidmapInner { + ConfigApplicationCommonIsolationGidmapInner { container, host, size } + } +} diff --git a/cli/unit-openapi/src/models/config_application_common_isolation_namespaces.rs b/cli/unit-openapi/src/models/config_application_common_isolation_namespaces.rs new file mode 100644 index 000000000..94efeb949 --- /dev/null +++ b/cli/unit-openapi/src/models/config_application_common_isolation_namespaces.rs @@ -0,0 +1,44 @@ +/* + * NGINX Unit 1.31.1 + * + * NGINX Unit is a lightweight and versatile application runtime that provides the essential components for your web application as a single open-source server: running application code, serving static assets, handling TLS and request routing. **Important**: Ufnit's API is designed to expose any part of its configuration as an addressable endpoint. Suppose a JSON object is stored at `/config/listeners/`: ```json { \"*:8080\": { \"pass\": \"applications/wp_emea_dev\" } } ``` Here, `/config/listeners/_*:8080` and `/config/listeners/_*:8080/pass` are also endpoints. Generally, object options are addressable by their names, array items—by their indexes (`/array/0/`). **Note**: By default, Unit is configured through a UNIX domain socket. To use this specification with OpenAPI tools interactively, [start](https://unit.nginx.org/howto/source/#source-startup) Unit with a TCP port as the control socket. + * + * The version of the OpenAPI document: 0.2.0 + * Contact: unit-owner@nginx.org + * Generated by: https://openapi-generator.tech + */ + +#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] +pub struct ConfigApplicationCommonIsolationNamespaces { + /// Creates a new cgroup namespace for the app. + #[serde(rename = "cgroup", skip_serializing_if = "Option::is_none")] + pub cgroup: Option, + /// Creates a new user namespace for the app. + #[serde(rename = "credential", skip_serializing_if = "Option::is_none")] + pub credential: Option, + /// Creates a new mount namespace for the app. + #[serde(rename = "mount", skip_serializing_if = "Option::is_none")] + pub mount: Option, + /// Creates a new network namespace for the app. + #[serde(rename = "network", skip_serializing_if = "Option::is_none")] + pub network: Option, + /// Creates a new PID namespace for the app. + #[serde(rename = "pid", skip_serializing_if = "Option::is_none")] + pub pid: Option, + /// Creates a new UTS namespace for the app. + #[serde(rename = "uname", skip_serializing_if = "Option::is_none")] + pub uname: Option, +} + +impl ConfigApplicationCommonIsolationNamespaces { + pub fn new() -> ConfigApplicationCommonIsolationNamespaces { + ConfigApplicationCommonIsolationNamespaces { + cgroup: None, + credential: None, + mount: None, + network: None, + pid: None, + uname: None, + } + } +} diff --git a/cli/unit-openapi/src/models/config_application_common_isolation_uidmap_inner.rs b/cli/unit-openapi/src/models/config_application_common_isolation_uidmap_inner.rs new file mode 100644 index 000000000..251ecf619 --- /dev/null +++ b/cli/unit-openapi/src/models/config_application_common_isolation_uidmap_inner.rs @@ -0,0 +1,31 @@ +/* + * NGINX Unit 1.31.1 + * + * NGINX Unit is a lightweight and versatile application runtime that provides the essential components for your web application as a single open-source server: running application code, serving static assets, handling TLS and request routing. **Important**: Ufnit's API is designed to expose any part of its configuration as an addressable endpoint. Suppose a JSON object is stored at `/config/listeners/`: ```json { \"*:8080\": { \"pass\": \"applications/wp_emea_dev\" } } ``` Here, `/config/listeners/_*:8080` and `/config/listeners/_*:8080/pass` are also endpoints. Generally, object options are addressable by their names, array items—by their indexes (`/array/0/`). **Note**: By default, Unit is configured through a UNIX domain socket. To use this specification with OpenAPI tools interactively, [start](https://unit.nginx.org/howto/source/#source-startup) Unit with a TCP port as the control socket. + * + * The version of the OpenAPI document: 0.2.0 + * Contact: unit-owner@nginx.org + * Generated by: https://openapi-generator.tech + */ + +/// ConfigApplicationCommonIsolationUidmapInner : User ID mapping object. + +#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] +pub struct ConfigApplicationCommonIsolationUidmapInner { + /// Starts the user ID mapping range in the app’s namespace. + #[serde(rename = "container")] + pub container: i32, + /// Starts the user ID mapping range in the OS namespace. + #[serde(rename = "host")] + pub host: i32, + /// Size of the ID range in both namespaces. + #[serde(rename = "size")] + pub size: i32, +} + +impl ConfigApplicationCommonIsolationUidmapInner { + /// User ID mapping object. + pub fn new(container: i32, host: i32, size: i32) -> ConfigApplicationCommonIsolationUidmapInner { + ConfigApplicationCommonIsolationUidmapInner { container, host, size } + } +} diff --git a/cli/unit-openapi/src/models/config_application_common_limits.rs b/cli/unit-openapi/src/models/config_application_common_limits.rs new file mode 100644 index 000000000..a3957b42d --- /dev/null +++ b/cli/unit-openapi/src/models/config_application_common_limits.rs @@ -0,0 +1,31 @@ +/* + * NGINX Unit 1.31.1 + * + * NGINX Unit is a lightweight and versatile application runtime that provides the essential components for your web application as a single open-source server: running application code, serving static assets, handling TLS and request routing. **Important**: Ufnit's API is designed to expose any part of its configuration as an addressable endpoint. Suppose a JSON object is stored at `/config/listeners/`: ```json { \"*:8080\": { \"pass\": \"applications/wp_emea_dev\" } } ``` Here, `/config/listeners/_*:8080` and `/config/listeners/_*:8080/pass` are also endpoints. Generally, object options are addressable by their names, array items—by their indexes (`/array/0/`). **Note**: By default, Unit is configured through a UNIX domain socket. To use this specification with OpenAPI tools interactively, [start](https://unit.nginx.org/howto/source/#source-startup) Unit with a TCP port as the control socket. + * + * The version of the OpenAPI document: 0.2.0 + * Contact: unit-owner@nginx.org + * Generated by: https://openapi-generator.tech + */ + +/// ConfigApplicationCommonLimits : Governs the life cycle of an application process. + +#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] +pub struct ConfigApplicationCommonLimits { + /// Maximum number of requests an app process can serve. + #[serde(rename = "requests", skip_serializing_if = "Option::is_none")] + pub requests: Option, + /// Request timeout in seconds. + #[serde(rename = "timeout", skip_serializing_if = "Option::is_none")] + pub timeout: Option, +} + +impl ConfigApplicationCommonLimits { + /// Governs the life cycle of an application process. + pub fn new() -> ConfigApplicationCommonLimits { + ConfigApplicationCommonLimits { + requests: None, + timeout: None, + } + } +} diff --git a/cli/unit-openapi/src/models/config_application_common_processes.rs b/cli/unit-openapi/src/models/config_application_common_processes.rs new file mode 100644 index 000000000..430175eb8 --- /dev/null +++ b/cli/unit-openapi/src/models/config_application_common_processes.rs @@ -0,0 +1,35 @@ +/* + * NGINX Unit 1.31.1 + * + * NGINX Unit is a lightweight and versatile application runtime that provides the essential components for your web application as a single open-source server: running application code, serving static assets, handling TLS and request routing. **Important**: Ufnit's API is designed to expose any part of its configuration as an addressable endpoint. Suppose a JSON object is stored at `/config/listeners/`: ```json { \"*:8080\": { \"pass\": \"applications/wp_emea_dev\" } } ``` Here, `/config/listeners/_*:8080` and `/config/listeners/_*:8080/pass` are also endpoints. Generally, object options are addressable by their names, array items—by their indexes (`/array/0/`). **Note**: By default, Unit is configured through a UNIX domain socket. To use this specification with OpenAPI tools interactively, [start](https://unit.nginx.org/howto/source/#source-startup) Unit with a TCP port as the control socket. + * + * The version of the OpenAPI document: 0.2.0 + * Contact: unit-owner@nginx.org + * Generated by: https://openapi-generator.tech + */ + +/// ConfigApplicationCommonProcesses : Governs the behavior of app processes. + +#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] +pub struct ConfigApplicationCommonProcesses { + /// Number of seconds Unit waits for before terminating an idle process that exceeds `spare`. + #[serde(rename = "idle_timeout", skip_serializing_if = "Option::is_none")] + pub idle_timeout: Option, + /// Maximum number of application processes that Unit maintains (busy and idle). + #[serde(rename = "max", skip_serializing_if = "Option::is_none")] + pub max: Option, + /// Minimum number of idle processes that Unit tries to maintain for an app. + #[serde(rename = "idle", skip_serializing_if = "Option::is_none")] + pub idle: Option, +} + +impl ConfigApplicationCommonProcesses { + /// Governs the behavior of app processes. + pub fn new() -> ConfigApplicationCommonProcesses { + ConfigApplicationCommonProcesses { + idle_timeout: None, + max: None, + idle: None, + } + } +} diff --git a/cli/unit-openapi/src/models/config_application_common_processes_any_of.rs b/cli/unit-openapi/src/models/config_application_common_processes_any_of.rs new file mode 100644 index 000000000..c09280264 --- /dev/null +++ b/cli/unit-openapi/src/models/config_application_common_processes_any_of.rs @@ -0,0 +1,32 @@ +/* + * NGINX Unit 1.31.1 + * + * NGINX Unit is a lightweight and versatile application runtime that provides the essential components for your web application as a single open-source server: running application code, serving static assets, handling TLS and request routing. **Important**: Ufnit's API is designed to expose any part of its configuration as an addressable endpoint. Suppose a JSON object is stored at `/config/listeners/`: ```json { \"*:8080\": { \"pass\": \"applications/wp_emea_dev\" } } ``` Here, `/config/listeners/_*:8080` and `/config/listeners/_*:8080/pass` are also endpoints. Generally, object options are addressable by their names, array items—by their indexes (`/array/0/`). **Note**: By default, Unit is configured through a UNIX domain socket. To use this specification with OpenAPI tools interactively, [start](https://unit.nginx.org/howto/source/#source-startup) Unit with a TCP port as the control socket. + * + * The version of the OpenAPI document: 0.2.0 + * Contact: unit-owner@nginx.org + * Generated by: https://openapi-generator.tech + */ + +#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] +pub struct ConfigApplicationCommonProcessesAnyOf { + /// Number of seconds Unit waits for before terminating an idle process that exceeds `spare`. + #[serde(rename = "idle_timeout", skip_serializing_if = "Option::is_none")] + pub idle_timeout: Option, + /// Maximum number of application processes that Unit maintains (busy and idle). + #[serde(rename = "max", skip_serializing_if = "Option::is_none")] + pub max: Option, + /// Minimum number of idle processes that Unit tries to maintain for an app. + #[serde(rename = "idle", skip_serializing_if = "Option::is_none")] + pub idle: Option, +} + +impl ConfigApplicationCommonProcessesAnyOf { + pub fn new() -> ConfigApplicationCommonProcessesAnyOf { + ConfigApplicationCommonProcessesAnyOf { + idle_timeout: None, + max: None, + idle: None, + } + } +} diff --git a/cli/unit-openapi/src/models/config_application_external.rs b/cli/unit-openapi/src/models/config_application_external.rs new file mode 100644 index 000000000..360b817c0 --- /dev/null +++ b/cli/unit-openapi/src/models/config_application_external.rs @@ -0,0 +1,91 @@ +/* + * NGINX Unit 1.31.1 + * + * NGINX Unit is a lightweight and versatile application runtime that provides the essential components for your web application as a single open-source server: running application code, serving static assets, handling TLS and request routing. **Important**: Ufnit's API is designed to expose any part of its configuration as an addressable endpoint. Suppose a JSON object is stored at `/config/listeners/`: ```json { \"*:8080\": { \"pass\": \"applications/wp_emea_dev\" } } ``` Here, `/config/listeners/_*:8080` and `/config/listeners/_*:8080/pass` are also endpoints. Generally, object options are addressable by their names, array items—by their indexes (`/array/0/`). **Note**: By default, Unit is configured through a UNIX domain socket. To use this specification with OpenAPI tools interactively, [start](https://unit.nginx.org/howto/source/#source-startup) Unit with a TCP port as the control socket. + * + * The version of the OpenAPI document: 0.2.0 + * Contact: unit-owner@nginx.org + * Generated by: https://openapi-generator.tech + */ + +/// ConfigApplicationExternal : Go or Node.js application on Unit. + +#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] +pub struct ConfigApplicationExternal { + /// Application type and language version. + #[serde(rename = "type")] + pub r#type: RHashType, + /// Environment variables to be passed to the app. + #[serde(rename = "environment", skip_serializing_if = "Option::is_none")] + pub environment: Option<::std::collections::HashMap>, + /// Group name that runs the app process. + #[serde(rename = "group", skip_serializing_if = "Option::is_none")] + pub group: Option, + #[serde(rename = "isolation", skip_serializing_if = "Option::is_none")] + pub isolation: Option>, + #[serde(rename = "limits", skip_serializing_if = "Option::is_none")] + pub limits: Option>, + #[serde(rename = "processes", skip_serializing_if = "Option::is_none")] + pub processes: Option>, + /// Username that runs the app process. + #[serde(rename = "user", skip_serializing_if = "Option::is_none")] + pub user: Option, + /// Filename where Unit redirects the app's stderr stream. + #[serde(rename = "stderr", skip_serializing_if = "Option::is_none")] + pub stderr: Option, + /// Filename where Unit redirects the app's stdout stream. + #[serde(rename = "stdout", skip_serializing_if = "Option::is_none")] + pub stdout: Option, + /// The app’s working directory. + #[serde(rename = "working_directory", skip_serializing_if = "Option::is_none")] + pub working_directory: Option, + /// Pathname of the app, absolute or relative to `working_directory`. + #[serde(rename = "executable")] + pub executable: String, + /// An array of strings. + #[serde(rename = "arguments", skip_serializing_if = "Option::is_none")] + pub arguments: Option>, +} + +impl ConfigApplicationExternal { + /// Go or Node.js application on Unit. + pub fn new(r#type: RHashType, executable: String) -> ConfigApplicationExternal { + ConfigApplicationExternal { + r#type, + environment: None, + group: None, + isolation: None, + limits: None, + processes: None, + user: None, + stderr: None, + stdout: None, + working_directory: None, + executable, + arguments: None, + } + } +} + +/// Application type and language version. +#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)] +pub enum RHashType { + #[serde(rename = "external")] + External, + #[serde(rename = "java")] + Java, + #[serde(rename = "perl")] + Perl, + #[serde(rename = "php")] + Php, + #[serde(rename = "python")] + Python, + #[serde(rename = "ruby")] + Ruby, +} + +impl Default for RHashType { + fn default() -> RHashType { + Self::External + } +} diff --git a/cli/unit-openapi/src/models/config_application_external_all_of.rs b/cli/unit-openapi/src/models/config_application_external_all_of.rs new file mode 100644 index 000000000..2b00611ad --- /dev/null +++ b/cli/unit-openapi/src/models/config_application_external_all_of.rs @@ -0,0 +1,28 @@ +/* + * NGINX Unit 1.31.1 + * + * NGINX Unit is a lightweight and versatile application runtime that provides the essential components for your web application as a single open-source server: running application code, serving static assets, handling TLS and request routing. **Important**: Ufnit's API is designed to expose any part of its configuration as an addressable endpoint. Suppose a JSON object is stored at `/config/listeners/`: ```json { \"*:8080\": { \"pass\": \"applications/wp_emea_dev\" } } ``` Here, `/config/listeners/_*:8080` and `/config/listeners/_*:8080/pass` are also endpoints. Generally, object options are addressable by their names, array items—by their indexes (`/array/0/`). **Note**: By default, Unit is configured through a UNIX domain socket. To use this specification with OpenAPI tools interactively, [start](https://unit.nginx.org/howto/source/#source-startup) Unit with a TCP port as the control socket. + * + * The version of the OpenAPI document: 0.2.0 + * Contact: unit-owner@nginx.org + * Generated by: https://openapi-generator.tech + */ + +#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] +pub struct ConfigApplicationExternalAllOf { + /// Pathname of the app, absolute or relative to `working_directory`. + #[serde(rename = "executable")] + pub executable: String, + /// An array of strings. + #[serde(rename = "arguments", skip_serializing_if = "Option::is_none")] + pub arguments: Option>, +} + +impl ConfigApplicationExternalAllOf { + pub fn new(executable: String) -> ConfigApplicationExternalAllOf { + ConfigApplicationExternalAllOf { + executable, + arguments: None, + } + } +} diff --git a/cli/unit-openapi/src/models/config_application_java.rs b/cli/unit-openapi/src/models/config_application_java.rs new file mode 100644 index 000000000..63830b40e --- /dev/null +++ b/cli/unit-openapi/src/models/config_application_java.rs @@ -0,0 +1,103 @@ +/* + * NGINX Unit 1.31.1 + * + * NGINX Unit is a lightweight and versatile application runtime that provides the essential components for your web application as a single open-source server: running application code, serving static assets, handling TLS and request routing. **Important**: Ufnit's API is designed to expose any part of its configuration as an addressable endpoint. Suppose a JSON object is stored at `/config/listeners/`: ```json { \"*:8080\": { \"pass\": \"applications/wp_emea_dev\" } } ``` Here, `/config/listeners/_*:8080` and `/config/listeners/_*:8080/pass` are also endpoints. Generally, object options are addressable by their names, array items—by their indexes (`/array/0/`). **Note**: By default, Unit is configured through a UNIX domain socket. To use this specification with OpenAPI tools interactively, [start](https://unit.nginx.org/howto/source/#source-startup) Unit with a TCP port as the control socket. + * + * The version of the OpenAPI document: 0.2.0 + * Contact: unit-owner@nginx.org + * Generated by: https://openapi-generator.tech + */ + +/// ConfigApplicationJava : Java application on Unit. + +#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] +pub struct ConfigApplicationJava { + /// Application type and language version. + #[serde(rename = "type")] + pub r#type: RHashType, + /// Environment variables to be passed to the app. + #[serde(rename = "environment", skip_serializing_if = "Option::is_none")] + pub environment: Option<::std::collections::HashMap>, + /// Group name that runs the app process. + #[serde(rename = "group", skip_serializing_if = "Option::is_none")] + pub group: Option, + #[serde(rename = "isolation", skip_serializing_if = "Option::is_none")] + pub isolation: Option>, + #[serde(rename = "limits", skip_serializing_if = "Option::is_none")] + pub limits: Option>, + #[serde(rename = "processes", skip_serializing_if = "Option::is_none")] + pub processes: Option>, + /// Username that runs the app process. + #[serde(rename = "user", skip_serializing_if = "Option::is_none")] + pub user: Option, + /// Filename where Unit redirects the app's stderr stream. + #[serde(rename = "stderr", skip_serializing_if = "Option::is_none")] + pub stderr: Option, + /// Filename where Unit redirects the app's stdout stream. + #[serde(rename = "stdout", skip_serializing_if = "Option::is_none")] + pub stdout: Option, + /// The app’s working directory. + #[serde(rename = "working_directory", skip_serializing_if = "Option::is_none")] + pub working_directory: Option, + /// Pathname of the application’s .war file (packaged or unpackaged). + #[serde(rename = "webapp")] + pub webapp: String, + /// An array of strings. + #[serde(rename = "classpath", skip_serializing_if = "Option::is_none")] + pub classpath: Option>, + /// An array of strings. + #[serde(rename = "options", skip_serializing_if = "Option::is_none")] + pub options: Option>, + /// Stack size of a worker thread in bytes. + #[serde(rename = "thread_stack_size", skip_serializing_if = "Option::is_none")] + pub thread_stack_size: Option, + /// Number of worker threads per app process. + #[serde(rename = "threads", skip_serializing_if = "Option::is_none")] + pub threads: Option, +} + +impl ConfigApplicationJava { + /// Java application on Unit. + pub fn new(r#type: RHashType, webapp: String) -> ConfigApplicationJava { + ConfigApplicationJava { + r#type, + environment: None, + group: None, + isolation: None, + limits: None, + processes: None, + user: None, + stderr: None, + stdout: None, + working_directory: None, + webapp, + classpath: None, + options: None, + thread_stack_size: None, + threads: None, + } + } +} + +/// Application type and language version. +#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)] +pub enum RHashType { + #[serde(rename = "external")] + External, + #[serde(rename = "java")] + Java, + #[serde(rename = "perl")] + Perl, + #[serde(rename = "php")] + Php, + #[serde(rename = "python")] + Python, + #[serde(rename = "ruby")] + Ruby, +} + +impl Default for RHashType { + fn default() -> RHashType { + Self::External + } +} diff --git a/cli/unit-openapi/src/models/config_application_java_all_of.rs b/cli/unit-openapi/src/models/config_application_java_all_of.rs new file mode 100644 index 000000000..b4142340a --- /dev/null +++ b/cli/unit-openapi/src/models/config_application_java_all_of.rs @@ -0,0 +1,40 @@ +/* + * NGINX Unit 1.31.1 + * + * NGINX Unit is a lightweight and versatile application runtime that provides the essential components for your web application as a single open-source server: running application code, serving static assets, handling TLS and request routing. **Important**: Ufnit's API is designed to expose any part of its configuration as an addressable endpoint. Suppose a JSON object is stored at `/config/listeners/`: ```json { \"*:8080\": { \"pass\": \"applications/wp_emea_dev\" } } ``` Here, `/config/listeners/_*:8080` and `/config/listeners/_*:8080/pass` are also endpoints. Generally, object options are addressable by their names, array items—by their indexes (`/array/0/`). **Note**: By default, Unit is configured through a UNIX domain socket. To use this specification with OpenAPI tools interactively, [start](https://unit.nginx.org/howto/source/#source-startup) Unit with a TCP port as the control socket. + * + * The version of the OpenAPI document: 0.2.0 + * Contact: unit-owner@nginx.org + * Generated by: https://openapi-generator.tech + */ + +#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] +pub struct ConfigApplicationJavaAllOf { + /// Pathname of the application’s .war file (packaged or unpackaged). + #[serde(rename = "webapp")] + pub webapp: String, + /// An array of strings. + #[serde(rename = "classpath", skip_serializing_if = "Option::is_none")] + pub classpath: Option>, + /// An array of strings. + #[serde(rename = "options", skip_serializing_if = "Option::is_none")] + pub options: Option>, + /// Stack size of a worker thread in bytes. + #[serde(rename = "thread_stack_size", skip_serializing_if = "Option::is_none")] + pub thread_stack_size: Option, + /// Number of worker threads per app process. + #[serde(rename = "threads", skip_serializing_if = "Option::is_none")] + pub threads: Option, +} + +impl ConfigApplicationJavaAllOf { + pub fn new(webapp: String) -> ConfigApplicationJavaAllOf { + ConfigApplicationJavaAllOf { + webapp, + classpath: None, + options: None, + thread_stack_size: None, + threads: None, + } + } +} diff --git a/cli/unit-openapi/src/models/config_application_perl.rs b/cli/unit-openapi/src/models/config_application_perl.rs new file mode 100644 index 000000000..acc9dbb79 --- /dev/null +++ b/cli/unit-openapi/src/models/config_application_perl.rs @@ -0,0 +1,95 @@ +/* + * NGINX Unit 1.31.1 + * + * NGINX Unit is a lightweight and versatile application runtime that provides the essential components for your web application as a single open-source server: running application code, serving static assets, handling TLS and request routing. **Important**: Ufnit's API is designed to expose any part of its configuration as an addressable endpoint. Suppose a JSON object is stored at `/config/listeners/`: ```json { \"*:8080\": { \"pass\": \"applications/wp_emea_dev\" } } ``` Here, `/config/listeners/_*:8080` and `/config/listeners/_*:8080/pass` are also endpoints. Generally, object options are addressable by their names, array items—by their indexes (`/array/0/`). **Note**: By default, Unit is configured through a UNIX domain socket. To use this specification with OpenAPI tools interactively, [start](https://unit.nginx.org/howto/source/#source-startup) Unit with a TCP port as the control socket. + * + * The version of the OpenAPI document: 0.2.0 + * Contact: unit-owner@nginx.org + * Generated by: https://openapi-generator.tech + */ + +/// ConfigApplicationPerl : Perl application on Unit. + +#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] +pub struct ConfigApplicationPerl { + /// Application type and language version. + #[serde(rename = "type")] + pub r#type: RHashType, + /// Environment variables to be passed to the app. + #[serde(rename = "environment", skip_serializing_if = "Option::is_none")] + pub environment: Option<::std::collections::HashMap>, + /// Group name that runs the app process. + #[serde(rename = "group", skip_serializing_if = "Option::is_none")] + pub group: Option, + #[serde(rename = "isolation", skip_serializing_if = "Option::is_none")] + pub isolation: Option>, + #[serde(rename = "limits", skip_serializing_if = "Option::is_none")] + pub limits: Option>, + #[serde(rename = "processes", skip_serializing_if = "Option::is_none")] + pub processes: Option>, + /// Username that runs the app process. + #[serde(rename = "user", skip_serializing_if = "Option::is_none")] + pub user: Option, + /// Filename where Unit redirects the app's stderr stream. + #[serde(rename = "stderr", skip_serializing_if = "Option::is_none")] + pub stderr: Option, + /// Filename where Unit redirects the app's stdout stream. + #[serde(rename = "stdout", skip_serializing_if = "Option::is_none")] + pub stdout: Option, + /// The app’s working directory. + #[serde(rename = "working_directory", skip_serializing_if = "Option::is_none")] + pub working_directory: Option, + /// PSGI script path. + #[serde(rename = "script")] + pub script: String, + /// Stack size of a worker thread in bytes. + #[serde(rename = "thread_stack_size", skip_serializing_if = "Option::is_none")] + pub thread_stack_size: Option, + /// Number of worker threads per app process. + #[serde(rename = "threads", skip_serializing_if = "Option::is_none")] + pub threads: Option, +} + +impl ConfigApplicationPerl { + /// Perl application on Unit. + pub fn new(r#type: RHashType, script: String) -> ConfigApplicationPerl { + ConfigApplicationPerl { + r#type, + environment: None, + group: None, + isolation: None, + limits: None, + processes: None, + user: None, + stderr: None, + stdout: None, + working_directory: None, + script, + thread_stack_size: None, + threads: None, + } + } +} + +/// Application type and language version. +#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)] +pub enum RHashType { + #[serde(rename = "external")] + External, + #[serde(rename = "java")] + Java, + #[serde(rename = "perl")] + Perl, + #[serde(rename = "php")] + Php, + #[serde(rename = "python")] + Python, + #[serde(rename = "ruby")] + Ruby, +} + +impl Default for RHashType { + fn default() -> RHashType { + Self::External + } +} diff --git a/cli/unit-openapi/src/models/config_application_perl_all_of.rs b/cli/unit-openapi/src/models/config_application_perl_all_of.rs new file mode 100644 index 000000000..598cf5e8f --- /dev/null +++ b/cli/unit-openapi/src/models/config_application_perl_all_of.rs @@ -0,0 +1,32 @@ +/* + * NGINX Unit 1.31.1 + * + * NGINX Unit is a lightweight and versatile application runtime that provides the essential components for your web application as a single open-source server: running application code, serving static assets, handling TLS and request routing. **Important**: Ufnit's API is designed to expose any part of its configuration as an addressable endpoint. Suppose a JSON object is stored at `/config/listeners/`: ```json { \"*:8080\": { \"pass\": \"applications/wp_emea_dev\" } } ``` Here, `/config/listeners/_*:8080` and `/config/listeners/_*:8080/pass` are also endpoints. Generally, object options are addressable by their names, array items—by their indexes (`/array/0/`). **Note**: By default, Unit is configured through a UNIX domain socket. To use this specification with OpenAPI tools interactively, [start](https://unit.nginx.org/howto/source/#source-startup) Unit with a TCP port as the control socket. + * + * The version of the OpenAPI document: 0.2.0 + * Contact: unit-owner@nginx.org + * Generated by: https://openapi-generator.tech + */ + +#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] +pub struct ConfigApplicationPerlAllOf { + /// PSGI script path. + #[serde(rename = "script")] + pub script: String, + /// Stack size of a worker thread in bytes. + #[serde(rename = "thread_stack_size", skip_serializing_if = "Option::is_none")] + pub thread_stack_size: Option, + /// Number of worker threads per app process. + #[serde(rename = "threads", skip_serializing_if = "Option::is_none")] + pub threads: Option, +} + +impl ConfigApplicationPerlAllOf { + pub fn new(script: String) -> ConfigApplicationPerlAllOf { + ConfigApplicationPerlAllOf { + script, + thread_stack_size: None, + threads: None, + } + } +} diff --git a/cli/unit-openapi/src/models/config_application_php.rs b/cli/unit-openapi/src/models/config_application_php.rs new file mode 100644 index 000000000..63f2802ae --- /dev/null +++ b/cli/unit-openapi/src/models/config_application_php.rs @@ -0,0 +1,102 @@ +/* + * NGINX Unit 1.31.1 + * + * NGINX Unit is a lightweight and versatile application runtime that provides the essential components for your web application as a single open-source server: running application code, serving static assets, handling TLS and request routing. **Important**: Ufnit's API is designed to expose any part of its configuration as an addressable endpoint. Suppose a JSON object is stored at `/config/listeners/`: ```json { \"*:8080\": { \"pass\": \"applications/wp_emea_dev\" } } ``` Here, `/config/listeners/_*:8080` and `/config/listeners/_*:8080/pass` are also endpoints. Generally, object options are addressable by their names, array items—by their indexes (`/array/0/`). **Note**: By default, Unit is configured through a UNIX domain socket. To use this specification with OpenAPI tools interactively, [start](https://unit.nginx.org/howto/source/#source-startup) Unit with a TCP port as the control socket. + * + * The version of the OpenAPI document: 0.2.0 + * Contact: unit-owner@nginx.org + * Generated by: https://openapi-generator.tech + */ + +/// ConfigApplicationPhp : PHP application on Unit. + +#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] +pub struct ConfigApplicationPhp { + /// Application type and language version. + #[serde(rename = "type")] + pub r#type: RHashType, + /// Environment variables to be passed to the app. + #[serde(rename = "environment", skip_serializing_if = "Option::is_none")] + pub environment: Option<::std::collections::HashMap>, + /// Group name that runs the app process. + #[serde(rename = "group", skip_serializing_if = "Option::is_none")] + pub group: Option, + #[serde(rename = "isolation", skip_serializing_if = "Option::is_none")] + pub isolation: Option>, + #[serde(rename = "limits", skip_serializing_if = "Option::is_none")] + pub limits: Option>, + #[serde(rename = "processes", skip_serializing_if = "Option::is_none")] + pub processes: Option>, + /// Username that runs the app process. + #[serde(rename = "user", skip_serializing_if = "Option::is_none")] + pub user: Option, + /// Filename where Unit redirects the app's stderr stream. + #[serde(rename = "stderr", skip_serializing_if = "Option::is_none")] + pub stderr: Option, + /// Filename where Unit redirects the app's stdout stream. + #[serde(rename = "stdout", skip_serializing_if = "Option::is_none")] + pub stdout: Option, + /// The app’s working directory. + #[serde(rename = "working_directory", skip_serializing_if = "Option::is_none")] + pub working_directory: Option, + /// Base directory of the app’s file structure. + #[serde(rename = "root")] + pub root: String, + /// Filename added to URI paths that point to directories if no `script` is set. + #[serde(rename = "index", skip_serializing_if = "Option::is_none")] + pub index: Option, + #[serde(rename = "options", skip_serializing_if = "Option::is_none")] + pub options: Option>, + /// Filename of a `root`-based PHP script that serves all requests to the app. + #[serde(rename = "script", skip_serializing_if = "Option::is_none")] + pub script: Option, + /// Application sections with custom `root`, `script`, and `index` values. + #[serde(rename = "targets", skip_serializing_if = "Option::is_none")] + pub targets: Option<::std::collections::HashMap>, +} + +impl ConfigApplicationPhp { + /// PHP application on Unit. + pub fn new(r#type: RHashType, root: String) -> ConfigApplicationPhp { + ConfigApplicationPhp { + r#type, + environment: None, + group: None, + isolation: None, + limits: None, + processes: None, + user: None, + stderr: None, + stdout: None, + working_directory: None, + root, + index: None, + options: None, + script: None, + targets: None, + } + } +} + +/// Application type and language version. +#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)] +pub enum RHashType { + #[serde(rename = "external")] + External, + #[serde(rename = "java")] + Java, + #[serde(rename = "perl")] + Perl, + #[serde(rename = "php")] + Php, + #[serde(rename = "python")] + Python, + #[serde(rename = "ruby")] + Ruby, +} + +impl Default for RHashType { + fn default() -> RHashType { + Self::External + } +} diff --git a/cli/unit-openapi/src/models/config_application_php_all_of.rs b/cli/unit-openapi/src/models/config_application_php_all_of.rs new file mode 100644 index 000000000..05902b7a3 --- /dev/null +++ b/cli/unit-openapi/src/models/config_application_php_all_of.rs @@ -0,0 +1,39 @@ +/* + * NGINX Unit 1.31.1 + * + * NGINX Unit is a lightweight and versatile application runtime that provides the essential components for your web application as a single open-source server: running application code, serving static assets, handling TLS and request routing. **Important**: Ufnit's API is designed to expose any part of its configuration as an addressable endpoint. Suppose a JSON object is stored at `/config/listeners/`: ```json { \"*:8080\": { \"pass\": \"applications/wp_emea_dev\" } } ``` Here, `/config/listeners/_*:8080` and `/config/listeners/_*:8080/pass` are also endpoints. Generally, object options are addressable by their names, array items—by their indexes (`/array/0/`). **Note**: By default, Unit is configured through a UNIX domain socket. To use this specification with OpenAPI tools interactively, [start](https://unit.nginx.org/howto/source/#source-startup) Unit with a TCP port as the control socket. + * + * The version of the OpenAPI document: 0.2.0 + * Contact: unit-owner@nginx.org + * Generated by: https://openapi-generator.tech + */ + +#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] +pub struct ConfigApplicationPhpAllOf { + /// Base directory of the app’s file structure. + #[serde(rename = "root")] + pub root: String, + /// Filename added to URI paths that point to directories if no `script` is set. + #[serde(rename = "index", skip_serializing_if = "Option::is_none")] + pub index: Option, + #[serde(rename = "options", skip_serializing_if = "Option::is_none")] + pub options: Option>, + /// Filename of a `root`-based PHP script that serves all requests to the app. + #[serde(rename = "script", skip_serializing_if = "Option::is_none")] + pub script: Option, + /// Application sections with custom `root`, `script`, and `index` values. + #[serde(rename = "targets", skip_serializing_if = "Option::is_none")] + pub targets: Option<::std::collections::HashMap>, +} + +impl ConfigApplicationPhpAllOf { + pub fn new(root: String) -> ConfigApplicationPhpAllOf { + ConfigApplicationPhpAllOf { + root, + index: None, + options: None, + script: None, + targets: None, + } + } +} diff --git a/cli/unit-openapi/src/models/config_application_php_all_of_options.rs b/cli/unit-openapi/src/models/config_application_php_all_of_options.rs new file mode 100644 index 000000000..e32bd3523 --- /dev/null +++ b/cli/unit-openapi/src/models/config_application_php_all_of_options.rs @@ -0,0 +1,35 @@ +/* + * NGINX Unit 1.31.1 + * + * NGINX Unit is a lightweight and versatile application runtime that provides the essential components for your web application as a single open-source server: running application code, serving static assets, handling TLS and request routing. **Important**: Ufnit's API is designed to expose any part of its configuration as an addressable endpoint. Suppose a JSON object is stored at `/config/listeners/`: ```json { \"*:8080\": { \"pass\": \"applications/wp_emea_dev\" } } ``` Here, `/config/listeners/_*:8080` and `/config/listeners/_*:8080/pass` are also endpoints. Generally, object options are addressable by their names, array items—by their indexes (`/array/0/`). **Note**: By default, Unit is configured through a UNIX domain socket. To use this specification with OpenAPI tools interactively, [start](https://unit.nginx.org/howto/source/#source-startup) Unit with a TCP port as the control socket. + * + * The version of the OpenAPI document: 0.2.0 + * Contact: unit-owner@nginx.org + * Generated by: https://openapi-generator.tech + */ + +/// ConfigApplicationPhpAllOfOptions : Defines the php.ini location and options. + +#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] +pub struct ConfigApplicationPhpAllOfOptions { + /// Extra directives set in PHP_INI_SYSTEM mode. + #[serde(rename = "admin", skip_serializing_if = "Option::is_none")] + pub admin: Option<::std::collections::HashMap>, + /// Pathname of the php.ini file. + #[serde(rename = "file", skip_serializing_if = "Option::is_none")] + pub file: Option, + /// Extra directives set in PHP_INI_USER mode. + #[serde(rename = "user", skip_serializing_if = "Option::is_none")] + pub user: Option<::std::collections::HashMap>, +} + +impl ConfigApplicationPhpAllOfOptions { + /// Defines the php.ini location and options. + pub fn new() -> ConfigApplicationPhpAllOfOptions { + ConfigApplicationPhpAllOfOptions { + admin: None, + file: None, + user: None, + } + } +} diff --git a/cli/unit-openapi/src/models/config_application_php_all_of_targets.rs b/cli/unit-openapi/src/models/config_application_php_all_of_targets.rs new file mode 100644 index 000000000..0ac3211ac --- /dev/null +++ b/cli/unit-openapi/src/models/config_application_php_all_of_targets.rs @@ -0,0 +1,32 @@ +/* + * NGINX Unit 1.31.1 + * + * NGINX Unit is a lightweight and versatile application runtime that provides the essential components for your web application as a single open-source server: running application code, serving static assets, handling TLS and request routing. **Important**: Ufnit's API is designed to expose any part of its configuration as an addressable endpoint. Suppose a JSON object is stored at `/config/listeners/`: ```json { \"*:8080\": { \"pass\": \"applications/wp_emea_dev\" } } ``` Here, `/config/listeners/_*:8080` and `/config/listeners/_*:8080/pass` are also endpoints. Generally, object options are addressable by their names, array items—by their indexes (`/array/0/`). **Note**: By default, Unit is configured through a UNIX domain socket. To use this specification with OpenAPI tools interactively, [start](https://unit.nginx.org/howto/source/#source-startup) Unit with a TCP port as the control socket. + * + * The version of the OpenAPI document: 0.2.0 + * Contact: unit-owner@nginx.org + * Generated by: https://openapi-generator.tech + */ + +#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] +pub struct ConfigApplicationPhpAllOfTargets { + /// Base directory of the target’s file structure. + #[serde(rename = "root")] + pub root: String, + /// Filename added to URI paths that point to directories if no `script` is set. + #[serde(rename = "index", skip_serializing_if = "Option::is_none")] + pub index: Option, + /// Filename of a `root`-based PHP script that serves all requests to the target. + #[serde(rename = "script", skip_serializing_if = "Option::is_none")] + pub script: Option, +} + +impl ConfigApplicationPhpAllOfTargets { + pub fn new(root: String) -> ConfigApplicationPhpAllOfTargets { + ConfigApplicationPhpAllOfTargets { + root, + index: None, + script: None, + } + } +} diff --git a/cli/unit-openapi/src/models/config_application_python.rs b/cli/unit-openapi/src/models/config_application_python.rs new file mode 100644 index 000000000..791e92320 --- /dev/null +++ b/cli/unit-openapi/src/models/config_application_python.rs @@ -0,0 +1,132 @@ +/* + * NGINX Unit 1.31.1 + * + * NGINX Unit is a lightweight and versatile application runtime that provides the essential components for your web application as a single open-source server: running application code, serving static assets, handling TLS and request routing. **Important**: Ufnit's API is designed to expose any part of its configuration as an addressable endpoint. Suppose a JSON object is stored at `/config/listeners/`: ```json { \"*:8080\": { \"pass\": \"applications/wp_emea_dev\" } } ``` Here, `/config/listeners/_*:8080` and `/config/listeners/_*:8080/pass` are also endpoints. Generally, object options are addressable by their names, array items—by their indexes (`/array/0/`). **Note**: By default, Unit is configured through a UNIX domain socket. To use this specification with OpenAPI tools interactively, [start](https://unit.nginx.org/howto/source/#source-startup) Unit with a TCP port as the control socket. + * + * The version of the OpenAPI document: 0.2.0 + * Contact: unit-owner@nginx.org + * Generated by: https://openapi-generator.tech + */ + +/// ConfigApplicationPython : Python application on Unit. + +#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] +pub struct ConfigApplicationPython { + /// Application type and language version. + #[serde(rename = "type")] + pub r#type: RHashType, + /// Environment variables to be passed to the app. + #[serde(rename = "environment", skip_serializing_if = "Option::is_none")] + pub environment: Option<::std::collections::HashMap>, + /// Group name that runs the app process. + #[serde(rename = "group", skip_serializing_if = "Option::is_none")] + pub group: Option, + #[serde(rename = "isolation", skip_serializing_if = "Option::is_none")] + pub isolation: Option>, + #[serde(rename = "limits", skip_serializing_if = "Option::is_none")] + pub limits: Option>, + #[serde(rename = "processes", skip_serializing_if = "Option::is_none")] + pub processes: Option>, + /// Username that runs the app process. + #[serde(rename = "user", skip_serializing_if = "Option::is_none")] + pub user: Option, + /// Filename where Unit redirects the app's stderr stream. + #[serde(rename = "stderr", skip_serializing_if = "Option::is_none")] + pub stderr: Option, + /// Filename where Unit redirects the app's stdout stream. + #[serde(rename = "stdout", skip_serializing_if = "Option::is_none")] + pub stdout: Option, + /// The app’s working directory. + #[serde(rename = "working_directory", skip_serializing_if = "Option::is_none")] + pub working_directory: Option, + /// App’s module name. + #[serde(rename = "module")] + pub module: String, + /// Name of the `module`-based callable that Unit runs as the app. + #[serde(rename = "callable", skip_serializing_if = "Option::is_none")] + pub callable: Option, + /// Path to the app’s virtual environment, absolute or relative to `working_directory`. + #[serde(rename = "home", skip_serializing_if = "Option::is_none")] + pub home: Option, + #[serde(rename = "path", skip_serializing_if = "Option::is_none")] + pub path: Option>, + /// SCRIPT_NAME context value for WSGI or the root_path context value for ASGI. + #[serde(rename = "prefix", skip_serializing_if = "Option::is_none")] + pub prefix: Option, + /// Hints Unit that the app uses a certain interface. + #[serde(rename = "protocol", skip_serializing_if = "Option::is_none")] + pub protocol: Option, + /// App sections with custom `module` and `callable` values. + #[serde(rename = "targets", skip_serializing_if = "Option::is_none")] + pub targets: Option<::std::collections::HashMap>, + /// Stack size of a worker thread in bytes. + #[serde(rename = "thread_stack_size", skip_serializing_if = "Option::is_none")] + pub thread_stack_size: Option, + /// Number of worker threads per app process. + #[serde(rename = "threads", skip_serializing_if = "Option::is_none")] + pub threads: Option, +} + +impl ConfigApplicationPython { + /// Python application on Unit. + pub fn new(r#type: RHashType, module: String) -> ConfigApplicationPython { + ConfigApplicationPython { + r#type, + environment: None, + group: None, + isolation: None, + limits: None, + processes: None, + user: None, + stderr: None, + stdout: None, + working_directory: None, + module, + callable: None, + home: None, + path: None, + prefix: None, + protocol: None, + targets: None, + thread_stack_size: None, + threads: None, + } + } +} + +/// Application type and language version. +#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)] +pub enum RHashType { + #[serde(rename = "external")] + External, + #[serde(rename = "java")] + Java, + #[serde(rename = "perl")] + Perl, + #[serde(rename = "php")] + Php, + #[serde(rename = "python")] + Python, + #[serde(rename = "ruby")] + Ruby, +} + +impl Default for RHashType { + fn default() -> RHashType { + Self::External + } +} +/// Hints Unit that the app uses a certain interface. +#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)] +pub enum Protocol { + #[serde(rename = "asgi")] + Asgi, + #[serde(rename = "wsgi")] + Wsgi, +} + +impl Default for Protocol { + fn default() -> Protocol { + Self::Asgi + } +} diff --git a/cli/unit-openapi/src/models/config_application_python_all_of.rs b/cli/unit-openapi/src/models/config_application_python_all_of.rs new file mode 100644 index 000000000..9cecf2e32 --- /dev/null +++ b/cli/unit-openapi/src/models/config_application_python_all_of.rs @@ -0,0 +1,70 @@ +/* + * NGINX Unit 1.31.1 + * + * NGINX Unit is a lightweight and versatile application runtime that provides the essential components for your web application as a single open-source server: running application code, serving static assets, handling TLS and request routing. **Important**: Ufnit's API is designed to expose any part of its configuration as an addressable endpoint. Suppose a JSON object is stored at `/config/listeners/`: ```json { \"*:8080\": { \"pass\": \"applications/wp_emea_dev\" } } ``` Here, `/config/listeners/_*:8080` and `/config/listeners/_*:8080/pass` are also endpoints. Generally, object options are addressable by their names, array items—by their indexes (`/array/0/`). **Note**: By default, Unit is configured through a UNIX domain socket. To use this specification with OpenAPI tools interactively, [start](https://unit.nginx.org/howto/source/#source-startup) Unit with a TCP port as the control socket. + * + * The version of the OpenAPI document: 0.2.0 + * Contact: unit-owner@nginx.org + * Generated by: https://openapi-generator.tech + */ + +#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] +pub struct ConfigApplicationPythonAllOf { + /// App’s module name. + #[serde(rename = "module")] + pub module: String, + /// Name of the `module`-based callable that Unit runs as the app. + #[serde(rename = "callable", skip_serializing_if = "Option::is_none")] + pub callable: Option, + /// Path to the app’s virtual environment, absolute or relative to `working_directory`. + #[serde(rename = "home", skip_serializing_if = "Option::is_none")] + pub home: Option, + #[serde(rename = "path", skip_serializing_if = "Option::is_none")] + pub path: Option>, + /// SCRIPT_NAME context value for WSGI or the root_path context value for ASGI. + #[serde(rename = "prefix", skip_serializing_if = "Option::is_none")] + pub prefix: Option, + /// Hints Unit that the app uses a certain interface. + #[serde(rename = "protocol", skip_serializing_if = "Option::is_none")] + pub protocol: Option, + /// App sections with custom `module` and `callable` values. + #[serde(rename = "targets", skip_serializing_if = "Option::is_none")] + pub targets: Option<::std::collections::HashMap>, + /// Stack size of a worker thread in bytes. + #[serde(rename = "thread_stack_size", skip_serializing_if = "Option::is_none")] + pub thread_stack_size: Option, + /// Number of worker threads per app process. + #[serde(rename = "threads", skip_serializing_if = "Option::is_none")] + pub threads: Option, +} + +impl ConfigApplicationPythonAllOf { + pub fn new(module: String) -> ConfigApplicationPythonAllOf { + ConfigApplicationPythonAllOf { + module, + callable: None, + home: None, + path: None, + prefix: None, + protocol: None, + targets: None, + thread_stack_size: None, + threads: None, + } + } +} + +/// Hints Unit that the app uses a certain interface. +#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)] +pub enum Protocol { + #[serde(rename = "asgi")] + Asgi, + #[serde(rename = "wsgi")] + Wsgi, +} + +impl Default for Protocol { + fn default() -> Protocol { + Self::Asgi + } +} diff --git a/cli/unit-openapi/src/models/config_application_python_all_of_path.rs b/cli/unit-openapi/src/models/config_application_python_all_of_path.rs new file mode 100644 index 000000000..70c9d478b --- /dev/null +++ b/cli/unit-openapi/src/models/config_application_python_all_of_path.rs @@ -0,0 +1,21 @@ +/* + * NGINX Unit 1.31.1 + * + * NGINX Unit is a lightweight and versatile application runtime that provides the essential components for your web application as a single open-source server: running application code, serving static assets, handling TLS and request routing. **Important**: Ufnit's API is designed to expose any part of its configuration as an addressable endpoint. Suppose a JSON object is stored at `/config/listeners/`: ```json { \"*:8080\": { \"pass\": \"applications/wp_emea_dev\" } } ``` Here, `/config/listeners/_*:8080` and `/config/listeners/_*:8080/pass` are also endpoints. Generally, object options are addressable by their names, array items—by their indexes (`/array/0/`). **Note**: By default, Unit is configured through a UNIX domain socket. To use this specification with OpenAPI tools interactively, [start](https://unit.nginx.org/howto/source/#source-startup) Unit with a TCP port as the control socket. + * + * The version of the OpenAPI document: 0.2.0 + * Contact: unit-owner@nginx.org + * Generated by: https://openapi-generator.tech + */ + +/// ConfigApplicationPythonAllOfPath : Additional Python module lookup paths. + +#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] +pub struct ConfigApplicationPythonAllOfPath {} + +impl ConfigApplicationPythonAllOfPath { + /// Additional Python module lookup paths. + pub fn new() -> ConfigApplicationPythonAllOfPath { + ConfigApplicationPythonAllOfPath {} + } +} diff --git a/cli/unit-openapi/src/models/config_application_python_all_of_targets.rs b/cli/unit-openapi/src/models/config_application_python_all_of_targets.rs new file mode 100644 index 000000000..ee0dfe069 --- /dev/null +++ b/cli/unit-openapi/src/models/config_application_python_all_of_targets.rs @@ -0,0 +1,32 @@ +/* + * NGINX Unit 1.31.1 + * + * NGINX Unit is a lightweight and versatile application runtime that provides the essential components for your web application as a single open-source server: running application code, serving static assets, handling TLS and request routing. **Important**: Ufnit's API is designed to expose any part of its configuration as an addressable endpoint. Suppose a JSON object is stored at `/config/listeners/`: ```json { \"*:8080\": { \"pass\": \"applications/wp_emea_dev\" } } ``` Here, `/config/listeners/_*:8080` and `/config/listeners/_*:8080/pass` are also endpoints. Generally, object options are addressable by their names, array items—by their indexes (`/array/0/`). **Note**: By default, Unit is configured through a UNIX domain socket. To use this specification with OpenAPI tools interactively, [start](https://unit.nginx.org/howto/source/#source-startup) Unit with a TCP port as the control socket. + * + * The version of the OpenAPI document: 0.2.0 + * Contact: unit-owner@nginx.org + * Generated by: https://openapi-generator.tech + */ + +#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] +pub struct ConfigApplicationPythonAllOfTargets { + /// Target's module name. + #[serde(rename = "module")] + pub module: String, + /// Name of the `module`-based callable that Unit runs as the target. + #[serde(rename = "callable", skip_serializing_if = "Option::is_none")] + pub callable: Option, + /// SCRIPT_NAME context value for WSGI or the root_path context value for ASGI. + #[serde(rename = "prefix", skip_serializing_if = "Option::is_none")] + pub prefix: Option, +} + +impl ConfigApplicationPythonAllOfTargets { + pub fn new(module: String) -> ConfigApplicationPythonAllOfTargets { + ConfigApplicationPythonAllOfTargets { + module, + callable: None, + prefix: None, + } + } +} diff --git a/cli/unit-openapi/src/models/config_application_ruby.rs b/cli/unit-openapi/src/models/config_application_ruby.rs new file mode 100644 index 000000000..98783a443 --- /dev/null +++ b/cli/unit-openapi/src/models/config_application_ruby.rs @@ -0,0 +1,95 @@ +/* + * NGINX Unit 1.31.1 + * + * NGINX Unit is a lightweight and versatile application runtime that provides the essential components for your web application as a single open-source server: running application code, serving static assets, handling TLS and request routing. **Important**: Ufnit's API is designed to expose any part of its configuration as an addressable endpoint. Suppose a JSON object is stored at `/config/listeners/`: ```json { \"*:8080\": { \"pass\": \"applications/wp_emea_dev\" } } ``` Here, `/config/listeners/_*:8080` and `/config/listeners/_*:8080/pass` are also endpoints. Generally, object options are addressable by their names, array items—by their indexes (`/array/0/`). **Note**: By default, Unit is configured through a UNIX domain socket. To use this specification with OpenAPI tools interactively, [start](https://unit.nginx.org/howto/source/#source-startup) Unit with a TCP port as the control socket. + * + * The version of the OpenAPI document: 0.2.0 + * Contact: unit-owner@nginx.org + * Generated by: https://openapi-generator.tech + */ + +/// ConfigApplicationRuby : Ruby application on Unit. + +#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] +pub struct ConfigApplicationRuby { + /// Application type and language version. + #[serde(rename = "type")] + pub r#type: RHashType, + /// Environment variables to be passed to the app. + #[serde(rename = "environment", skip_serializing_if = "Option::is_none")] + pub environment: Option<::std::collections::HashMap>, + /// Group name that runs the app process. + #[serde(rename = "group", skip_serializing_if = "Option::is_none")] + pub group: Option, + #[serde(rename = "isolation", skip_serializing_if = "Option::is_none")] + pub isolation: Option>, + #[serde(rename = "limits", skip_serializing_if = "Option::is_none")] + pub limits: Option>, + #[serde(rename = "processes", skip_serializing_if = "Option::is_none")] + pub processes: Option>, + /// Username that runs the app process. + #[serde(rename = "user", skip_serializing_if = "Option::is_none")] + pub user: Option, + /// Filename where Unit redirects the app's stderr stream. + #[serde(rename = "stderr", skip_serializing_if = "Option::is_none")] + pub stderr: Option, + /// Filename where Unit redirects the app's stdout stream. + #[serde(rename = "stdout", skip_serializing_if = "Option::is_none")] + pub stdout: Option, + /// The app’s working directory. + #[serde(rename = "working_directory", skip_serializing_if = "Option::is_none")] + pub working_directory: Option, + /// Rack script pathname, including the .ru extension. + #[serde(rename = "script")] + pub script: String, + /// Pathname of the .rb file setting the event hooks invoked during the app’s lifecycle. + #[serde(rename = "hooks", skip_serializing_if = "Option::is_none")] + pub hooks: Option, + /// Number of worker threads per app process. + #[serde(rename = "threads", skip_serializing_if = "Option::is_none")] + pub threads: Option, +} + +impl ConfigApplicationRuby { + /// Ruby application on Unit. + pub fn new(r#type: RHashType, script: String) -> ConfigApplicationRuby { + ConfigApplicationRuby { + r#type, + environment: None, + group: None, + isolation: None, + limits: None, + processes: None, + user: None, + stderr: None, + stdout: None, + working_directory: None, + script, + hooks: None, + threads: None, + } + } +} + +/// Application type and language version. +#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)] +pub enum RHashType { + #[serde(rename = "external")] + External, + #[serde(rename = "java")] + Java, + #[serde(rename = "perl")] + Perl, + #[serde(rename = "php")] + Php, + #[serde(rename = "python")] + Python, + #[serde(rename = "ruby")] + Ruby, +} + +impl Default for RHashType { + fn default() -> RHashType { + Self::External + } +} diff --git a/cli/unit-openapi/src/models/config_application_ruby_all_of.rs b/cli/unit-openapi/src/models/config_application_ruby_all_of.rs new file mode 100644 index 000000000..1a8ee8834 --- /dev/null +++ b/cli/unit-openapi/src/models/config_application_ruby_all_of.rs @@ -0,0 +1,32 @@ +/* + * NGINX Unit 1.31.1 + * + * NGINX Unit is a lightweight and versatile application runtime that provides the essential components for your web application as a single open-source server: running application code, serving static assets, handling TLS and request routing. **Important**: Ufnit's API is designed to expose any part of its configuration as an addressable endpoint. Suppose a JSON object is stored at `/config/listeners/`: ```json { \"*:8080\": { \"pass\": \"applications/wp_emea_dev\" } } ``` Here, `/config/listeners/_*:8080` and `/config/listeners/_*:8080/pass` are also endpoints. Generally, object options are addressable by their names, array items—by their indexes (`/array/0/`). **Note**: By default, Unit is configured through a UNIX domain socket. To use this specification with OpenAPI tools interactively, [start](https://unit.nginx.org/howto/source/#source-startup) Unit with a TCP port as the control socket. + * + * The version of the OpenAPI document: 0.2.0 + * Contact: unit-owner@nginx.org + * Generated by: https://openapi-generator.tech + */ + +#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] +pub struct ConfigApplicationRubyAllOf { + /// Rack script pathname, including the .ru extension. + #[serde(rename = "script")] + pub script: String, + /// Pathname of the .rb file setting the event hooks invoked during the app’s lifecycle. + #[serde(rename = "hooks", skip_serializing_if = "Option::is_none")] + pub hooks: Option, + /// Number of worker threads per app process. + #[serde(rename = "threads", skip_serializing_if = "Option::is_none")] + pub threads: Option, +} + +impl ConfigApplicationRubyAllOf { + pub fn new(script: String) -> ConfigApplicationRubyAllOf { + ConfigApplicationRubyAllOf { + script, + hooks: None, + threads: None, + } + } +} diff --git a/cli/unit-openapi/src/models/config_listener.rs b/cli/unit-openapi/src/models/config_listener.rs new file mode 100644 index 000000000..40e0afbaa --- /dev/null +++ b/cli/unit-openapi/src/models/config_listener.rs @@ -0,0 +1,33 @@ +/* + * NGINX Unit 1.31.1 + * + * NGINX Unit is a lightweight and versatile application runtime that provides the essential components for your web application as a single open-source server: running application code, serving static assets, handling TLS and request routing. **Important**: Ufnit's API is designed to expose any part of its configuration as an addressable endpoint. Suppose a JSON object is stored at `/config/listeners/`: ```json { \"*:8080\": { \"pass\": \"applications/wp_emea_dev\" } } ``` Here, `/config/listeners/_*:8080` and `/config/listeners/_*:8080/pass` are also endpoints. Generally, object options are addressable by their names, array items—by their indexes (`/array/0/`). **Note**: By default, Unit is configured through a UNIX domain socket. To use this specification with OpenAPI tools interactively, [start](https://unit.nginx.org/howto/source/#source-startup) Unit with a TCP port as the control socket. + * + * The version of the OpenAPI document: 0.2.0 + * Contact: unit-owner@nginx.org + * Generated by: https://openapi-generator.tech + */ + +/// ConfigListener : An individual listener. + +#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] +pub struct ConfigListener { + #[serde(rename = "tls", skip_serializing_if = "Option::is_none")] + pub tls: Option>, + #[serde(rename = "forwarded", skip_serializing_if = "Option::is_none")] + pub forwarded: Option>, + /// Destination to which the listener passes incoming requests. + #[serde(rename = "pass", skip_serializing_if = "Option::is_none")] + pub pass: Option, +} + +impl ConfigListener { + /// An individual listener. + pub fn new() -> ConfigListener { + ConfigListener { + tls: None, + forwarded: None, + pass: None, + } + } +} diff --git a/cli/unit-openapi/src/models/config_listener_forwarded.rs b/cli/unit-openapi/src/models/config_listener_forwarded.rs new file mode 100644 index 000000000..6b5a09daf --- /dev/null +++ b/cli/unit-openapi/src/models/config_listener_forwarded.rs @@ -0,0 +1,55 @@ +/* + * NGINX Unit 1.31.1 + * + * NGINX Unit is a lightweight and versatile application runtime that provides the essential components for your web application as a single open-source server: running application code, serving static assets, handling TLS and request routing. **Important**: Ufnit's API is designed to expose any part of its configuration as an addressable endpoint. Suppose a JSON object is stored at `/config/listeners/`: ```json { \"*:8080\": { \"pass\": \"applications/wp_emea_dev\" } } ``` Here, `/config/listeners/_*:8080` and `/config/listeners/_*:8080/pass` are also endpoints. Generally, object options are addressable by their names, array items—by their indexes (`/array/0/`). **Note**: By default, Unit is configured through a UNIX domain socket. To use this specification with OpenAPI tools interactively, [start](https://unit.nginx.org/howto/source/#source-startup) Unit with a TCP port as the control socket. + * + * The version of the OpenAPI document: 0.2.0 + * Contact: unit-owner@nginx.org + * Generated by: https://openapi-generator.tech + */ + +/// ConfigListenerForwarded : Configures client IP address and protocol replacement. + +#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] +pub struct ConfigListenerForwarded { + /// Defines the HTTP header fields to expect in the request; uses the `X-Forwarded-For` format. + #[serde(rename = "client_ip", skip_serializing_if = "Option::is_none")] + pub client_ip: Option, + #[serde(rename = "source")] + pub source: Box, + /// Controls how the `client_ip` fields are traversed. + #[serde(rename = "recursive", skip_serializing_if = "Option::is_none")] + pub recursive: Option, + /// Defines the relevant HTTP header field to expect in the request; uses the `X-Forwarded-Proto` format. + #[serde(rename = "protocol", skip_serializing_if = "Option::is_none")] + pub protocol: Option, +} + +impl ConfigListenerForwarded { + /// Configures client IP address and protocol replacement. + pub fn new(source: crate::models::ConfigListenerForwardedSource) -> ConfigListenerForwarded { + ConfigListenerForwarded { + client_ip: None, + source: Box::new(source), + recursive: None, + protocol: None, + } + } +} + +/// Defines the relevant HTTP header field to expect in the request; uses the `X-Forwarded-Proto` format. +#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)] +pub enum Protocol { + #[serde(rename = "http")] + Http, + #[serde(rename = "https")] + Https, + #[serde(rename = "on")] + On, +} + +impl Default for Protocol { + fn default() -> Protocol { + Self::Http + } +} diff --git a/cli/unit-openapi/src/models/config_listener_forwarded_source.rs b/cli/unit-openapi/src/models/config_listener_forwarded_source.rs new file mode 100644 index 000000000..4723da38d --- /dev/null +++ b/cli/unit-openapi/src/models/config_listener_forwarded_source.rs @@ -0,0 +1,21 @@ +/* + * NGINX Unit 1.31.1 + * + * NGINX Unit is a lightweight and versatile application runtime that provides the essential components for your web application as a single open-source server: running application code, serving static assets, handling TLS and request routing. **Important**: Ufnit's API is designed to expose any part of its configuration as an addressable endpoint. Suppose a JSON object is stored at `/config/listeners/`: ```json { \"*:8080\": { \"pass\": \"applications/wp_emea_dev\" } } ``` Here, `/config/listeners/_*:8080` and `/config/listeners/_*:8080/pass` are also endpoints. Generally, object options are addressable by their names, array items—by their indexes (`/array/0/`). **Note**: By default, Unit is configured through a UNIX domain socket. To use this specification with OpenAPI tools interactively, [start](https://unit.nginx.org/howto/source/#source-startup) Unit with a TCP port as the control socket. + * + * The version of the OpenAPI document: 0.2.0 + * Contact: unit-owner@nginx.org + * Generated by: https://openapi-generator.tech + */ + +/// ConfigListenerForwardedSource : Defines address-based patterns for trusted addresses. + +#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] +pub struct ConfigListenerForwardedSource {} + +impl ConfigListenerForwardedSource { + /// Defines address-based patterns for trusted addresses. + pub fn new() -> ConfigListenerForwardedSource { + ConfigListenerForwardedSource {} + } +} diff --git a/cli/unit-openapi/src/models/config_listener_tls.rs b/cli/unit-openapi/src/models/config_listener_tls.rs new file mode 100644 index 000000000..42684b99a --- /dev/null +++ b/cli/unit-openapi/src/models/config_listener_tls.rs @@ -0,0 +1,33 @@ +/* + * NGINX Unit 1.31.1 + * + * NGINX Unit is a lightweight and versatile application runtime that provides the essential components for your web application as a single open-source server: running application code, serving static assets, handling TLS and request routing. **Important**: Ufnit's API is designed to expose any part of its configuration as an addressable endpoint. Suppose a JSON object is stored at `/config/listeners/`: ```json { \"*:8080\": { \"pass\": \"applications/wp_emea_dev\" } } ``` Here, `/config/listeners/_*:8080` and `/config/listeners/_*:8080/pass` are also endpoints. Generally, object options are addressable by their names, array items—by their indexes (`/array/0/`). **Note**: By default, Unit is configured through a UNIX domain socket. To use this specification with OpenAPI tools interactively, [start](https://unit.nginx.org/howto/source/#source-startup) Unit with a TCP port as the control socket. + * + * The version of the OpenAPI document: 0.2.0 + * Contact: unit-owner@nginx.org + * Generated by: https://openapi-generator.tech + */ + +/// ConfigListenerTls : Defines SSL/TLS settings for the listener. + +#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] +pub struct ConfigListenerTls { + /// Defines the SSL configuration commands to be set for the listener. + #[serde(rename = "conf_commands", skip_serializing_if = "Option::is_none")] + pub conf_commands: Option<::std::collections::HashMap>, + #[serde(rename = "session", skip_serializing_if = "Option::is_none")] + pub session: Option>, + #[serde(rename = "certificate")] + pub certificate: Box, +} + +impl ConfigListenerTls { + /// Defines SSL/TLS settings for the listener. + pub fn new(certificate: crate::models::ConfigListenerTlsCertificate) -> ConfigListenerTls { + ConfigListenerTls { + conf_commands: None, + session: None, + certificate: Box::new(certificate), + } + } +} diff --git a/cli/unit-openapi/src/models/config_listener_tls_certificate.rs b/cli/unit-openapi/src/models/config_listener_tls_certificate.rs new file mode 100644 index 000000000..2fd3afda1 --- /dev/null +++ b/cli/unit-openapi/src/models/config_listener_tls_certificate.rs @@ -0,0 +1,21 @@ +/* + * NGINX Unit 1.31.1 + * + * NGINX Unit is a lightweight and versatile application runtime that provides the essential components for your web application as a single open-source server: running application code, serving static assets, handling TLS and request routing. **Important**: Ufnit's API is designed to expose any part of its configuration as an addressable endpoint. Suppose a JSON object is stored at `/config/listeners/`: ```json { \"*:8080\": { \"pass\": \"applications/wp_emea_dev\" } } ``` Here, `/config/listeners/_*:8080` and `/config/listeners/_*:8080/pass` are also endpoints. Generally, object options are addressable by their names, array items—by their indexes (`/array/0/`). **Note**: By default, Unit is configured through a UNIX domain socket. To use this specification with OpenAPI tools interactively, [start](https://unit.nginx.org/howto/source/#source-startup) Unit with a TCP port as the control socket. + * + * The version of the OpenAPI document: 0.2.0 + * Contact: unit-owner@nginx.org + * Generated by: https://openapi-generator.tech + */ + +/// ConfigListenerTlsCertificate : Refers to one or more certificate bundles uploaded earlier. + +#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] +pub struct ConfigListenerTlsCertificate {} + +impl ConfigListenerTlsCertificate { + /// Refers to one or more certificate bundles uploaded earlier. + pub fn new() -> ConfigListenerTlsCertificate { + ConfigListenerTlsCertificate {} + } +} diff --git a/cli/unit-openapi/src/models/config_listener_tls_session.rs b/cli/unit-openapi/src/models/config_listener_tls_session.rs new file mode 100644 index 000000000..af4d822df --- /dev/null +++ b/cli/unit-openapi/src/models/config_listener_tls_session.rs @@ -0,0 +1,34 @@ +/* + * NGINX Unit 1.31.1 + * + * NGINX Unit is a lightweight and versatile application runtime that provides the essential components for your web application as a single open-source server: running application code, serving static assets, handling TLS and request routing. **Important**: Ufnit's API is designed to expose any part of its configuration as an addressable endpoint. Suppose a JSON object is stored at `/config/listeners/`: ```json { \"*:8080\": { \"pass\": \"applications/wp_emea_dev\" } } ``` Here, `/config/listeners/_*:8080` and `/config/listeners/_*:8080/pass` are also endpoints. Generally, object options are addressable by their names, array items—by their indexes (`/array/0/`). **Note**: By default, Unit is configured through a UNIX domain socket. To use this specification with OpenAPI tools interactively, [start](https://unit.nginx.org/howto/source/#source-startup) Unit with a TCP port as the control socket. + * + * The version of the OpenAPI document: 0.2.0 + * Contact: unit-owner@nginx.org + * Generated by: https://openapi-generator.tech + */ + +/// ConfigListenerTlsSession : Configures the TLS session cache and tickets for the listener. + +#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] +pub struct ConfigListenerTlsSession { + /// Number of sessions in the TLS session cache. + #[serde(rename = "cache_size", skip_serializing_if = "Option::is_none")] + pub cache_size: Option, + /// Session timeout for the TLS session cache in seconds. + #[serde(rename = "timeout", skip_serializing_if = "Option::is_none")] + pub timeout: Option, + #[serde(rename = "tickets", skip_serializing_if = "Option::is_none")] + pub tickets: Option>, +} + +impl ConfigListenerTlsSession { + /// Configures the TLS session cache and tickets for the listener. + pub fn new() -> ConfigListenerTlsSession { + ConfigListenerTlsSession { + cache_size: None, + timeout: None, + tickets: None, + } + } +} diff --git a/cli/unit-openapi/src/models/config_listener_tls_session_tickets.rs b/cli/unit-openapi/src/models/config_listener_tls_session_tickets.rs new file mode 100644 index 000000000..396375348 --- /dev/null +++ b/cli/unit-openapi/src/models/config_listener_tls_session_tickets.rs @@ -0,0 +1,21 @@ +/* + * NGINX Unit 1.31.1 + * + * NGINX Unit is a lightweight and versatile application runtime that provides the essential components for your web application as a single open-source server: running application code, serving static assets, handling TLS and request routing. **Important**: Ufnit's API is designed to expose any part of its configuration as an addressable endpoint. Suppose a JSON object is stored at `/config/listeners/`: ```json { \"*:8080\": { \"pass\": \"applications/wp_emea_dev\" } } ``` Here, `/config/listeners/_*:8080` and `/config/listeners/_*:8080/pass` are also endpoints. Generally, object options are addressable by their names, array items—by their indexes (`/array/0/`). **Note**: By default, Unit is configured through a UNIX domain socket. To use this specification with OpenAPI tools interactively, [start](https://unit.nginx.org/howto/source/#source-startup) Unit with a TCP port as the control socket. + * + * The version of the OpenAPI document: 0.2.0 + * Contact: unit-owner@nginx.org + * Generated by: https://openapi-generator.tech + */ + +/// ConfigListenerTlsSessionTickets : Configures TLS session tickets. + +#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] +pub struct ConfigListenerTlsSessionTickets {} + +impl ConfigListenerTlsSessionTickets { + /// Configures TLS session tickets. + pub fn new() -> ConfigListenerTlsSessionTickets { + ConfigListenerTlsSessionTickets {} + } +} diff --git a/cli/unit-openapi/src/models/config_route_step.rs b/cli/unit-openapi/src/models/config_route_step.rs new file mode 100644 index 000000000..18e03fd15 --- /dev/null +++ b/cli/unit-openapi/src/models/config_route_step.rs @@ -0,0 +1,29 @@ +/* + * NGINX Unit 1.31.1 + * + * NGINX Unit is a lightweight and versatile application runtime that provides the essential components for your web application as a single open-source server: running application code, serving static assets, handling TLS and request routing. **Important**: Ufnit's API is designed to expose any part of its configuration as an addressable endpoint. Suppose a JSON object is stored at `/config/listeners/`: ```json { \"*:8080\": { \"pass\": \"applications/wp_emea_dev\" } } ``` Here, `/config/listeners/_*:8080` and `/config/listeners/_*:8080/pass` are also endpoints. Generally, object options are addressable by their names, array items—by their indexes (`/array/0/`). **Note**: By default, Unit is configured through a UNIX domain socket. To use this specification with OpenAPI tools interactively, [start](https://unit.nginx.org/howto/source/#source-startup) Unit with a TCP port as the control socket. + * + * The version of the OpenAPI document: 0.2.0 + * Contact: unit-owner@nginx.org + * Generated by: https://openapi-generator.tech + */ + +/// ConfigRouteStep : An object whose options define a step's conditions and action. + +#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] +pub struct ConfigRouteStep { + #[serde(rename = "action")] + pub action: Box, + #[serde(rename = "match", skip_serializing_if = "Option::is_none")] + pub r#match: Option>, +} + +impl ConfigRouteStep { + /// An object whose options define a step's conditions and action. + pub fn new(action: crate::models::ConfigRouteStepAction) -> ConfigRouteStep { + ConfigRouteStep { + action: Box::new(action), + r#match: None, + } + } +} diff --git a/cli/unit-openapi/src/models/config_route_step_action.rs b/cli/unit-openapi/src/models/config_route_step_action.rs new file mode 100644 index 000000000..d8dfb7692 --- /dev/null +++ b/cli/unit-openapi/src/models/config_route_step_action.rs @@ -0,0 +1,78 @@ +/* + * NGINX Unit 1.31.1 + * + * NGINX Unit is a lightweight and versatile application runtime that provides the essential components for your web application as a single open-source server: running application code, serving static assets, handling TLS and request routing. **Important**: Ufnit's API is designed to expose any part of its configuration as an addressable endpoint. Suppose a JSON object is stored at `/config/listeners/`: ```json { \"*:8080\": { \"pass\": \"applications/wp_emea_dev\" } } ``` Here, `/config/listeners/_*:8080` and `/config/listeners/_*:8080/pass` are also endpoints. Generally, object options are addressable by their names, array items—by their indexes (`/array/0/`). **Note**: By default, Unit is configured through a UNIX domain socket. To use this specification with OpenAPI tools interactively, [start](https://unit.nginx.org/howto/source/#source-startup) Unit with a TCP port as the control socket. + * + * The version of the OpenAPI document: 0.2.0 + * Contact: unit-owner@nginx.org + * Generated by: https://openapi-generator.tech + */ + +/// ConfigRouteStepAction : An object whose options define a step's action. + +#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] +pub struct ConfigRouteStepAction { + /// Destination to which the action passes incoming requests. + #[serde(rename = "pass")] + pub pass: String, + /// Updates the URI of the incoming request before the action is applied. + #[serde(rename = "rewrite", skip_serializing_if = "Option::is_none")] + pub rewrite: Option, + /// Updates the header fields of Unit’s response before the action is taken. + #[serde(rename = "response_headers", skip_serializing_if = "Option::is_none")] + pub response_headers: Option<::std::collections::HashMap>, + /// Socket address of an HTTP server to where the request is proxied. + #[serde(rename = "proxy")] + pub proxy: String, + /// Defines the HTTP response status code to be returned. + #[serde(rename = "return")] + pub r#return: i32, + /// URI; used if the return value implies redirection. + #[serde(rename = "location", skip_serializing_if = "Option::is_none")] + pub location: Option, + #[serde(rename = "share")] + pub share: Box, + /// Filename; tried if share is a directory. + #[serde(rename = "index", skip_serializing_if = "Option::is_none")] + pub index: Option, + #[serde(rename = "fallback", skip_serializing_if = "Option::is_none")] + pub fallback: Option>, + /// An array of strings. + #[serde(rename = "types", skip_serializing_if = "Option::is_none")] + pub types: Option>, + /// Directory pathname that restricts the shareable paths. + #[serde(rename = "chroot", skip_serializing_if = "Option::is_none")] + pub chroot: Option, + /// Turns on and off symbolic link resolution. + #[serde(rename = "follow_symlinks", skip_serializing_if = "Option::is_none")] + pub follow_symlinks: Option, + /// Turns on and off mount point resolution. + #[serde(rename = "traverse_mounts", skip_serializing_if = "Option::is_none")] + pub traverse_mounts: Option, +} + +impl ConfigRouteStepAction { + /// An object whose options define a step's action. + pub fn new( + pass: String, + proxy: String, + r#return: i32, + share: crate::models::StringOrStringArray, + ) -> ConfigRouteStepAction { + ConfigRouteStepAction { + pass, + rewrite: None, + response_headers: None, + proxy, + r#return, + location: None, + share: Box::new(share), + index: None, + fallback: None, + types: None, + chroot: None, + follow_symlinks: None, + traverse_mounts: None, + } + } +} diff --git a/cli/unit-openapi/src/models/config_route_step_action_pass.rs b/cli/unit-openapi/src/models/config_route_step_action_pass.rs new file mode 100644 index 000000000..eb5b56e81 --- /dev/null +++ b/cli/unit-openapi/src/models/config_route_step_action_pass.rs @@ -0,0 +1,35 @@ +/* + * NGINX Unit 1.31.1 + * + * NGINX Unit is a lightweight and versatile application runtime that provides the essential components for your web application as a single open-source server: running application code, serving static assets, handling TLS and request routing. **Important**: Ufnit's API is designed to expose any part of its configuration as an addressable endpoint. Suppose a JSON object is stored at `/config/listeners/`: ```json { \"*:8080\": { \"pass\": \"applications/wp_emea_dev\" } } ``` Here, `/config/listeners/_*:8080` and `/config/listeners/_*:8080/pass` are also endpoints. Generally, object options are addressable by their names, array items—by their indexes (`/array/0/`). **Note**: By default, Unit is configured through a UNIX domain socket. To use this specification with OpenAPI tools interactively, [start](https://unit.nginx.org/howto/source/#source-startup) Unit with a TCP port as the control socket. + * + * The version of the OpenAPI document: 0.2.0 + * Contact: unit-owner@nginx.org + * Generated by: https://openapi-generator.tech + */ + +/// ConfigRouteStepActionPass : An object whose single option defines a step's pass action. + +#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] +pub struct ConfigRouteStepActionPass { + /// Destination to which the action passes incoming requests. + #[serde(rename = "pass")] + pub pass: String, + /// Updates the URI of the incoming request before the action is applied. + #[serde(rename = "rewrite", skip_serializing_if = "Option::is_none")] + pub rewrite: Option, + /// Updates the header fields of Unit’s response before the action is taken. + #[serde(rename = "response_headers", skip_serializing_if = "Option::is_none")] + pub response_headers: Option<::std::collections::HashMap>, +} + +impl ConfigRouteStepActionPass { + /// An object whose single option defines a step's pass action. + pub fn new(pass: String) -> ConfigRouteStepActionPass { + ConfigRouteStepActionPass { + pass, + rewrite: None, + response_headers: None, + } + } +} diff --git a/cli/unit-openapi/src/models/config_route_step_action_proxy.rs b/cli/unit-openapi/src/models/config_route_step_action_proxy.rs new file mode 100644 index 000000000..ede81f05a --- /dev/null +++ b/cli/unit-openapi/src/models/config_route_step_action_proxy.rs @@ -0,0 +1,35 @@ +/* + * NGINX Unit 1.31.1 + * + * NGINX Unit is a lightweight and versatile application runtime that provides the essential components for your web application as a single open-source server: running application code, serving static assets, handling TLS and request routing. **Important**: Ufnit's API is designed to expose any part of its configuration as an addressable endpoint. Suppose a JSON object is stored at `/config/listeners/`: ```json { \"*:8080\": { \"pass\": \"applications/wp_emea_dev\" } } ``` Here, `/config/listeners/_*:8080` and `/config/listeners/_*:8080/pass` are also endpoints. Generally, object options are addressable by their names, array items—by their indexes (`/array/0/`). **Note**: By default, Unit is configured through a UNIX domain socket. To use this specification with OpenAPI tools interactively, [start](https://unit.nginx.org/howto/source/#source-startup) Unit with a TCP port as the control socket. + * + * The version of the OpenAPI document: 0.2.0 + * Contact: unit-owner@nginx.org + * Generated by: https://openapi-generator.tech + */ + +/// ConfigRouteStepActionProxy : An object whose single option defines a step's proxy action. + +#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] +pub struct ConfigRouteStepActionProxy { + /// Socket address of an HTTP server to where the request is proxied. + #[serde(rename = "proxy")] + pub proxy: String, + /// Updates the URI of the incoming request before the action is applied. + #[serde(rename = "rewrite", skip_serializing_if = "Option::is_none")] + pub rewrite: Option, + /// Updates the header fields of Unit’s response before the action is taken. + #[serde(rename = "response_headers", skip_serializing_if = "Option::is_none")] + pub response_headers: Option<::std::collections::HashMap>, +} + +impl ConfigRouteStepActionProxy { + /// An object whose single option defines a step's proxy action. + pub fn new(proxy: String) -> ConfigRouteStepActionProxy { + ConfigRouteStepActionProxy { + proxy, + rewrite: None, + response_headers: None, + } + } +} diff --git a/cli/unit-openapi/src/models/config_route_step_action_return.rs b/cli/unit-openapi/src/models/config_route_step_action_return.rs new file mode 100644 index 000000000..b0de60e65 --- /dev/null +++ b/cli/unit-openapi/src/models/config_route_step_action_return.rs @@ -0,0 +1,39 @@ +/* + * NGINX Unit 1.31.1 + * + * NGINX Unit is a lightweight and versatile application runtime that provides the essential components for your web application as a single open-source server: running application code, serving static assets, handling TLS and request routing. **Important**: Ufnit's API is designed to expose any part of its configuration as an addressable endpoint. Suppose a JSON object is stored at `/config/listeners/`: ```json { \"*:8080\": { \"pass\": \"applications/wp_emea_dev\" } } ``` Here, `/config/listeners/_*:8080` and `/config/listeners/_*:8080/pass` are also endpoints. Generally, object options are addressable by their names, array items—by their indexes (`/array/0/`). **Note**: By default, Unit is configured through a UNIX domain socket. To use this specification with OpenAPI tools interactively, [start](https://unit.nginx.org/howto/source/#source-startup) Unit with a TCP port as the control socket. + * + * The version of the OpenAPI document: 0.2.0 + * Contact: unit-owner@nginx.org + * Generated by: https://openapi-generator.tech + */ + +/// ConfigRouteStepActionReturn : An object whose single option defines a step's return action. + +#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] +pub struct ConfigRouteStepActionReturn { + /// Defines the HTTP response status code to be returned. + #[serde(rename = "return")] + pub r#return: i32, + /// URI; used if the return value implies redirection. + #[serde(rename = "location", skip_serializing_if = "Option::is_none")] + pub location: Option, + /// Updates the URI of the incoming request before the action is applied. + #[serde(rename = "rewrite", skip_serializing_if = "Option::is_none")] + pub rewrite: Option, + /// Updates the header fields of Unit’s response before the action is taken. + #[serde(rename = "response_headers", skip_serializing_if = "Option::is_none")] + pub response_headers: Option<::std::collections::HashMap>, +} + +impl ConfigRouteStepActionReturn { + /// An object whose single option defines a step's return action. + pub fn new(r#return: i32) -> ConfigRouteStepActionReturn { + ConfigRouteStepActionReturn { + r#return, + location: None, + rewrite: None, + response_headers: None, + } + } +} diff --git a/cli/unit-openapi/src/models/config_route_step_action_share.rs b/cli/unit-openapi/src/models/config_route_step_action_share.rs new file mode 100644 index 000000000..59cd52892 --- /dev/null +++ b/cli/unit-openapi/src/models/config_route_step_action_share.rs @@ -0,0 +1,57 @@ +/* + * NGINX Unit 1.31.1 + * + * NGINX Unit is a lightweight and versatile application runtime that provides the essential components for your web application as a single open-source server: running application code, serving static assets, handling TLS and request routing. **Important**: Ufnit's API is designed to expose any part of its configuration as an addressable endpoint. Suppose a JSON object is stored at `/config/listeners/`: ```json { \"*:8080\": { \"pass\": \"applications/wp_emea_dev\" } } ``` Here, `/config/listeners/_*:8080` and `/config/listeners/_*:8080/pass` are also endpoints. Generally, object options are addressable by their names, array items—by their indexes (`/array/0/`). **Note**: By default, Unit is configured through a UNIX domain socket. To use this specification with OpenAPI tools interactively, [start](https://unit.nginx.org/howto/source/#source-startup) Unit with a TCP port as the control socket. + * + * The version of the OpenAPI document: 0.2.0 + * Contact: unit-owner@nginx.org + * Generated by: https://openapi-generator.tech + */ + +/// ConfigRouteStepActionShare : An object whose single option defines a step's share action. + +#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] +pub struct ConfigRouteStepActionShare { + #[serde(rename = "share")] + pub share: Box, + /// Filename; tried if share is a directory. + #[serde(rename = "index", skip_serializing_if = "Option::is_none")] + pub index: Option, + #[serde(rename = "fallback", skip_serializing_if = "Option::is_none")] + pub fallback: Option>, + /// An array of strings. + #[serde(rename = "types", skip_serializing_if = "Option::is_none")] + pub types: Option>, + /// Directory pathname that restricts the shareable paths. + #[serde(rename = "chroot", skip_serializing_if = "Option::is_none")] + pub chroot: Option, + /// Turns on and off symbolic link resolution. + #[serde(rename = "follow_symlinks", skip_serializing_if = "Option::is_none")] + pub follow_symlinks: Option, + /// Turns on and off mount point resolution. + #[serde(rename = "traverse_mounts", skip_serializing_if = "Option::is_none")] + pub traverse_mounts: Option, + /// Updates the URI of the incoming request before the action is applied. + #[serde(rename = "rewrite", skip_serializing_if = "Option::is_none")] + pub rewrite: Option, + /// Updates the header fields of Unit’s response before the action is taken. + #[serde(rename = "response_headers", skip_serializing_if = "Option::is_none")] + pub response_headers: Option<::std::collections::HashMap>, +} + +impl ConfigRouteStepActionShare { + /// An object whose single option defines a step's share action. + pub fn new(share: crate::models::StringOrStringArray) -> ConfigRouteStepActionShare { + ConfigRouteStepActionShare { + share: Box::new(share), + index: None, + fallback: None, + types: None, + chroot: None, + follow_symlinks: None, + traverse_mounts: None, + rewrite: None, + response_headers: None, + } + } +} diff --git a/cli/unit-openapi/src/models/config_route_step_match.rs b/cli/unit-openapi/src/models/config_route_step_match.rs new file mode 100644 index 000000000..5b8108ab8 --- /dev/null +++ b/cli/unit-openapi/src/models/config_route_step_match.rs @@ -0,0 +1,69 @@ +/* + * NGINX Unit 1.31.1 + * + * NGINX Unit is a lightweight and versatile application runtime that provides the essential components for your web application as a single open-source server: running application code, serving static assets, handling TLS and request routing. **Important**: Ufnit's API is designed to expose any part of its configuration as an addressable endpoint. Suppose a JSON object is stored at `/config/listeners/`: ```json { \"*:8080\": { \"pass\": \"applications/wp_emea_dev\" } } ``` Here, `/config/listeners/_*:8080` and `/config/listeners/_*:8080/pass` are also endpoints. Generally, object options are addressable by their names, array items—by their indexes (`/array/0/`). **Note**: By default, Unit is configured through a UNIX domain socket. To use this specification with OpenAPI tools interactively, [start](https://unit.nginx.org/howto/source/#source-startup) Unit with a TCP port as the control socket. + * + * The version of the OpenAPI document: 0.2.0 + * Contact: unit-owner@nginx.org + * Generated by: https://openapi-generator.tech + */ + +/// ConfigRouteStepMatch : An object whose options define a step's conditions. + +#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] +pub struct ConfigRouteStepMatch { + #[serde(rename = "arguments", skip_serializing_if = "Option::is_none")] + pub arguments: Option>, + #[serde(rename = "cookies", skip_serializing_if = "Option::is_none")] + pub cookies: Option>, + #[serde(rename = "destination", skip_serializing_if = "Option::is_none")] + pub destination: Option>, + #[serde(rename = "headers", skip_serializing_if = "Option::is_none")] + pub headers: Option>, + #[serde(rename = "host", skip_serializing_if = "Option::is_none")] + pub host: Option>, + #[serde(rename = "method", skip_serializing_if = "Option::is_none")] + pub method: Option>, + #[serde(rename = "query", skip_serializing_if = "Option::is_none")] + pub query: Option>, + /// URI scheme. Accepts only two patterns, either `http` or `https`. + #[serde(rename = "scheme", skip_serializing_if = "Option::is_none")] + pub scheme: Option, + #[serde(rename = "source", skip_serializing_if = "Option::is_none")] + pub source: Option>, + #[serde(rename = "uri", skip_serializing_if = "Option::is_none")] + pub uri: Option>, +} + +impl ConfigRouteStepMatch { + /// An object whose options define a step's conditions. + pub fn new() -> ConfigRouteStepMatch { + ConfigRouteStepMatch { + arguments: None, + cookies: None, + destination: None, + headers: None, + host: None, + method: None, + query: None, + scheme: None, + source: None, + uri: None, + } + } +} + +/// URI scheme. Accepts only two patterns, either `http` or `https`. +#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)] +pub enum Scheme { + #[serde(rename = "http")] + Http, + #[serde(rename = "https")] + Https, +} + +impl Default for Scheme { + fn default() -> Scheme { + Self::Http + } +} diff --git a/cli/unit-openapi/src/models/config_route_step_match_arguments.rs b/cli/unit-openapi/src/models/config_route_step_match_arguments.rs new file mode 100644 index 000000000..df1e8f62d --- /dev/null +++ b/cli/unit-openapi/src/models/config_route_step_match_arguments.rs @@ -0,0 +1,21 @@ +/* + * NGINX Unit 1.31.1 + * + * NGINX Unit is a lightweight and versatile application runtime that provides the essential components for your web application as a single open-source server: running application code, serving static assets, handling TLS and request routing. **Important**: Ufnit's API is designed to expose any part of its configuration as an addressable endpoint. Suppose a JSON object is stored at `/config/listeners/`: ```json { \"*:8080\": { \"pass\": \"applications/wp_emea_dev\" } } ``` Here, `/config/listeners/_*:8080` and `/config/listeners/_*:8080/pass` are also endpoints. Generally, object options are addressable by their names, array items—by their indexes (`/array/0/`). **Note**: By default, Unit is configured through a UNIX domain socket. To use this specification with OpenAPI tools interactively, [start](https://unit.nginx.org/howto/source/#source-startup) Unit with a TCP port as the control socket. + * + * The version of the OpenAPI document: 0.2.0 + * Contact: unit-owner@nginx.org + * Generated by: https://openapi-generator.tech + */ + +/// ConfigRouteStepMatchArguments : Arguments supplied with the request’s query string. + +#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] +pub struct ConfigRouteStepMatchArguments {} + +impl ConfigRouteStepMatchArguments { + /// Arguments supplied with the request’s query string. + pub fn new() -> ConfigRouteStepMatchArguments { + ConfigRouteStepMatchArguments {} + } +} diff --git a/cli/unit-openapi/src/models/config_route_step_match_cookies.rs b/cli/unit-openapi/src/models/config_route_step_match_cookies.rs new file mode 100644 index 000000000..ee79ae845 --- /dev/null +++ b/cli/unit-openapi/src/models/config_route_step_match_cookies.rs @@ -0,0 +1,21 @@ +/* + * NGINX Unit 1.31.1 + * + * NGINX Unit is a lightweight and versatile application runtime that provides the essential components for your web application as a single open-source server: running application code, serving static assets, handling TLS and request routing. **Important**: Ufnit's API is designed to expose any part of its configuration as an addressable endpoint. Suppose a JSON object is stored at `/config/listeners/`: ```json { \"*:8080\": { \"pass\": \"applications/wp_emea_dev\" } } ``` Here, `/config/listeners/_*:8080` and `/config/listeners/_*:8080/pass` are also endpoints. Generally, object options are addressable by their names, array items—by their indexes (`/array/0/`). **Note**: By default, Unit is configured through a UNIX domain socket. To use this specification with OpenAPI tools interactively, [start](https://unit.nginx.org/howto/source/#source-startup) Unit with a TCP port as the control socket. + * + * The version of the OpenAPI document: 0.2.0 + * Contact: unit-owner@nginx.org + * Generated by: https://openapi-generator.tech + */ + +/// ConfigRouteStepMatchCookies : Cookies supplied with the request. + +#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] +pub struct ConfigRouteStepMatchCookies {} + +impl ConfigRouteStepMatchCookies { + /// Cookies supplied with the request. + pub fn new() -> ConfigRouteStepMatchCookies { + ConfigRouteStepMatchCookies {} + } +} diff --git a/cli/unit-openapi/src/models/config_route_step_match_headers.rs b/cli/unit-openapi/src/models/config_route_step_match_headers.rs new file mode 100644 index 000000000..afc89979b --- /dev/null +++ b/cli/unit-openapi/src/models/config_route_step_match_headers.rs @@ -0,0 +1,21 @@ +/* + * NGINX Unit 1.31.1 + * + * NGINX Unit is a lightweight and versatile application runtime that provides the essential components for your web application as a single open-source server: running application code, serving static assets, handling TLS and request routing. **Important**: Ufnit's API is designed to expose any part of its configuration as an addressable endpoint. Suppose a JSON object is stored at `/config/listeners/`: ```json { \"*:8080\": { \"pass\": \"applications/wp_emea_dev\" } } ``` Here, `/config/listeners/_*:8080` and `/config/listeners/_*:8080/pass` are also endpoints. Generally, object options are addressable by their names, array items—by their indexes (`/array/0/`). **Note**: By default, Unit is configured through a UNIX domain socket. To use this specification with OpenAPI tools interactively, [start](https://unit.nginx.org/howto/source/#source-startup) Unit with a TCP port as the control socket. + * + * The version of the OpenAPI document: 0.2.0 + * Contact: unit-owner@nginx.org + * Generated by: https://openapi-generator.tech + */ + +/// ConfigRouteStepMatchHeaders : Header fields supplied with the request. + +#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] +pub struct ConfigRouteStepMatchHeaders {} + +impl ConfigRouteStepMatchHeaders { + /// Header fields supplied with the request. + pub fn new() -> ConfigRouteStepMatchHeaders { + ConfigRouteStepMatchHeaders {} + } +} diff --git a/cli/unit-openapi/src/models/config_routes.rs b/cli/unit-openapi/src/models/config_routes.rs new file mode 100644 index 000000000..319a187d8 --- /dev/null +++ b/cli/unit-openapi/src/models/config_routes.rs @@ -0,0 +1,21 @@ +/* + * NGINX Unit 1.31.1 + * + * NGINX Unit is a lightweight and versatile application runtime that provides the essential components for your web application as a single open-source server: running application code, serving static assets, handling TLS and request routing. **Important**: Ufnit's API is designed to expose any part of its configuration as an addressable endpoint. Suppose a JSON object is stored at `/config/listeners/`: ```json { \"*:8080\": { \"pass\": \"applications/wp_emea_dev\" } } ``` Here, `/config/listeners/_*:8080` and `/config/listeners/_*:8080/pass` are also endpoints. Generally, object options are addressable by their names, array items—by their indexes (`/array/0/`). **Note**: By default, Unit is configured through a UNIX domain socket. To use this specification with OpenAPI tools interactively, [start](https://unit.nginx.org/howto/source/#source-startup) Unit with a TCP port as the control socket. + * + * The version of the OpenAPI document: 0.2.0 + * Contact: unit-owner@nginx.org + * Generated by: https://openapi-generator.tech + */ + +/// ConfigRoutes : Configures the routes. + +#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] +pub struct ConfigRoutes {} + +impl ConfigRoutes { + /// Configures the routes. + pub fn new() -> ConfigRoutes { + ConfigRoutes {} + } +} diff --git a/cli/unit-openapi/src/models/config_settings.rs b/cli/unit-openapi/src/models/config_settings.rs new file mode 100644 index 000000000..c86df1a80 --- /dev/null +++ b/cli/unit-openapi/src/models/config_settings.rs @@ -0,0 +1,24 @@ +/* + * NGINX Unit 1.31.1 + * + * NGINX Unit is a lightweight and versatile application runtime that provides the essential components for your web application as a single open-source server: running application code, serving static assets, handling TLS and request routing. **Important**: Ufnit's API is designed to expose any part of its configuration as an addressable endpoint. Suppose a JSON object is stored at `/config/listeners/`: ```json { \"*:8080\": { \"pass\": \"applications/wp_emea_dev\" } } ``` Here, `/config/listeners/_*:8080` and `/config/listeners/_*:8080/pass` are also endpoints. Generally, object options are addressable by their names, array items—by their indexes (`/array/0/`). **Note**: By default, Unit is configured through a UNIX domain socket. To use this specification with OpenAPI tools interactively, [start](https://unit.nginx.org/howto/source/#source-startup) Unit with a TCP port as the control socket. + * + * The version of the OpenAPI document: 0.2.0 + * Contact: unit-owner@nginx.org + * Generated by: https://openapi-generator.tech + */ + +/// ConfigSettings : An object whose single option represents global Unit settings. + +#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] +pub struct ConfigSettings { + #[serde(rename = "http", skip_serializing_if = "Option::is_none")] + pub http: Option>, +} + +impl ConfigSettings { + /// An object whose single option represents global Unit settings. + pub fn new() -> ConfigSettings { + ConfigSettings { http: None } + } +} diff --git a/cli/unit-openapi/src/models/config_settings_http.rs b/cli/unit-openapi/src/models/config_settings_http.rs new file mode 100644 index 000000000..0a987d079 --- /dev/null +++ b/cli/unit-openapi/src/models/config_settings_http.rs @@ -0,0 +1,58 @@ +/* + * NGINX Unit 1.31.1 + * + * NGINX Unit is a lightweight and versatile application runtime that provides the essential components for your web application as a single open-source server: running application code, serving static assets, handling TLS and request routing. **Important**: Ufnit's API is designed to expose any part of its configuration as an addressable endpoint. Suppose a JSON object is stored at `/config/listeners/`: ```json { \"*:8080\": { \"pass\": \"applications/wp_emea_dev\" } } ``` Here, `/config/listeners/_*:8080` and `/config/listeners/_*:8080/pass` are also endpoints. Generally, object options are addressable by their names, array items—by their indexes (`/array/0/`). **Note**: By default, Unit is configured through a UNIX domain socket. To use this specification with OpenAPI tools interactively, [start](https://unit.nginx.org/howto/source/#source-startup) Unit with a TCP port as the control socket. + * + * The version of the OpenAPI document: 0.2.0 + * Contact: unit-owner@nginx.org + * Generated by: https://openapi-generator.tech + */ + +/// ConfigSettingsHttp : An object whose options represent global HTTP settings in Unit. + +#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] +pub struct ConfigSettingsHttp { + /// Maximum number of seconds to read data from the body of a client’s request. + #[serde(rename = "body_read_timeout", skip_serializing_if = "Option::is_none")] + pub body_read_timeout: Option, + /// If `true`, Unit only processes header names made of alphanumerics and hyphens. + #[serde(rename = "discard_unsafe_fields", skip_serializing_if = "Option::is_none")] + pub discard_unsafe_fields: Option, + /// Maximum number of seconds to read the header of a client’s request. + #[serde(rename = "header_read_timeout", skip_serializing_if = "Option::is_none")] + pub header_read_timeout: Option, + /// Maximum number of seconds between requests in a keep-alive connection. + #[serde(rename = "idle_timeout", skip_serializing_if = "Option::is_none")] + pub idle_timeout: Option, + /// Enables or disables router logging. + #[serde(rename = "log_route", skip_serializing_if = "Option::is_none")] + pub log_route: Option, + /// Maximum number of bytes in the body of a client’s request. + #[serde(rename = "max_body_size", skip_serializing_if = "Option::is_none")] + pub max_body_size: Option, + /// Maximum number of seconds to transmit data as a response to the client. + #[serde(rename = "send_timeout", skip_serializing_if = "Option::is_none")] + pub send_timeout: Option, + /// Enables or disables version numbers in Unit's `Server` header fields. + #[serde(rename = "server_version", skip_serializing_if = "Option::is_none")] + pub server_version: Option, + #[serde(rename = "static", skip_serializing_if = "Option::is_none")] + pub r#static: Option>, +} + +impl ConfigSettingsHttp { + /// An object whose options represent global HTTP settings in Unit. + pub fn new() -> ConfigSettingsHttp { + ConfigSettingsHttp { + body_read_timeout: None, + discard_unsafe_fields: None, + header_read_timeout: None, + idle_timeout: None, + log_route: None, + max_body_size: None, + send_timeout: None, + server_version: None, + r#static: None, + } + } +} diff --git a/cli/unit-openapi/src/models/config_settings_http_static.rs b/cli/unit-openapi/src/models/config_settings_http_static.rs new file mode 100644 index 000000000..d84c4b1cb --- /dev/null +++ b/cli/unit-openapi/src/models/config_settings_http_static.rs @@ -0,0 +1,25 @@ +/* + * NGINX Unit 1.31.1 + * + * NGINX Unit is a lightweight and versatile application runtime that provides the essential components for your web application as a single open-source server: running application code, serving static assets, handling TLS and request routing. **Important**: Ufnit's API is designed to expose any part of its configuration as an addressable endpoint. Suppose a JSON object is stored at `/config/listeners/`: ```json { \"*:8080\": { \"pass\": \"applications/wp_emea_dev\" } } ``` Here, `/config/listeners/_*:8080` and `/config/listeners/_*:8080/pass` are also endpoints. Generally, object options are addressable by their names, array items—by their indexes (`/array/0/`). **Note**: By default, Unit is configured through a UNIX domain socket. To use this specification with OpenAPI tools interactively, [start](https://unit.nginx.org/howto/source/#source-startup) Unit with a TCP port as the control socket. + * + * The version of the OpenAPI document: 0.2.0 + * Contact: unit-owner@nginx.org + * Generated by: https://openapi-generator.tech + */ + +/// ConfigSettingsHttpStatic : An object whose single option defines specific MIME types. + +#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] +pub struct ConfigSettingsHttpStatic { + /// An object whose options define individual MIME types. + #[serde(rename = "mime_types", skip_serializing_if = "Option::is_none")] + pub mime_types: Option<::std::collections::HashMap>, +} + +impl ConfigSettingsHttpStatic { + /// An object whose single option defines specific MIME types. + pub fn new() -> ConfigSettingsHttpStatic { + ConfigSettingsHttpStatic { mime_types: None } + } +} diff --git a/cli/unit-openapi/src/models/config_settings_http_static_mime_type.rs b/cli/unit-openapi/src/models/config_settings_http_static_mime_type.rs new file mode 100644 index 000000000..d67c089bd --- /dev/null +++ b/cli/unit-openapi/src/models/config_settings_http_static_mime_type.rs @@ -0,0 +1,21 @@ +/* + * NGINX Unit 1.31.1 + * + * NGINX Unit is a lightweight and versatile application runtime that provides the essential components for your web application as a single open-source server: running application code, serving static assets, handling TLS and request routing. **Important**: Ufnit's API is designed to expose any part of its configuration as an addressable endpoint. Suppose a JSON object is stored at `/config/listeners/`: ```json { \"*:8080\": { \"pass\": \"applications/wp_emea_dev\" } } ``` Here, `/config/listeners/_*:8080` and `/config/listeners/_*:8080/pass` are also endpoints. Generally, object options are addressable by their names, array items—by their indexes (`/array/0/`). **Note**: By default, Unit is configured through a UNIX domain socket. To use this specification with OpenAPI tools interactively, [start](https://unit.nginx.org/howto/source/#source-startup) Unit with a TCP port as the control socket. + * + * The version of the OpenAPI document: 0.2.0 + * Contact: unit-owner@nginx.org + * Generated by: https://openapi-generator.tech + */ + +/// ConfigSettingsHttpStaticMimeType : An entity that defines an individual MIME type by listing file extensions. + +#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] +pub struct ConfigSettingsHttpStaticMimeType {} + +impl ConfigSettingsHttpStaticMimeType { + /// An entity that defines an individual MIME type by listing file extensions. + pub fn new() -> ConfigSettingsHttpStaticMimeType { + ConfigSettingsHttpStaticMimeType {} + } +} diff --git a/cli/unit-openapi/src/models/mod.rs b/cli/unit-openapi/src/models/mod.rs new file mode 100644 index 000000000..ede1a504d --- /dev/null +++ b/cli/unit-openapi/src/models/mod.rs @@ -0,0 +1,128 @@ +pub mod cert_bundle; +pub use self::cert_bundle::CertBundle; +pub mod cert_bundle_chain_cert; +pub use self::cert_bundle_chain_cert::CertBundleChainCert; +pub mod cert_bundle_chain_cert_issuer; +pub use self::cert_bundle_chain_cert_issuer::CertBundleChainCertIssuer; +pub mod cert_bundle_chain_cert_subj; +pub use self::cert_bundle_chain_cert_subj::CertBundleChainCertSubj; +pub mod cert_bundle_chain_cert_validity; +pub use self::cert_bundle_chain_cert_validity::CertBundleChainCertValidity; +pub mod config; +pub use self::config::Config; +pub mod config_access_log; +pub use self::config_access_log::ConfigAccessLog; +pub mod config_access_log_object; +pub use self::config_access_log_object::ConfigAccessLogObject; +pub mod config_application; +pub use self::config_application::ConfigApplication; +pub mod config_application_common; +pub use self::config_application_common::ConfigApplicationCommon; +pub mod config_application_common_isolation; +pub use self::config_application_common_isolation::ConfigApplicationCommonIsolation; +pub mod config_application_common_isolation_automount; +pub use self::config_application_common_isolation_automount::ConfigApplicationCommonIsolationAutomount; +pub mod config_application_common_isolation_cgroup; +pub use self::config_application_common_isolation_cgroup::ConfigApplicationCommonIsolationCgroup; +pub mod config_application_common_isolation_gidmap_inner; +pub use self::config_application_common_isolation_gidmap_inner::ConfigApplicationCommonIsolationGidmapInner; +pub mod config_application_common_isolation_namespaces; +pub use self::config_application_common_isolation_namespaces::ConfigApplicationCommonIsolationNamespaces; +pub mod config_application_common_isolation_uidmap_inner; +pub use self::config_application_common_isolation_uidmap_inner::ConfigApplicationCommonIsolationUidmapInner; +pub mod config_application_common_limits; +pub use self::config_application_common_limits::ConfigApplicationCommonLimits; +pub mod config_application_common_processes; +pub use self::config_application_common_processes::ConfigApplicationCommonProcesses; +pub mod config_application_common_processes_any_of; +pub use self::config_application_common_processes_any_of::ConfigApplicationCommonProcessesAnyOf; +pub mod config_application_external; +pub use self::config_application_external::ConfigApplicationExternal; +pub mod config_application_external_all_of; +pub use self::config_application_external_all_of::ConfigApplicationExternalAllOf; +pub mod config_application_java; +pub use self::config_application_java::ConfigApplicationJava; +pub mod config_application_java_all_of; +pub use self::config_application_java_all_of::ConfigApplicationJavaAllOf; +pub mod config_application_perl; +pub use self::config_application_perl::ConfigApplicationPerl; +pub mod config_application_perl_all_of; +pub use self::config_application_perl_all_of::ConfigApplicationPerlAllOf; +pub mod config_application_php; +pub use self::config_application_php::ConfigApplicationPhp; +pub mod config_application_php_all_of; +pub use self::config_application_php_all_of::ConfigApplicationPhpAllOf; +pub mod config_application_php_all_of_options; +pub use self::config_application_php_all_of_options::ConfigApplicationPhpAllOfOptions; +pub mod config_application_php_all_of_targets; +pub use self::config_application_php_all_of_targets::ConfigApplicationPhpAllOfTargets; +pub mod config_application_python; +pub use self::config_application_python::ConfigApplicationPython; +pub mod config_application_python_all_of; +pub use self::config_application_python_all_of::ConfigApplicationPythonAllOf; +pub mod config_application_python_all_of_path; +pub use self::config_application_python_all_of_path::ConfigApplicationPythonAllOfPath; +pub mod config_application_python_all_of_targets; +pub use self::config_application_python_all_of_targets::ConfigApplicationPythonAllOfTargets; +pub mod config_application_ruby; +pub use self::config_application_ruby::ConfigApplicationRuby; +pub mod config_application_ruby_all_of; +pub use self::config_application_ruby_all_of::ConfigApplicationRubyAllOf; +pub mod config_listener; +pub use self::config_listener::ConfigListener; +pub mod config_listener_forwarded; +pub use self::config_listener_forwarded::ConfigListenerForwarded; +pub mod config_listener_forwarded_source; +pub use self::config_listener_forwarded_source::ConfigListenerForwardedSource; +pub mod config_listener_tls; +pub use self::config_listener_tls::ConfigListenerTls; +pub mod config_listener_tls_certificate; +pub use self::config_listener_tls_certificate::ConfigListenerTlsCertificate; +pub mod config_listener_tls_session; +pub use self::config_listener_tls_session::ConfigListenerTlsSession; +pub mod config_listener_tls_session_tickets; +pub use self::config_listener_tls_session_tickets::ConfigListenerTlsSessionTickets; +pub mod config_route_step; +pub use self::config_route_step::ConfigRouteStep; +pub mod config_route_step_action; +pub use self::config_route_step_action::ConfigRouteStepAction; +pub mod config_route_step_action_pass; +pub use self::config_route_step_action_pass::ConfigRouteStepActionPass; +pub mod config_route_step_action_proxy; +pub use self::config_route_step_action_proxy::ConfigRouteStepActionProxy; +pub mod config_route_step_action_return; +pub use self::config_route_step_action_return::ConfigRouteStepActionReturn; +pub mod config_route_step_action_share; +pub use self::config_route_step_action_share::ConfigRouteStepActionShare; +pub mod config_route_step_match; +pub use self::config_route_step_match::ConfigRouteStepMatch; +pub mod config_route_step_match_arguments; +pub use self::config_route_step_match_arguments::ConfigRouteStepMatchArguments; +pub mod config_route_step_match_cookies; +pub use self::config_route_step_match_cookies::ConfigRouteStepMatchCookies; +pub mod config_route_step_match_headers; +pub use self::config_route_step_match_headers::ConfigRouteStepMatchHeaders; +pub mod config_routes; +pub use self::config_routes::ConfigRoutes; +pub mod config_settings; +pub use self::config_settings::ConfigSettings; +pub mod config_settings_http; +pub use self::config_settings_http::ConfigSettingsHttp; +pub mod config_settings_http_static; +pub use self::config_settings_http_static::ConfigSettingsHttpStatic; +pub mod config_settings_http_static_mime_type; +pub use self::config_settings_http_static_mime_type::ConfigSettingsHttpStaticMimeType; +pub mod status; +pub use self::status::Status; +pub mod status_applications_app; +pub use self::status_applications_app::StatusApplicationsApp; +pub mod status_applications_app_processes; +pub use self::status_applications_app_processes::StatusApplicationsAppProcesses; +pub mod status_applications_app_requests; +pub use self::status_applications_app_requests::StatusApplicationsAppRequests; +pub mod status_connections; +pub use self::status_connections::StatusConnections; +pub mod status_requests; +pub use self::status_requests::StatusRequests; +pub mod string_or_string_array; +pub use self::string_or_string_array::StringOrStringArray; diff --git a/cli/unit-openapi/src/models/status.rs b/cli/unit-openapi/src/models/status.rs new file mode 100644 index 000000000..7e0e54ad6 --- /dev/null +++ b/cli/unit-openapi/src/models/status.rs @@ -0,0 +1,33 @@ +/* + * NGINX Unit 1.31.1 + * + * NGINX Unit is a lightweight and versatile application runtime that provides the essential components for your web application as a single open-source server: running application code, serving static assets, handling TLS and request routing. **Important**: Ufnit's API is designed to expose any part of its configuration as an addressable endpoint. Suppose a JSON object is stored at `/config/listeners/`: ```json { \"*:8080\": { \"pass\": \"applications/wp_emea_dev\" } } ``` Here, `/config/listeners/_*:8080` and `/config/listeners/_*:8080/pass` are also endpoints. Generally, object options are addressable by their names, array items—by their indexes (`/array/0/`). **Note**: By default, Unit is configured through a UNIX domain socket. To use this specification with OpenAPI tools interactively, [start](https://unit.nginx.org/howto/source/#source-startup) Unit with a TCP port as the control socket. + * + * The version of the OpenAPI document: 0.2.0 + * Contact: unit-owner@nginx.org + * Generated by: https://openapi-generator.tech + */ + +/// Status : Represents Unit's usage statistics. + +#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] +pub struct Status { + #[serde(rename = "connections", skip_serializing_if = "Option::is_none")] + pub connections: Option>, + #[serde(rename = "requests", skip_serializing_if = "Option::is_none")] + pub requests: Option>, + /// Lists Unit's application process and request statistics. + #[serde(rename = "applications", skip_serializing_if = "Option::is_none")] + pub applications: Option<::std::collections::HashMap>, +} + +impl Status { + /// Represents Unit's usage statistics. + pub fn new() -> Status { + Status { + connections: None, + requests: None, + applications: None, + } + } +} diff --git a/cli/unit-openapi/src/models/status_applications_app.rs b/cli/unit-openapi/src/models/status_applications_app.rs new file mode 100644 index 000000000..b687fea88 --- /dev/null +++ b/cli/unit-openapi/src/models/status_applications_app.rs @@ -0,0 +1,29 @@ +/* + * NGINX Unit 1.31.1 + * + * NGINX Unit is a lightweight and versatile application runtime that provides the essential components for your web application as a single open-source server: running application code, serving static assets, handling TLS and request routing. **Important**: Ufnit's API is designed to expose any part of its configuration as an addressable endpoint. Suppose a JSON object is stored at `/config/listeners/`: ```json { \"*:8080\": { \"pass\": \"applications/wp_emea_dev\" } } ``` Here, `/config/listeners/_*:8080` and `/config/listeners/_*:8080/pass` are also endpoints. Generally, object options are addressable by their names, array items—by their indexes (`/array/0/`). **Note**: By default, Unit is configured through a UNIX domain socket. To use this specification with OpenAPI tools interactively, [start](https://unit.nginx.org/howto/source/#source-startup) Unit with a TCP port as the control socket. + * + * The version of the OpenAPI document: 0.2.0 + * Contact: unit-owner@nginx.org + * Generated by: https://openapi-generator.tech + */ + +/// StatusApplicationsApp : Represents Unit's per-app process and request statistics. + +#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] +pub struct StatusApplicationsApp { + #[serde(rename = "processes", skip_serializing_if = "Option::is_none")] + pub processes: Option>, + #[serde(rename = "requests", skip_serializing_if = "Option::is_none")] + pub requests: Option>, +} + +impl StatusApplicationsApp { + /// Represents Unit's per-app process and request statistics. + pub fn new() -> StatusApplicationsApp { + StatusApplicationsApp { + processes: None, + requests: None, + } + } +} diff --git a/cli/unit-openapi/src/models/status_applications_app_processes.rs b/cli/unit-openapi/src/models/status_applications_app_processes.rs new file mode 100644 index 000000000..47c7c4e12 --- /dev/null +++ b/cli/unit-openapi/src/models/status_applications_app_processes.rs @@ -0,0 +1,35 @@ +/* + * NGINX Unit 1.31.1 + * + * NGINX Unit is a lightweight and versatile application runtime that provides the essential components for your web application as a single open-source server: running application code, serving static assets, handling TLS and request routing. **Important**: Ufnit's API is designed to expose any part of its configuration as an addressable endpoint. Suppose a JSON object is stored at `/config/listeners/`: ```json { \"*:8080\": { \"pass\": \"applications/wp_emea_dev\" } } ``` Here, `/config/listeners/_*:8080` and `/config/listeners/_*:8080/pass` are also endpoints. Generally, object options are addressable by their names, array items—by their indexes (`/array/0/`). **Note**: By default, Unit is configured through a UNIX domain socket. To use this specification with OpenAPI tools interactively, [start](https://unit.nginx.org/howto/source/#source-startup) Unit with a TCP port as the control socket. + * + * The version of the OpenAPI document: 0.2.0 + * Contact: unit-owner@nginx.org + * Generated by: https://openapi-generator.tech + */ + +/// StatusApplicationsAppProcesses : Represents Unit's per-app process statistics. + +#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] +pub struct StatusApplicationsAppProcesses { + /// Current running app processes. + #[serde(rename = "running", skip_serializing_if = "Option::is_none")] + pub running: Option, + /// Current starting app processes. + #[serde(rename = "starting", skip_serializing_if = "Option::is_none")] + pub starting: Option, + /// Current idle app processes. + #[serde(rename = "idle", skip_serializing_if = "Option::is_none")] + pub idle: Option, +} + +impl StatusApplicationsAppProcesses { + /// Represents Unit's per-app process statistics. + pub fn new() -> StatusApplicationsAppProcesses { + StatusApplicationsAppProcesses { + running: None, + starting: None, + idle: None, + } + } +} diff --git a/cli/unit-openapi/src/models/status_applications_app_requests.rs b/cli/unit-openapi/src/models/status_applications_app_requests.rs new file mode 100644 index 000000000..a3e080630 --- /dev/null +++ b/cli/unit-openapi/src/models/status_applications_app_requests.rs @@ -0,0 +1,25 @@ +/* + * NGINX Unit 1.31.1 + * + * NGINX Unit is a lightweight and versatile application runtime that provides the essential components for your web application as a single open-source server: running application code, serving static assets, handling TLS and request routing. **Important**: Ufnit's API is designed to expose any part of its configuration as an addressable endpoint. Suppose a JSON object is stored at `/config/listeners/`: ```json { \"*:8080\": { \"pass\": \"applications/wp_emea_dev\" } } ``` Here, `/config/listeners/_*:8080` and `/config/listeners/_*:8080/pass` are also endpoints. Generally, object options are addressable by their names, array items—by their indexes (`/array/0/`). **Note**: By default, Unit is configured through a UNIX domain socket. To use this specification with OpenAPI tools interactively, [start](https://unit.nginx.org/howto/source/#source-startup) Unit with a TCP port as the control socket. + * + * The version of the OpenAPI document: 0.2.0 + * Contact: unit-owner@nginx.org + * Generated by: https://openapi-generator.tech + */ + +/// StatusApplicationsAppRequests : Represents Unit's per-app request statistics. + +#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] +pub struct StatusApplicationsAppRequests { + /// Active app requests. + #[serde(rename = "active", skip_serializing_if = "Option::is_none")] + pub active: Option, +} + +impl StatusApplicationsAppRequests { + /// Represents Unit's per-app request statistics. + pub fn new() -> StatusApplicationsAppRequests { + StatusApplicationsAppRequests { active: None } + } +} diff --git a/cli/unit-openapi/src/models/status_connections.rs b/cli/unit-openapi/src/models/status_connections.rs new file mode 100644 index 000000000..706a1cbe9 --- /dev/null +++ b/cli/unit-openapi/src/models/status_connections.rs @@ -0,0 +1,39 @@ +/* + * NGINX Unit 1.31.1 + * + * NGINX Unit is a lightweight and versatile application runtime that provides the essential components for your web application as a single open-source server: running application code, serving static assets, handling TLS and request routing. **Important**: Ufnit's API is designed to expose any part of its configuration as an addressable endpoint. Suppose a JSON object is stored at `/config/listeners/`: ```json { \"*:8080\": { \"pass\": \"applications/wp_emea_dev\" } } ``` Here, `/config/listeners/_*:8080` and `/config/listeners/_*:8080/pass` are also endpoints. Generally, object options are addressable by their names, array items—by their indexes (`/array/0/`). **Note**: By default, Unit is configured through a UNIX domain socket. To use this specification with OpenAPI tools interactively, [start](https://unit.nginx.org/howto/source/#source-startup) Unit with a TCP port as the control socket. + * + * The version of the OpenAPI document: 0.2.0 + * Contact: unit-owner@nginx.org + * Generated by: https://openapi-generator.tech + */ + +/// StatusConnections : Represents Unit's per-instance connection statistics. + +#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] +pub struct StatusConnections { + /// Total accepted connections during the instance’s lifetime. + #[serde(rename = "accepted", skip_serializing_if = "Option::is_none")] + pub accepted: Option, + /// Current active connections for the instance. + #[serde(rename = "active", skip_serializing_if = "Option::is_none")] + pub active: Option, + /// Current idle connections for the instance. + #[serde(rename = "idle", skip_serializing_if = "Option::is_none")] + pub idle: Option, + /// Total closed connections during the instance’s lifetime. + #[serde(rename = "closed", skip_serializing_if = "Option::is_none")] + pub closed: Option, +} + +impl StatusConnections { + /// Represents Unit's per-instance connection statistics. + pub fn new() -> StatusConnections { + StatusConnections { + accepted: None, + active: None, + idle: None, + closed: None, + } + } +} diff --git a/cli/unit-openapi/src/models/status_requests.rs b/cli/unit-openapi/src/models/status_requests.rs new file mode 100644 index 000000000..8fa8845c3 --- /dev/null +++ b/cli/unit-openapi/src/models/status_requests.rs @@ -0,0 +1,25 @@ +/* + * NGINX Unit 1.31.1 + * + * NGINX Unit is a lightweight and versatile application runtime that provides the essential components for your web application as a single open-source server: running application code, serving static assets, handling TLS and request routing. **Important**: Ufnit's API is designed to expose any part of its configuration as an addressable endpoint. Suppose a JSON object is stored at `/config/listeners/`: ```json { \"*:8080\": { \"pass\": \"applications/wp_emea_dev\" } } ``` Here, `/config/listeners/_*:8080` and `/config/listeners/_*:8080/pass` are also endpoints. Generally, object options are addressable by their names, array items—by their indexes (`/array/0/`). **Note**: By default, Unit is configured through a UNIX domain socket. To use this specification with OpenAPI tools interactively, [start](https://unit.nginx.org/howto/source/#source-startup) Unit with a TCP port as the control socket. + * + * The version of the OpenAPI document: 0.2.0 + * Contact: unit-owner@nginx.org + * Generated by: https://openapi-generator.tech + */ + +/// StatusRequests : Represents Unit's per-instance request statistics. + +#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] +pub struct StatusRequests { + /// Total non-API requests during the instance’s lifetime. + #[serde(rename = "total", skip_serializing_if = "Option::is_none")] + pub total: Option, +} + +impl StatusRequests { + /// Represents Unit's per-instance request statistics. + pub fn new() -> StatusRequests { + StatusRequests { total: None } + } +} diff --git a/cli/unit-openapi/src/models/string_or_string_array.rs b/cli/unit-openapi/src/models/string_or_string_array.rs new file mode 100644 index 000000000..aca439476 --- /dev/null +++ b/cli/unit-openapi/src/models/string_or_string_array.rs @@ -0,0 +1,21 @@ +/* + * NGINX Unit 1.31.1 + * + * NGINX Unit is a lightweight and versatile application runtime that provides the essential components for your web application as a single open-source server: running application code, serving static assets, handling TLS and request routing. **Important**: Ufnit's API is designed to expose any part of its configuration as an addressable endpoint. Suppose a JSON object is stored at `/config/listeners/`: ```json { \"*:8080\": { \"pass\": \"applications/wp_emea_dev\" } } ``` Here, `/config/listeners/_*:8080` and `/config/listeners/_*:8080/pass` are also endpoints. Generally, object options are addressable by their names, array items—by their indexes (`/array/0/`). **Note**: By default, Unit is configured through a UNIX domain socket. To use this specification with OpenAPI tools interactively, [start](https://unit.nginx.org/howto/source/#source-startup) Unit with a TCP port as the control socket. + * + * The version of the OpenAPI document: 0.2.0 + * Contact: unit-owner@nginx.org + * Generated by: https://openapi-generator.tech + */ + +/// StringOrStringArray : A string or an array of strings. + +#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] +pub struct StringOrStringArray {} + +impl StringOrStringArray { + /// A string or an array of strings. + pub fn new() -> StringOrStringArray { + StringOrStringArray {} + } +} diff --git a/cli/unitctl/Cargo.toml b/cli/unitctl/Cargo.toml new file mode 100644 index 000000000..98930fb3d --- /dev/null +++ b/cli/unitctl/Cargo.toml @@ -0,0 +1,56 @@ +[package] +name = "unitctl" +description = "CLI interface to the NGINX UNIT Control API" +version = "0.4.0-beta" +authors = ["Elijah Zupancic"] +edition = "2021" +license = "Apache-2.0" + +[[bin]] +name = "unitctl" +path = "src/main.rs" + +[features] + +[dependencies] +clap = { version = "4.4", features = ["default", "derive", "cargo"] } +custom_error = "1.9" +serde = "1.0" +json5 = "0.4" +nu-json = "0.89" +serde_json = { version = "1.0", optional = false } +serde_yaml = "0.9" +rustls-pemfile = "2.0.0" +unit-client-rs = { path = "../unit-client-rs" } +colored_json = "4.1" +tempfile = "3.8" +which = "5.0" +walkdir = "2.4" + +hyper = { version = "0.14", features = ["http1", "server", "client"] } +hyperlocal = "0.8" +hyper-tls = "0.5" +tokio = { version = "1.35", features = ["macros"] } +futures = "0.3" + +[package.metadata.deb] +copyright = "2022, F5" +license-file = ["../LICENSE.txt", "0"] +extended-description = """\ +A utility for controlling NGINX UNIT.""" +section = "utility" +priority = "optional" +assets = [ + ["../target/release/unitctl", "usr/bin/", "755"], + ["../target/man/unitctl.1.gz", "usr/share/man/man1/", "644"] +] + +[package.metadata.generate-rpm] +summary = """\ +A utility for controlling NGINX UNIT.""" +section = "utility" +priority = "optional" +assets = [ + { source = "../target/release/unitctl", dest = "/usr/bin/unitctl", mode = "755" }, + { source = "../target/man/unitctl.1.gz", dest = "/usr/share/man/man1/unitctl.1.gz", mode = "644" }, +] diff --git a/cli/unitctl/src/cmd/edit.rs b/cli/unitctl/src/cmd/edit.rs new file mode 100644 index 000000000..cbe012893 --- /dev/null +++ b/cli/unitctl/src/cmd/edit.rs @@ -0,0 +1,105 @@ +use crate::inputfile::{InputFile, InputFormat}; +use crate::requests::{send_and_validate_config_deserialize_response, send_empty_body_deserialize_response}; +use crate::unitctl::UnitCtl; +use crate::{wait, OutputFormat, UnitctlError}; +use std::path::{Path, PathBuf}; +use unit_client_rs::unit_client::UnitClient; +use which::which; + +const EDITOR_ENV_VARS: [&str; 2] = ["EDITOR", "VISUAL"]; +const EDITOR_KNOWN_LIST: [&str; 8] = [ + "sensible-editor", + "editor", + "vim", + "nano", + "nvim", + "vi", + "pico", + "emacs", +]; + +pub(crate) fn cmd(cli: &UnitCtl, output_format: OutputFormat) -> Result<(), UnitctlError> { + let control_socket = wait::wait_for_socket(cli)?; + let client = UnitClient::new(control_socket); + // Get latest configuration + let current_config = send_empty_body_deserialize_response(&client, "GET", "/config")?; + + // Write JSON to temporary file - this file will automatically be deleted by the OS when + // the last file handle to it is removed. + let mut temp_file = tempfile::Builder::new() + .prefix("unitctl-") + .suffix(".json") + .tempfile() + .map_err(|e| UnitctlError::IoError { source: e })?; + + // Pretty format JSON received from UNIT and write to the temporary file + serde_json::to_writer_pretty(temp_file.as_file_mut(), ¤t_config) + .map_err(|e| UnitctlError::SerializationError { message: e.to_string() })?; + + // Load edited file + let temp_file_path = temp_file.path(); + let before_edit_mod_time = temp_file_path.metadata().ok().map(|m| m.modified().ok()); + + let inputfile = InputFile::FileWithFormat(temp_file_path.into(), InputFormat::Json5); + open_editor(temp_file_path)?; + let after_edit_mod_time = temp_file_path.metadata().ok().map(|m| m.modified().ok()); + + // Check if file was modified before sending to UNIT + if let (Some(before), Some(after)) = (before_edit_mod_time, after_edit_mod_time) { + if before == after { + eprintln!("File was not modified - no changes will be sent to UNIT"); + return Ok(()); + } + }; + + // Send edited file to UNIT to overwrite current configuration + send_and_validate_config_deserialize_response(&client, "PUT", "/config", Some(&inputfile)) + .and_then(|status| output_format.write_to_stdout(&status)) +} + +/// Look for an editor in the environment variables +fn find_editor_from_env() -> Option { + EDITOR_ENV_VARS + .iter() + .filter_map(std::env::var_os) + .filter(|s| !s.is_empty()) + .filter_map(|s| which(s).ok()) + .filter_map(|path| path.canonicalize().ok()) + .find(|path| path.exists()) +} + +/// Look for editor in path by matching against a list of known editors or aliases +fn find_editor_from_known_list() -> Option { + EDITOR_KNOWN_LIST + .iter() + .filter_map(|editor| which(editor).ok()) + .filter_map(|path| path.canonicalize().ok()) + .find(|editor| editor.exists()) +} + +/// Find the path to an editor +pub fn find_editor_path() -> Result { + find_editor_from_env() + .or_else(find_editor_from_known_list) + .ok_or_else(|| UnitctlError::EditorError { + message: "Could not find an editor".to_string(), + }) +} + +/// Start an editor with a given path +pub fn open_editor(path: &Path) -> Result<(), UnitctlError> { + let editor_path = find_editor_path()?; + let status = std::process::Command::new(editor_path) + .arg(path) + .status() + .map_err(|e| UnitctlError::EditorError { + message: format!("Could not open editor: {}", e), + })?; + if status.success() { + Ok(()) + } else { + Err(UnitctlError::EditorError { + message: format!("Editor exited with non-zero status: {}", status), + }) + } +} diff --git a/cli/unitctl/src/cmd/execute.rs b/cli/unitctl/src/cmd/execute.rs new file mode 100644 index 000000000..60957a831 --- /dev/null +++ b/cli/unitctl/src/cmd/execute.rs @@ -0,0 +1,68 @@ +use crate::inputfile::InputFile; +use crate::requests::{ + send_and_validate_config_deserialize_response, send_and_validate_pem_data_deserialize_response, + send_body_deserialize_response, send_empty_body_deserialize_response, +}; +use crate::unitctl::UnitCtl; +use crate::wait; +use crate::{OutputFormat, UnitctlError}; +use unit_client_rs::unit_client::UnitClient; + +pub(crate) fn cmd( + cli: &UnitCtl, + output_format: &OutputFormat, + input_file: &Option, + method: &str, + path: &str, +) -> Result<(), UnitctlError> { + let control_socket = wait::wait_for_socket(cli)?; + let client = UnitClient::new(control_socket); + + let path_trimmed = path.trim(); + let method_upper = method.to_uppercase(); + let input_file_arg = input_file + .as_ref() + .map(|file| InputFile::new(file, &path_trimmed.to_string())); + + if method_upper.eq("GET") && input_file.is_some() { + eprintln!("Cannot use GET method with input file - ignoring input file"); + } + + send_and_deserialize(client, method_upper, input_file_arg, path_trimmed, output_format) +} + +fn send_and_deserialize( + client: UnitClient, + method: String, + input_file: Option, + path: &str, + output_format: &OutputFormat, +) -> Result<(), UnitctlError> { + let is_js_modules_dir = path.starts_with("/js_modules/") || path.starts_with("js_modules/"); + + // If we are sending a GET request to a JS modules directory, we want to print the contents of the JS file + // instead of the JSON response + if method.eq("GET") && is_js_modules_dir && path.ends_with(".js") { + let script = send_body_deserialize_response::(&client, method.as_str(), path, input_file.as_ref())?; + println!("{}", script); + return Ok(()); + } + + // Otherwise, we want to print the JSON response (a map) as represented by the output format + match input_file { + Some(input_file) => { + if input_file.is_config() { + send_and_validate_config_deserialize_response(&client, method.as_str(), path, Some(&input_file)) + // TLS certificate data + } else if input_file.is_pem_bundle() { + send_and_validate_pem_data_deserialize_response(&client, method.as_str(), path, &input_file) + // This is unknown data + } else { + panic!("Unknown input file type") + } + } + // A none value for an input file can be considered a request to send an empty body + None => send_empty_body_deserialize_response(&client, method.as_str(), path), + } + .and_then(|status| output_format.write_to_stdout(&status)) +} diff --git a/cli/unitctl/src/cmd/import.rs b/cli/unitctl/src/cmd/import.rs new file mode 100644 index 000000000..e5e574569 --- /dev/null +++ b/cli/unitctl/src/cmd/import.rs @@ -0,0 +1,124 @@ +use crate::inputfile::{InputFile, InputFormat}; +use crate::unitctl::UnitCtl; +use crate::unitctl_error::UnitctlError; +use crate::{requests, wait}; +use std::path::{Path, PathBuf}; +use unit_client_rs::unit_client::{UnitClient, UnitSerializableMap}; +use walkdir::{DirEntry, WalkDir}; + +enum UploadFormat { + Config, + PemBundle, + Javascript, +} + +impl From<&InputFile> for UploadFormat { + fn from(input_file: &InputFile) -> Self { + if input_file.is_config() { + UploadFormat::Config + } else if input_file.is_pem_bundle() { + UploadFormat::PemBundle + } else if input_file.is_javascript() { + UploadFormat::Javascript + } else { + panic!("Unknown input file type"); + } + } +} + +impl UploadFormat { + fn can_be_overwritten(&self) -> bool { + matches!(self, UploadFormat::Config) + } + fn upload_path(&self, path: &Path) -> String { + match self { + UploadFormat::Config => "/config".to_string(), + UploadFormat::PemBundle => format!("/certificates/{}.pem", Self::file_stem(path)), + UploadFormat::Javascript => format!("/js_modules/{}.js", Self::file_stem(path)), + } + } + + fn file_stem(path: &Path) -> String { + path.file_stem().unwrap_or_default().to_string_lossy().into() + } +} + +pub fn cmd(cli: &UnitCtl, directory: &PathBuf) -> Result<(), UnitctlError> { + if !directory.exists() { + return Err(UnitctlError::PathNotFound { + path: directory.to_string_lossy().into(), + }); + } + + let control_socket = wait::wait_for_socket(cli)?; + let client = UnitClient::new(control_socket); + + let results: Vec> = WalkDir::new(directory) + .follow_links(true) + .sort_by_file_name() + .into_iter() + .filter_map(Result::ok) + .filter(|e| !e.path().is_dir()) + .map(|pe| process_entry(pe, &client)) + .collect(); + + if results.iter().filter(|r| r.is_err()).count() == results.len() { + Err(UnitctlError::NoFilesImported) + } else { + println!("Imported {} files", results.len()); + Ok(()) + } +} + +fn process_entry(entry: DirEntry, client: &UnitClient) -> Result<(), UnitctlError> { + let input_file = InputFile::from(entry.path()); + if input_file.format() == InputFormat::Unknown { + println!( + "Skipping unknown file type: {}", + input_file.to_path()?.to_string_lossy() + ); + return Err(UnitctlError::UnknownInputFileType { + path: input_file.to_path()?.to_string_lossy().into(), + }); + } + let upload_format = UploadFormat::from(&input_file); + let upload_path = upload_format.upload_path(entry.path()); + + // We can't overwrite JS or PEM files, so we delete them first + if !upload_format.can_be_overwritten() { + let _ = requests::send_empty_body_deserialize_response(client, "DELETE", upload_path.as_str()).ok(); + } + + let result = match upload_format { + UploadFormat::Config => requests::send_and_validate_config_deserialize_response( + client, + "PUT", + upload_path.as_str(), + Some(&input_file), + ), + UploadFormat::PemBundle => { + requests::send_and_validate_pem_data_deserialize_response(client, "PUT", upload_path.as_str(), &input_file) + } + UploadFormat::Javascript => requests::send_body_deserialize_response::( + client, + "PUT", + upload_path.as_str(), + Some(&input_file), + ), + }; + + match result { + Ok(_) => { + eprintln!( + "Imported {} -> {}", + input_file.to_path()?.to_string_lossy(), + upload_path + ); + Ok(()) + } + Err(error) => { + eprintln!("Error {} -> {}", input_file.to_path()?.to_string_lossy(), error); + Err(error) + } + } +} diff --git a/cli/unitctl/src/cmd/instances.rs b/cli/unitctl/src/cmd/instances.rs new file mode 100644 index 000000000..26e150273 --- /dev/null +++ b/cli/unitctl/src/cmd/instances.rs @@ -0,0 +1,16 @@ +use crate::{OutputFormat, UnitctlError}; +use unit_client_rs::unitd_instance::UnitdInstance; + +pub(crate) fn cmd(output_format: OutputFormat) -> Result<(), UnitctlError> { + let instances = UnitdInstance::running_unitd_instances(); + if instances.is_empty() { + Err(UnitctlError::NoUnitInstancesError) + } else if output_format.eq(&OutputFormat::Text) { + instances.iter().for_each(|instance| { + println!("{}", instance); + }); + Ok(()) + } else { + output_format.write_to_stdout(&instances) + } +} diff --git a/cli/unitctl/src/cmd/listeners.rs b/cli/unitctl/src/cmd/listeners.rs new file mode 100644 index 000000000..081a6cd9e --- /dev/null +++ b/cli/unitctl/src/cmd/listeners.rs @@ -0,0 +1,13 @@ +use crate::unitctl::UnitCtl; +use crate::wait; +use crate::{OutputFormat, UnitctlError}; +use unit_client_rs::unit_client::UnitClient; + +pub fn cmd(cli: &UnitCtl, output_format: OutputFormat) -> Result<(), UnitctlError> { + let control_socket = wait::wait_for_socket(cli)?; + let client = UnitClient::new(control_socket); + client + .listeners() + .map_err(|e| UnitctlError::UnitClientError { source: *e }) + .and_then(|response| output_format.write_to_stdout(&response)) +} diff --git a/cli/unitctl/src/cmd/mod.rs b/cli/unitctl/src/cmd/mod.rs new file mode 100644 index 000000000..e7e32ee5c --- /dev/null +++ b/cli/unitctl/src/cmd/mod.rs @@ -0,0 +1,7 @@ +pub(crate) mod edit; +pub(crate) mod execute; +pub(crate) mod import; +pub(crate) mod instances; +pub(crate) mod listeners; +pub(crate) mod status; +pub(crate) mod ui; diff --git a/cli/unitctl/src/cmd/status.rs b/cli/unitctl/src/cmd/status.rs new file mode 100644 index 000000000..1f40735f2 --- /dev/null +++ b/cli/unitctl/src/cmd/status.rs @@ -0,0 +1,13 @@ +use crate::unitctl::UnitCtl; +use crate::wait; +use crate::{OutputFormat, UnitctlError}; +use unit_client_rs::unit_client::UnitClient; + +pub fn cmd(cli: &UnitCtl, output_format: OutputFormat) -> Result<(), UnitctlError> { + let control_socket = wait::wait_for_socket(cli)?; + let client = UnitClient::new(control_socket); + client + .status() + .map_err(|e| UnitctlError::UnitClientError { source: *e }) + .and_then(|response| output_format.write_to_stdout(&response)) +} diff --git a/cli/unitctl/src/cmd/ui.rs b/cli/unitctl/src/cmd/ui.rs new file mode 100644 index 000000000..5bfa9243c --- /dev/null +++ b/cli/unitctl/src/cmd/ui.rs @@ -0,0 +1,215 @@ +use crate::wait; +use crate::UnitctlError; +use std::io::Error as IoError; +use std::net::IpAddr; +use std::str::FromStr; + +use std::borrow::ToOwned; +use std::convert::Infallible; + +use crate::unitctl::UnitCtl; +use hyper::client::ResponseFuture; +use hyper::service::{make_service_fn, service_fn}; +use hyper::{Body, Client, Request, Response, Result as HyperResult, Server, StatusCode, Uri as HyperUri}; +use hyper_tls::HttpsConnector; +use hyperlocal::{UnixClientExt, Uri as HyperLocalUri}; +use std::net::SocketAddr; +use std::path::Path; +use unit_client_rs::control_socket_address::ControlSocket; + +/// The HTML index page we serve from the UI server +const HTML_INDEX: &str = include_str!("../../www/index.html"); +/// The minified Rapidoc JS library we serve from the UI server that reads the OpenAPI spec +/// and renders the UI +const RAPIDOC_MIN_JS: &str = include_str!("../../www/rapidoc-min.js"); +/// The OpenAPI spec we serve from the UI server that Rapidoc reads to render the UI. +/// It is hardcoded here so that we do not need to make external network calls to fetch it. +const OPENAPI_SPEC: &str = include_str!("../../../../docs/unit-openapi.yaml"); + +pub(crate) fn cmd(cli: &UnitCtl, bind_address: &str, port: u16, debug: bool) -> Result<(), UnitctlError> { + let bind_ip_address = IpAddr::from_str(bind_address).map_err(|e| UnitctlError::IoError { + source: IoError::new(std::io::ErrorKind::InvalidInput, e), + })?; + let control_socket = wait::wait_for_socket(cli)?; + start_ui(control_socket, bind_ip_address, port, debug) +} + +/// Start the UI server +pub fn start_ui( + control_socket: ControlSocket, + bind_address: IpAddr, + port: u16, + debug: bool, +) -> Result<(), UnitctlError> { + if debug { + if control_socket.is_local_socket() { + eprintln!("Using local socket: {}", control_socket); + } else { + eprintln!("Using tcp socket: {}", control_socket); + } + } + + let normalized_control_socket_address = control_socket.to_string(); + + let ui_runtime = tokio::runtime::Builder::new_current_thread() + .enable_all() + .build() + .expect("Unable to create a current_thread runtime"); + + ui_runtime + .block_on(async move { run(normalized_control_socket_address, bind_address, port, debug).await }) + .map_err(|e| UnitctlError::UiServerError { + message: format!("Error running UI: {}", e), + }) +} + +#[derive(Debug, Clone)] +struct RequestForwarder { + control_socket: String, + rapidoc_request_path: String, + debug: bool, +} + +impl RequestForwarder { + fn new(control_socket: String, debug: bool) -> Self { + RequestForwarder { + control_socket, + rapidoc_request_path: format!("/rapidoc@{}/dist/rapidoc-min.js", Self::rapidoc_version()), + debug, + } + } + + /// Get the version of the Rapidoc library we are serving from its minified JS file. + fn rapidoc_version() -> &'static str { + match RAPIDOC_MIN_JS.lines().next() { + Some(first_line) => { + let version = first_line + .strip_prefix("/*! RapiDoc ") + .map(|remaining| remaining.split_once(' ').unwrap().1); + match version { + Some(version) => version, + None => panic!("Failed to parse RapiDoc version from rapidoc-min.js"), + } + } + None => panic!("Failed to read first line of rapidoc-min.js"), + } + } + + /// Execute a client request against the UNIT control socket + fn execute_client_request(&self, request: Request) -> ResponseFuture { + let is_unix_local_socket = self.control_socket.starts_with("unix:"); + if is_unix_local_socket { + Client::unix().request(request) + } else { + Client::builder().build(HttpsConnector::new()).request(request) + } + } + + /// Handle an incoming request to UNIT by forwarding it to the control socket + async fn handle_request(&self, request: Request) -> HyperResult> { + // Build our request URI differently depending on if we are using a local unix socket + let uri: HyperUri = match self.control_socket.strip_prefix("unix:") { + Some(socket_path) => HyperLocalUri::new(Path::new(socket_path), request.uri().path()).into(), + None => HyperUri::from_str(format!("{}{}", self.control_socket, request.uri().path()).as_str()) + .expect("Failed to build URI"), + }; + let client_request = Request::builder() + .method(request.method()) + .uri(uri) + .body(request.into_body()) + .expect("Failed to build request"); + + let response = self.execute_client_request(client_request).await; + match response { + Ok(mut response) => { + response + .headers_mut() + .append("Cache-Control", "no-cache, no-store, must-revalidate".parse().unwrap()); + response.headers_mut().append("Pragma", "no-cache".parse().unwrap()); + response.headers_mut().append("Expires", "0".parse().unwrap()); + Ok(response) + } + Err(e) => { + eprintln!("Error forwarding request: {:?}", e); + Ok(Response::builder() + .status(StatusCode::INTERNAL_SERVER_ERROR) + .body(Body::from("Internal Server Error")) + .unwrap()) + } + } + } +} + +/// Handle an incoming request to the UI server by routing it to the appropriate handler. +/// Generally all requests made outside of the /control-ui/ directory will be forwarded +/// directly to the control socket. +async fn request_router(req: Request, forwarder: RequestForwarder) -> HyperResult> { + if forwarder.debug { + eprintln!("Request: {:?}", req.uri()); + eprintln!(" {:?}", req.headers()); + } + + // Remap the request path to serve the rapidoc-min.js file if requested with a hardcoded + // version number. We do this so that we can easily change the version number of the + // Rapidoc library. + let path = if req.uri().path().eq(forwarder.rapidoc_request_path.as_str()) { + eprintln!("Remapping request {} to /control-ui/rapidoc-min.js", req.uri().path()); + "/control-ui/rapidoc-min.js" + } else { + req.uri().path() + }; + let response = match path { + "/control-ui/" => Ok(Response::builder() + .status(StatusCode::OK) + .header("Content-Type", "text/html") + .body(HTML_INDEX.into()) + .unwrap()), + "/control-ui/rapidoc-min.js" => Ok(Response::builder() + .status(StatusCode::OK) + .header("Content-Type", "application/javascript") + .body(RAPIDOC_MIN_JS.into()) + .unwrap()), + "/control-ui/unit-openapi.yaml" => Ok(Response::builder() + .status(StatusCode::OK) + .header("Content-Type", "application/x-yaml") + .body(OPENAPI_SPEC.into()) + .unwrap()), + "/favicon.ico" => Ok(Response::builder() + .status(StatusCode::NOT_FOUND) + .body(Body::empty()) + .unwrap()), + _ => forwarder.handle_request(req).await, + }; + + if forwarder.debug { + if let Ok(response) = &response { + eprintln!("Response status: {:?}", response.status()); + eprintln!("Response headers:\n {:?}", response.headers()); + } else { + eprintln!("Response error: {:?}", response); + } + } + + response +} + +/// Start the UI server using Tokio +async fn run(control_socket: String, bind_address: IpAddr, port: u16, debug: bool) -> HyperResult<()> { + // Set the address to run our server on + let addr = SocketAddr::new(bind_address, port); + eprintln!("Starting UI server on http://{}/control-ui/", addr); + eprintln!("Press Ctrl-C to stop the server"); + + let make_service = make_service_fn(move |_| { + let request_handler = RequestForwarder::new(control_socket.to_owned(), debug.to_owned()); + + async { + // This is the `Service` that will handle the connection. + // `service_fn` is a helper to convert a function that + // returns a Response into a `Service`. + Ok::<_, Infallible>(service_fn(move |req| request_router(req, request_handler.to_owned()))) + } + }); + + Server::bind(&addr).serve(make_service).await +} diff --git a/cli/unitctl/src/inputfile.rs b/cli/unitctl/src/inputfile.rs new file mode 100644 index 000000000..b2479d505 --- /dev/null +++ b/cli/unitctl/src/inputfile.rs @@ -0,0 +1,289 @@ +use std::collections::HashMap; +use std::io; +use std::io::{BufRead, BufReader, Error as IoError, Read}; +use std::path::{Path, PathBuf}; + +use crate::known_size::KnownSize; +use clap::ValueEnum; + +use super::UnitSerializableMap; +use super::UnitctlError; + +/// Input file data format +#[derive(ValueEnum, Copy, Clone, Debug, PartialEq, Eq)] +pub enum InputFormat { + Yaml, + Json, + Json5, + Hjson, + Pem, + JavaScript, + Unknown, +} + +impl InputFormat { + pub fn from_file_extension(file_extension: S) -> Self + where + S: Into, + { + match file_extension.into().to_lowercase().as_str() { + "yaml" => InputFormat::Yaml, + "yml" => InputFormat::Yaml, + "json" => InputFormat::Json, + "json5" => InputFormat::Json5, + "hjson" => InputFormat::Hjson, + "cjson" => InputFormat::Hjson, + "pem" => InputFormat::Pem, + "js" => InputFormat::JavaScript, + "njs" => InputFormat::JavaScript, + _ => InputFormat::Unknown, + } + } + + /// This function allows us to infer the input format based on the remote path which is + /// useful when processing input from STDIN. + pub fn from_remote_path(remote_path: S) -> Self + where + S: Into, + { + let remote_upload_path = remote_path.into(); + let lead_slash_removed = remote_upload_path.trim_start_matches('/'); + let first_path = lead_slash_removed + .split_once('/') + .map_or(lead_slash_removed, |(first, _)| first); + match first_path { + "config" => InputFormat::Hjson, + "certificates" => InputFormat::Pem, + "js_modules" => InputFormat::JavaScript, + _ => InputFormat::Json, + } + } +} + +/// A "file" that can be used as input to a command +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum InputFile { + // Data received via STDIN + Stdin(InputFormat), + // Data that is on the file system where the format is inferred from the extension + File(Box), + // Data that is on the file system where the format is explicitly specified + FileWithFormat(Box, InputFormat), +} + +impl InputFile { + /// Creates a new instance of `InputFile` from a string + pub fn new(file_path_or_dash: S, remote_path: S) -> Self + where + S: Into, + { + let file_path: String = file_path_or_dash.into(); + + match file_path.as_str() { + "-" => InputFile::Stdin(InputFormat::from_remote_path(remote_path)), + _ => InputFile::File(PathBuf::from(&file_path).into_boxed_path()), + } + } + + /// Returns the format of the input file + pub fn format(&self) -> InputFormat { + match self { + InputFile::Stdin(format) => *format, + InputFile::File(path) => { + // Figure out the file format based on the file extension + match path.extension().and_then(|s| s.to_str()) { + Some(ext) => InputFormat::from_file_extension(ext), + None => InputFormat::Unknown, + } + } + InputFile::FileWithFormat(_file, format) => *format, + } + } + + pub fn mime_type(&self) -> String { + match self.format() { + InputFormat::Yaml => "application/x-yaml".to_string(), + InputFormat::Json => "application/json".to_string(), + InputFormat::Json5 => "application/json5".to_string(), + InputFormat::Hjson => "application/hjson".to_string(), + InputFormat::Pem => "application/x-pem-file".to_string(), + InputFormat::JavaScript => "application/javascript".to_string(), + InputFormat::Unknown => "application/octet-stream".to_string(), + } + } + + /// Returns true if the input file is in the format of a configuration file + pub fn is_config(&self) -> bool { + matches!( + self.format(), + InputFormat::Yaml | InputFormat::Json | InputFormat::Json5 | InputFormat::Hjson + ) + } + + pub fn is_javascript(&self) -> bool { + matches!(self.format(), InputFormat::JavaScript) + } + + pub fn is_pem_bundle(&self) -> bool { + matches!(self.format(), InputFormat::Pem) + } + + /// Returns the path to the input file if it is a file and not a stream + pub fn to_path(&self) -> Result<&Path, UnitctlError> { + match self { + InputFile::Stdin(_) => { + let io_error = IoError::new(std::io::ErrorKind::InvalidInput, "Input file is stdin"); + Err(UnitctlError::IoError { source: io_error }) + } + InputFile::File(path) | InputFile::FileWithFormat(path, _) => Ok(path), + } + } + + /// Converts a HJSON Value type to a JSON Value type + fn hjson_value_to_json_value(value: nu_json::Value) -> serde_json::Value { + serde_json::to_value(value).expect("Failed to convert HJSON value to JSON value") + } + + pub fn to_unit_serializable_map(&self) -> Result { + let reader: Box = self.try_into()?; + let body_data: UnitSerializableMap = match self.format() { + InputFormat::Yaml => serde_yaml::from_reader(reader) + .map_err(|e| UnitctlError::DeserializationError { message: e.to_string() })?, + InputFormat::Json => serde_json::from_reader(reader) + .map_err(|e| UnitctlError::DeserializationError { message: e.to_string() })?, + InputFormat::Json5 => { + let mut reader = BufReader::new(reader); + let mut json5_string: String = String::new(); + reader + .read_to_string(&mut json5_string) + .map_err(|e| UnitctlError::DeserializationError { message: e.to_string() })?; + json5::from_str(&json5_string) + .map_err(|e| UnitctlError::DeserializationError { message: e.to_string() })? + } + InputFormat::Hjson => { + let hjson_value: HashMap = nu_json::from_reader(reader) + .map_err(|e| UnitctlError::DeserializationError { message: e.to_string() })?; + + hjson_value + .iter() + .map(|(k, v)| { + let json_value = Self::hjson_value_to_json_value(v.clone()); + (k.clone(), json_value) + }) + .collect() + } + _ => Err(UnitctlError::DeserializationError { + message: format!("Unsupported input format for serialization: {:?}", self), + })?, + }; + Ok(body_data) + } +} + +impl From<&Path> for InputFile { + fn from(path: &Path) -> Self { + InputFile::File(path.into()) + } +} + +impl TryInto> for &InputFile { + type Error = UnitctlError; + + fn try_into(self) -> Result, Self::Error> { + let reader: Box = match self { + InputFile::Stdin(_) => Box::new(BufReader::new(io::stdin())), + InputFile::File(_) | InputFile::FileWithFormat(_, _) => { + let path = self.to_path()?; + let file = std::fs::File::open(path).map_err(|e| UnitctlError::IoError { source: e })?; + let reader = Box::new(BufReader::new(file)); + Box::new(reader) + } + }; + Ok(reader) + } +} + +impl TryInto> for &InputFile { + type Error = UnitctlError; + + fn try_into(self) -> Result, Self::Error> { + let mut buf: Vec = vec![]; + let mut reader: Box = self.try_into()?; + reader + .read_to_end(&mut buf) + .map_err(|e| UnitctlError::IoError { source: e })?; + Ok(buf) + } +} + +impl TryInto for &InputFile { + type Error = UnitctlError; + + fn try_into(self) -> Result { + let known_size: KnownSize = match self { + InputFile::Stdin(_) => { + let mut buf: Vec = vec![]; + let _ = io::stdin() + .read_to_end(&mut buf) + .map_err(|e| UnitctlError::IoError { source: e })?; + KnownSize::Vec(buf) + } + InputFile::File(_) | InputFile::FileWithFormat(_, _) => { + let path = self.to_path()?; + let file = std::fs::File::open(path).map_err(|e| UnitctlError::IoError { source: e })?; + let len = file.metadata().map_err(|e| UnitctlError::IoError { source: e })?.len(); + let reader = Box::new(file); + KnownSize::Read(reader, len) + } + }; + Ok(known_size) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn can_parse_file_extensions() { + assert_eq!(InputFormat::from_file_extension("yaml"), InputFormat::Yaml); + assert_eq!(InputFormat::from_file_extension("yml"), InputFormat::Yaml); + assert_eq!(InputFormat::from_file_extension("json"), InputFormat::Json); + assert_eq!(InputFormat::from_file_extension("json5"), InputFormat::Json5); + assert_eq!(InputFormat::from_file_extension("pem"), InputFormat::Pem); + assert_eq!(InputFormat::from_file_extension("js"), InputFormat::JavaScript); + assert_eq!(InputFormat::from_file_extension("njs"), InputFormat::JavaScript); + assert_eq!(InputFormat::from_file_extension("txt"), InputFormat::Unknown); + } + + #[test] + fn can_parse_remote_paths() { + assert_eq!(InputFormat::from_remote_path("//config"), InputFormat::Hjson); + assert_eq!(InputFormat::from_remote_path("/config"), InputFormat::Hjson); + assert_eq!(InputFormat::from_remote_path("/config/"), InputFormat::Hjson); + assert_eq!(InputFormat::from_remote_path("config/"), InputFormat::Hjson); + assert_eq!(InputFormat::from_remote_path("config"), InputFormat::Hjson); + assert_eq!(InputFormat::from_remote_path("/config/something/"), InputFormat::Hjson); + assert_eq!(InputFormat::from_remote_path("config/something/"), InputFormat::Hjson); + assert_eq!(InputFormat::from_remote_path("config/something"), InputFormat::Hjson); + assert_eq!(InputFormat::from_remote_path("/certificates"), InputFormat::Pem); + assert_eq!(InputFormat::from_remote_path("/certificates/"), InputFormat::Pem); + assert_eq!(InputFormat::from_remote_path("certificates/"), InputFormat::Pem); + assert_eq!(InputFormat::from_remote_path("certificates"), InputFormat::Pem); + assert_eq!(InputFormat::from_remote_path("js_modules"), InputFormat::JavaScript); + assert_eq!(InputFormat::from_remote_path("js_modules/"), InputFormat::JavaScript); + + assert_eq!( + InputFormat::from_remote_path("/certificates/something/"), + InputFormat::Pem + ); + assert_eq!( + InputFormat::from_remote_path("certificates/something/"), + InputFormat::Pem + ); + assert_eq!( + InputFormat::from_remote_path("certificates/something"), + InputFormat::Pem + ); + } +} diff --git a/cli/unitctl/src/known_size.rs b/cli/unitctl/src/known_size.rs new file mode 100644 index 000000000..d73aff915 --- /dev/null +++ b/cli/unitctl/src/known_size.rs @@ -0,0 +1,77 @@ +use futures::Stream; +use hyper::Body; +use std::io; +use std::io::{Cursor, Read}; +use std::pin::Pin; +use std::task::{Context, Poll}; + +pub enum KnownSize { + Vec(Vec), + Read(Box, u64), + String(String), + Empty, +} + +impl KnownSize { + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + pub fn len(&self) -> u64 { + match self { + KnownSize::Vec(v) => v.len() as u64, + KnownSize::Read(_, size) => *size, + KnownSize::String(s) => s.len() as u64, + KnownSize::Empty => 0, + } + } +} + +impl Stream for KnownSize { + type Item = io::Result>; + + fn poll_next(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll> { + let buf = &mut [0u8; 1024]; + + if let KnownSize::Read(r, _) = self.get_mut() { + return match r.read(buf) { + Ok(0) => Poll::Ready(None), + Ok(n) => Poll::Ready(Some(Ok(buf[..n].to_vec()))), + Err(e) => Poll::Ready(Some(Err(e))), + }; + } + + panic!("not implemented") + } + + fn size_hint(&self) -> (usize, Option) { + (0, Some(self.len() as usize)) + } +} + +impl From for Box { + fn from(value: KnownSize) -> Self { + match value { + KnownSize::Vec(v) => Box::new(Cursor::new(v)), + KnownSize::Read(r, _) => r, + KnownSize::String(s) => Box::new(Cursor::new(s)), + KnownSize::Empty => Box::new(Cursor::new(Vec::new())), + } + } +} + +impl From for Body { + fn from(value: KnownSize) -> Self { + if value.is_empty() { + return Body::empty(); + } + if let KnownSize::Vec(v) = value { + return Body::from(v); + } + if let KnownSize::String(s) = value { + return Body::from(s); + } + + Body::wrap_stream(value) + } +} diff --git a/cli/unitctl/src/main.rs b/cli/unitctl/src/main.rs new file mode 100644 index 000000000..0070a17c9 --- /dev/null +++ b/cli/unitctl/src/main.rs @@ -0,0 +1,107 @@ +extern crate clap; +extern crate colored_json; +extern crate custom_error; +extern crate nu_json; +extern crate rustls_pemfile; +extern crate serde; +extern crate unit_client_rs; + +use clap::Parser; + +use crate::cmd::{edit, execute as execute_cmd, import, instances, listeners, status, ui}; +use crate::output_format::OutputFormat; +use crate::unitctl::{Commands, UnitCtl}; +use crate::unitctl_error::UnitctlError; +use unit_client_rs::unit_client::{UnitClient, UnitClientError, UnitSerializableMap}; + +mod cmd; +mod inputfile; +pub mod known_size; +mod output_format; +mod requests; +mod unitctl; +mod unitctl_error; +mod wait; + +fn main() -> Result<(), UnitctlError> { + let cli = UnitCtl::parse(); + + match cli.command { + Commands::Instances { output_format } => instances::cmd(output_format), + + Commands::Edit { output_format } => edit::cmd(&cli, output_format), + + Commands::Import { ref directory } => import::cmd(&cli, directory), + + Commands::Execute { + ref output_format, + ref input_file, + ref method, + ref path, + } => execute_cmd::cmd(&cli, output_format, input_file, method, path), + + Commands::Status { output_format } => status::cmd(&cli, output_format), + + Commands::Listeners { output_format } => listeners::cmd(&cli, output_format), + + Commands::Ui { + ref bind_address, + port, + debug, + } => ui::cmd(&cli, bind_address, port, debug), + } + .map_err(|error| { + eprint_error(&error); + std::process::exit(error.exit_code()); + }) +} + +fn eprint_error(error: &UnitctlError) { + match error { + UnitctlError::NoUnitInstancesError => { + eprintln!("No running unit instances found"); + } + UnitctlError::MultipleUnitInstancesError { ref suggestion } => { + eprintln!("{}", suggestion); + } + UnitctlError::NoSocketPathError => { + eprintln!("Unable to detect socket path from running instance"); + } + UnitctlError::UnitClientError { source } => match source { + UnitClientError::SocketPermissionsError { .. } => { + eprintln!("{}", source); + eprintln!("Try running again with the same permissions as the unit control socket"); + } + _ => { + eprintln!("Unit client error: {}", source); + } + }, + UnitctlError::SerializationError { message } => { + eprintln!("Serialization error: {}", message); + } + UnitctlError::DeserializationError { message } => { + eprintln!("Deserialization error: {}", message); + } + UnitctlError::IoError { ref source } => { + eprintln!("IO error: {}", source); + } + UnitctlError::PathNotFound { path } => { + eprintln!("Path not found: {}", path); + } + UnitctlError::EditorError { message } => { + eprintln!("Error opening editor: {}", message); + } + UnitctlError::CertificateError { message } => { + eprintln!("Certificate error: {}", message); + } + UnitctlError::NoInputFileError => { + eprintln!("No input file specified when required"); + } + UnitctlError::UiServerError { ref message } => { + eprintln!("UI server error: {}", message); + } + _ => { + eprintln!("{}", error); + } + } +} diff --git a/cli/unitctl/src/output_format.rs b/cli/unitctl/src/output_format.rs new file mode 100644 index 000000000..eb7f954e2 --- /dev/null +++ b/cli/unitctl/src/output_format.rs @@ -0,0 +1,43 @@ +use crate::UnitctlError; +use clap::ValueEnum; +use colored_json::ColorMode; +use serde::Serialize; +use std::io::{stdout, BufWriter, Write}; + +#[derive(ValueEnum, Copy, Clone, Debug, PartialEq, Eq)] +pub(crate) enum OutputFormat { + Yaml, + Json, + #[value(id = "json-pretty")] + JsonPretty, + Text, +} + +impl OutputFormat { + pub fn write_to_stdout(&self, object: &T) -> Result<(), UnitctlError> + where + T: ?Sized + Serialize, + { + let no_color = std::env::var("NO_COLOR").map_or(false, |_| true); + let mut out = stdout(); + let value = + serde_json::to_value(object).map_err(|e| UnitctlError::SerializationError { message: e.to_string() })?; + + match (self, no_color) { + (OutputFormat::Yaml, _) => serde_yaml::to_writer(BufWriter::new(out), &value) + .map_err(|e| UnitctlError::SerializationError { message: e.to_string() }), + (OutputFormat::Json, _) => serde_json::to_writer(BufWriter::new(out), &value) + .map_err(|e| UnitctlError::SerializationError { message: e.to_string() }), + (OutputFormat::JsonPretty, true) => serde_json::to_writer_pretty(BufWriter::new(out), &value) + .map_err(|e| UnitctlError::SerializationError { message: e.to_string() }), + (OutputFormat::JsonPretty, false) => { + let mode = ColorMode::Auto(colored_json::Output::StdOut); + colored_json::write_colored_json_with_mode(&value, &mut out, mode) + .map_err(|e| UnitctlError::SerializationError { message: e.to_string() }) + } + (OutputFormat::Text, _) => stdout() + .write_fmt(format_args!("{:?}", &value)) + .map_err(|e| UnitctlError::IoError { source: e }), + } + } +} diff --git a/cli/unitctl/src/requests.rs b/cli/unitctl/src/requests.rs new file mode 100644 index 000000000..bd47c6453 --- /dev/null +++ b/cli/unitctl/src/requests.rs @@ -0,0 +1,175 @@ +use super::inputfile::InputFile; +use super::UnitClient; +use super::UnitSerializableMap; +use super::UnitctlError; +use crate::known_size::KnownSize; +use hyper::{Body, Request}; +use rustls_pemfile::Item; +use std::collections::HashMap; +use std::io::Cursor; +use std::sync::atomic::AtomicUsize; +use unit_client_rs::unit_client::UnitClientError; + +/// Send the contents of a file to the unit server +/// We assume that the file is valid and can be sent to the server +pub fn send_and_validate_config_deserialize_response( + client: &UnitClient, + method: &str, + path: &str, + input_file: Option<&InputFile>, +) -> Result { + let body_data = match input_file { + Some(input) => Some(input.to_unit_serializable_map()?), + None => None, + }; + + /* Unfortunately, we have load the json text into memory before sending it to the server. + * This allows for validation of the json content before sending to the server. There may be + * a better way of doing this and it is worth investigating. */ + let json = serde_json::to_value(&body_data).map_err(|error| UnitClientError::JsonError { + source: error, + path: path.into(), + })?; + + let mime_type = input_file.map(|f| f.mime_type()); + let reader = KnownSize::String(json.to_string()); + + streaming_upload_deserialize_response(client, method, path, mime_type, reader) + .map_err(|e| UnitctlError::UnitClientError { source: e }) +} + +/// Send an empty body to the unit server +pub fn send_empty_body_deserialize_response( + client: &UnitClient, + method: &str, + path: &str, +) -> Result { + send_body_deserialize_response(client, method, path, None) +} + +/// Send the contents of a PEM file to the unit server +pub fn send_and_validate_pem_data_deserialize_response( + client: &UnitClient, + method: &str, + path: &str, + input_file: &InputFile, +) -> Result { + let bytes: Vec = input_file.try_into()?; + { + let mut cursor = Cursor::new(&bytes); + let items = rustls_pemfile::read_all(&mut cursor) + .map(|item| item.map_err(|e| UnitctlError::IoError { source: e })) + .collect(); + validate_pem_items(items)?; + } + let known_size = KnownSize::Vec((*bytes).to_owned()); + + streaming_upload_deserialize_response(client, method, path, Some(input_file.mime_type()), known_size) + .map_err(|e| UnitctlError::UnitClientError { source: e }) +} + +/// Validate the contents of a PEM file +fn validate_pem_items(pem_items: Vec>) -> Result<(), UnitctlError> { + fn item_name(item: Item) -> String { + match item { + Item::X509Certificate(_) => "X509Certificate", + Item::Sec1Key(_) => "Sec1Key", + Item::Crl(_) => "Crl", + Item::Pkcs1Key(_) => "Pkcs1Key", + Item::Pkcs8Key(_) => "Pkcs8Key", + // Note: this is not a valid PEM item, but rustls_pemfile library defines the enum as non-exhaustive + _ => "Unknown", + } + .to_string() + } + + if pem_items.is_empty() { + let error = UnitctlError::CertificateError { + message: "No certificates found in file".to_string(), + }; + return Err(error); + } + + let mut items_tally: HashMap = HashMap::new(); + + for pem_item_result in pem_items { + let pem_item = pem_item_result?; + let key = item_name(pem_item); + if let Some(count) = items_tally.get_mut(key.clone().as_str()) { + count.fetch_add(1, std::sync::atomic::Ordering::Relaxed); + } else { + items_tally.insert(key, AtomicUsize::new(1)); + } + } + + let key_count = items_tally + .iter() + .filter(|(key, _)| key.ends_with("Key")) + .fold(0, |acc, (_, count)| { + acc + count.load(std::sync::atomic::Ordering::Relaxed) + }); + let cert_count = items_tally + .iter() + .filter(|(key, _)| key.ends_with("Certificate")) + .fold(0, |acc, (_, count)| { + acc + count.load(std::sync::atomic::Ordering::Relaxed) + }); + + if key_count == 0 { + let error = UnitctlError::CertificateError { + message: "No private keys found in file".to_string(), + }; + return Err(error); + } + if cert_count == 0 { + let error = UnitctlError::CertificateError { + message: "No certificates found in file".to_string(), + }; + return Err(error); + } + + Ok(()) +} + +pub fn send_body_deserialize_response serde::Deserialize<'de>>( + client: &UnitClient, + method: &str, + path: &str, + input_file: Option<&InputFile>, +) -> Result { + match input_file { + Some(input) => { + streaming_upload_deserialize_response(client, method, path, Some(input.mime_type()), input.try_into()?) + } + None => streaming_upload_deserialize_response(client, method, path, None, KnownSize::Empty), + } + .map_err(|e| UnitctlError::UnitClientError { source: e }) +} + +fn streaming_upload_deserialize_response serde::Deserialize<'de>>( + client: &UnitClient, + method: &str, + path: &str, + mime_type: Option, + read: KnownSize, +) -> Result { + let uri = client.control_socket.create_uri_with_path(path); + + let content_length = read.len(); + let body = Body::from(read); + + let mut request = Request::builder() + .method(method) + .header("Content-Length", content_length) + .uri(uri) + .body(body) + .expect("Unable to build request"); + + if let Some(content_type) = mime_type { + request + .headers_mut() + .insert("Content-Type", content_type.parse().unwrap()); + } + + client.send_request_and_deserialize_response(request) +} diff --git a/cli/unitctl/src/unitctl.rs b/cli/unitctl/src/unitctl.rs new file mode 100644 index 000000000..2d0bd8675 --- /dev/null +++ b/cli/unitctl/src/unitctl.rs @@ -0,0 +1,171 @@ +extern crate clap; + +use crate::output_format::OutputFormat; +use clap::error::ErrorKind::ValueValidation; +use clap::{Error as ClapError, Parser, Subcommand}; +use std::path::PathBuf; +use unit_client_rs::control_socket_address::ControlSocket; + +#[derive(Parser, Debug)] +#[command(author, version, about, long_about)] +pub(crate) struct UnitCtl { + #[arg( + required = false, + short = 's', + long = "control-socket-address", + value_parser = parse_control_socket_address, + help = "Path (unix:/var/run/unit/control.sock), tcp address with port (127.0.0.1:80), or URL" + )] + pub(crate) control_socket_address: Option, + #[arg( + required = false, + default_missing_value = "1", + value_parser = parse_u8, + short = 'w', + long = "wait-timeout-seconds", + help = "Number of seconds to wait for control socket to become available" + )] + pub(crate) wait_time_seconds: Option, + #[arg( + required = false, + default_value = "3", + value_parser = parse_u8, + short = 't', + long = "wait-max-tries", + help = "Number of times to try to access control socket when waiting" + )] + pub(crate) wait_max_tries: Option, + #[command(subcommand)] + pub(crate) command: Commands, +} + +#[derive(Debug, Subcommand)] +pub(crate) enum Commands { + #[command(about = "List all running UNIT processes")] + Instances { + #[arg( + required = false, + global = true, + short = 't', + long = "output-format", + default_value = "text", + help = "Output format: text, yaml, json, json-pretty (default)" + )] + output_format: OutputFormat, + }, + #[command(about = "Open current UNIT configuration in editor")] + Edit { + #[arg( + required = false, + global = true, + short = 't', + long = "output-format", + default_value = "json-pretty", + help = "Output format: yaml, json, json-pretty (default)" + )] + output_format: OutputFormat, + }, + #[command(about = "Import configuration from a directory")] + Import { + #[arg(required = true, help = "Directory to import from")] + directory: PathBuf, + }, + #[command(about = "Sends raw JSON payload to UNIT")] + Execute { + #[arg( + required = false, + global = true, + short = 't', + long = "output-format", + default_value = "json-pretty", + help = "Output format: yaml, json, json-pretty (default)" + )] + output_format: OutputFormat, + #[arg( + required = false, + global = true, + short = 'f', + long = "file", + help = "Input file (json, json5, cjson, hjson yaml, pem) to send to unit when applicable use - for stdin" + )] + input_file: Option, + #[arg( + help = "HTTP method to use (GET, POST, PUT, DELETE)", + required = true, + short = 'm', + long = "http-method", + value_parser = parse_http_method, + )] + method: String, + #[arg(required = true, short = 'p', long = "path")] + path: String, + }, + #[command(about = "Get the current status of UNIT")] + Status { + #[arg( + required = false, + global = true, + short = 't', + long = "output-format", + default_value = "json-pretty", + help = "Output format: yaml, json, json-pretty (default)" + )] + output_format: OutputFormat, + }, + #[command(about = "List active listeners")] + Listeners { + #[arg( + required = false, + global = true, + short = 't', + long = "output-format", + default_value = "json-pretty", + help = "Output format: yaml, json, json-pretty (default)" + )] + output_format: OutputFormat, + }, + #[command(about = "Start an interactive web UI")] + Ui { + #[arg( + required = false, + short = 'b', + long = "bind-address", + default_value = "127.0.0.1", + help = "Address to bind to" + )] + bind_address: String, + #[arg( + required = false, + short = 'p', + long = "port", + default_value = "3000", + help = "Port to listen on" + )] + port: u16, + #[arg( + required = false, + short = 'd', + long = "debug", + default_value = "false", + help = "Enable debug request/response logging" + )] + debug: bool, + }, +} + +fn parse_control_socket_address(s: &str) -> Result { + ControlSocket::try_from(s).map_err(|e| ClapError::raw(ValueValidation, e.to_string())) +} + +fn parse_http_method(s: &str) -> Result { + let method = s.to_uppercase(); + match method.as_str() { + "GET" | "POST" | "PUT" | "DELETE" => Ok(method), + _ => Err(ClapError::raw(ValueValidation, format!("Invalid HTTP method: {}", s))), + } +} + +fn parse_u8(s: &str) -> Result { + s.parse::() + .map_err(|e| ClapError::raw(ValueValidation, format!("Invalid number: {}", e))) +} diff --git a/cli/unitctl/src/unitctl_error.rs b/cli/unitctl/src/unitctl_error.rs new file mode 100644 index 000000000..1cf4fe485 --- /dev/null +++ b/cli/unitctl/src/unitctl_error.rs @@ -0,0 +1,72 @@ +use std::fmt::{Display, Formatter}; +use std::io::Error as IoError; +use std::process::{ExitCode, Termination}; +use unit_client_rs::unit_client::UnitClientError; + +use custom_error::custom_error; + +#[derive(Debug, Clone, PartialEq, Eq)] +pub(crate) enum ControlSocketErrorKind { + NotFound, + Permissions, + Parse, + General, +} + +impl Display for ControlSocketErrorKind { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + writeln!(f, "{:?}", self) + } +} + +custom_error! {pub UnitctlError + ControlSocketError { kind: ControlSocketErrorKind, message: String } = "{message}", + CertificateError { message: String } = "Certificate error: {message}", + EditorError { message: String } = "Error opening editor: {message}", + NoUnitInstancesError = "No running unit instances found", + MultipleUnitInstancesError { + suggestion: String} = "Multiple unit instances found: {suggestion}", + NoSocketPathError = "Unable to detect socket path from running instance", + NoInputFileError = "No input file specified when required", + UiServerError { message: String } = "UI server error: {message}", + UnitClientError { source: UnitClientError } = "Unit client error: {source}", + SerializationError { message: String } = "Serialization error: {message}", + DeserializationError { message: String } = "Deserialization error: {message}", + IoError { source: IoError } = "IO error: {source}", + PathNotFound { path: String } = "Path not found: {path}", + UnknownInputFileType { path: String } = "Unknown input type for file: {path}", + NoFilesImported = "All imports failed", + WaitTimeoutError = "Timeout waiting for unit to start has been exceeded", +} + +impl UnitctlError { + pub fn exit_code(&self) -> i32 { + match self { + UnitctlError::NoUnitInstancesError => 10, + UnitctlError::MultipleUnitInstancesError { .. } => 11, + UnitctlError::NoSocketPathError => 12, + UnitctlError::UnitClientError { .. } => 13, + UnitctlError::WaitTimeoutError => 14, + _ => 99, + } + } + + pub fn retryable(&self) -> bool { + match self { + UnitctlError::ControlSocketError { kind, .. } => { + // try again because there is no socket created yet + ControlSocketErrorKind::NotFound == *kind + } + // try again because unit isn't running + UnitctlError::NoUnitInstancesError => true, + // do not retry because this is an unrecoverable error + _ => false, + } + } +} + +impl Termination for UnitctlError { + fn report(self) -> ExitCode { + ExitCode::from(self.exit_code() as u8) + } +} diff --git a/cli/unitctl/src/wait.rs b/cli/unitctl/src/wait.rs new file mode 100644 index 000000000..998dc59c5 --- /dev/null +++ b/cli/unitctl/src/wait.rs @@ -0,0 +1,165 @@ +use crate::unitctl::UnitCtl; +use crate::unitctl_error::{ControlSocketErrorKind, UnitctlError}; +use std::time::Duration; +use unit_client_rs::control_socket_address::ControlSocket; +use unit_client_rs::unit_client::{UnitClient, UnitClientError}; +use unit_client_rs::unitd_instance::UnitdInstance; + +/// Waits for a socket to become available. Availability is tested by attempting to access the +/// status endpoint via the control socket. When socket is available, ControlSocket instance +/// is returned. +pub fn wait_for_socket(cli: &UnitCtl) -> Result { + // Don't wait, if wait_time is not specified + if cli.wait_time_seconds.is_none() { + return cli.control_socket_address.instance_value_if_none().and_validate(); + } + + let wait_time = + Duration::from_secs(cli.wait_time_seconds.expect("wait_time_option default was not applied") as u64); + let max_tries = cli.wait_max_tries.expect("max_tries_option default was not applied"); + + let mut attempt: u8 = 0; + let mut control_socket: ControlSocket; + while attempt < max_tries { + if attempt > 0 { + eprintln!( + "Waiting for {}s control socket to be available try {}/{}...", + wait_time.as_secs(), + attempt + 1, + max_tries + ); + std::thread::sleep(wait_time); + } + + attempt += 1; + + let result = cli.control_socket_address.instance_value_if_none().and_validate(); + + if let Err(error) = result { + if error.retryable() { + continue; + } else { + return Err(error); + } + } + + control_socket = result.unwrap(); + let client = UnitClient::new(control_socket.clone()); + + match client.status() { + Ok(_) => { + return Ok(control_socket.to_owned()); + } + Err(error) => { + eprintln!("Unable to access status endpoint: {}", *error); + continue; + } + } + } + + if attempt >= max_tries { + Err(UnitctlError::WaitTimeoutError) + } else { + panic!("Unexpected state - this should never happen"); + } +} + +trait OptionControlSocket { + fn instance_value_if_none(&self) -> Result; +} + +impl OptionControlSocket for Option { + fn instance_value_if_none(&self) -> Result { + if let Some(control_socket) = self { + Ok(control_socket.to_owned()) + } else { + find_socket_address_from_instance() + } + } +} + +trait ResultControlSocket { + fn and_validate(self) -> Result; +} + +impl ResultControlSocket for Result { + fn and_validate(self) -> Result { + self.and_then(|control_socket| { + control_socket.validate().map_err(|error| match error { + UnitClientError::UnixSocketNotFound { .. } => UnitctlError::ControlSocketError { + kind: ControlSocketErrorKind::NotFound, + message: format!("{}", error), + }, + UnitClientError::SocketPermissionsError { .. } => UnitctlError::ControlSocketError { + kind: ControlSocketErrorKind::Permissions, + message: format!("{}", error), + }, + UnitClientError::TcpSocketAddressUriError { .. } + | UnitClientError::TcpSocketAddressNoPortError { .. } + | UnitClientError::TcpSocketAddressParseError { .. } => UnitctlError::ControlSocketError { + kind: ControlSocketErrorKind::Parse, + message: format!("{}", error), + }, + _ => UnitctlError::ControlSocketError { + kind: ControlSocketErrorKind::General, + message: format!("{}", error), + }, + }) + }) + } +} + +fn find_socket_address_from_instance() -> Result { + let instances = UnitdInstance::running_unitd_instances(); + if instances.is_empty() { + return Err(UnitctlError::NoUnitInstancesError); + } else if instances.len() > 1 { + let suggestion: String = "Multiple unit instances found. Specify the socket address to the instance you wish \ + to control using the `--control-socket-address` flag" + .to_string(); + return Err(UnitctlError::MultipleUnitInstancesError { suggestion }); + } + + let instance = instances.first().unwrap(); + match instance.control_api_socket_address() { + Some(path) => Ok(ControlSocket::try_from(path).unwrap()), + None => Err(UnitctlError::NoSocketPathError), + } +} + +#[test] +fn wait_for_unavailable_unix_socket() { + let control_socket = ControlSocket::try_from("unix:/tmp/this_socket_does_not_exist.sock"); + let cli = UnitCtl { + control_socket_address: Some(control_socket.unwrap()), + wait_time_seconds: Some(1u8), + wait_max_tries: Some(3u8), + command: crate::unitctl::Commands::Status { + output_format: crate::output_format::OutputFormat::JsonPretty, + }, + }; + let error = wait_for_socket(&cli).expect_err("Expected error, but no error received"); + match error { + UnitctlError::WaitTimeoutError => {} + _ => panic!("Expected WaitTimeoutError: {}", error), + } +} + +#[test] +fn wait_for_unavailable_tcp_socket() { + let control_socket = ControlSocket::try_from("http://127.0.0.1:9783456"); + let cli = UnitCtl { + control_socket_address: Some(control_socket.unwrap()), + wait_time_seconds: Some(1u8), + wait_max_tries: Some(3u8), + command: crate::unitctl::Commands::Status { + output_format: crate::output_format::OutputFormat::JsonPretty, + }, + }; + + let error = wait_for_socket(&cli).expect_err("Expected error, but no error received"); + match error { + UnitctlError::WaitTimeoutError => {} + _ => panic!("Expected WaitTimeoutError"), + } +} diff --git a/cli/unitctl/www/index.html b/cli/unitctl/www/index.html new file mode 100644 index 000000000..53c4afc51 --- /dev/null +++ b/cli/unitctl/www/index.html @@ -0,0 +1,24 @@ + + + + + Unit Control API + + + + + + + \ No newline at end of file diff --git a/cli/unitctl/www/rapidoc-min-9.3.4.js b/cli/unitctl/www/rapidoc-min-9.3.4.js new file mode 100644 index 000000000..0104e904a --- /dev/null +++ b/cli/unitctl/www/rapidoc-min-9.3.4.js @@ -0,0 +1,3895 @@ +/*! RapiDoc 9.3.4 | Author - Mrinmoy Majumdar | License information can be found in rapidoc-min.js.LICENSE.txt */ +(()=>{var e,t,r={656:(e,t,r)=>{"use strict";const n=window,o=n.ShadowRoot&&(void 0===n.ShadyCSS||n.ShadyCSS.nativeShadow)&&"adoptedStyleSheets"in Document.prototype&&"replace"in CSSStyleSheet.prototype,a=Symbol(),i=new WeakMap;class s{constructor(e,t,r){if(this._$cssResult$=!0,r!==a)throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");this.cssText=e,this.t=t}get styleSheet(){let e=this.o;const t=this.t;if(o&&void 0===e){const r=void 0!==t&&1===t.length;r&&(e=i.get(t)),void 0===e&&((this.o=e=new CSSStyleSheet).replaceSync(this.cssText),r&&i.set(t,e))}return e}toString(){return this.cssText}}const l=e=>new s("string"==typeof e?e:e+"",void 0,a),c=(e,...t)=>{const r=1===e.length?e[0]:t.reduce(((t,r,n)=>t+(e=>{if(!0===e._$cssResult$)return e.cssText;if("number"==typeof e)return e;throw Error("Value passed to 'css' function must be a 'css' function result: "+e+". Use 'unsafeCSS' to pass non-literal values, but take care to ensure page security.")})(r)+e[n+1]),e[0]);return new s(r,e,a)},p=o?e=>e:e=>e instanceof CSSStyleSheet?(e=>{let t="";for(const r of e.cssRules)t+=r.cssText;return l(t)})(e):e;var d;const u=window,h=u.trustedTypes,f=h?h.emptyScript:"",m=u.reactiveElementPolyfillSupport,y={toAttribute(e,t){switch(t){case Boolean:e=e?f:null;break;case Object:case Array:e=null==e?e:JSON.stringify(e)}return e},fromAttribute(e,t){let r=e;switch(t){case Boolean:r=null!==e;break;case Number:r=null===e?null:Number(e);break;case Object:case Array:try{r=JSON.parse(e)}catch(e){r=null}}return r}},g=(e,t)=>t!==e&&(t==t||e==e),v={attribute:!0,type:String,converter:y,reflect:!1,hasChanged:g};class b extends HTMLElement{constructor(){super(),this._$Ei=new Map,this.isUpdatePending=!1,this.hasUpdated=!1,this._$El=null,this.u()}static addInitializer(e){var t;this.finalize(),(null!==(t=this.h)&&void 0!==t?t:this.h=[]).push(e)}static get observedAttributes(){this.finalize();const e=[];return this.elementProperties.forEach(((t,r)=>{const n=this._$Ep(r,t);void 0!==n&&(this._$Ev.set(n,r),e.push(n))})),e}static createProperty(e,t=v){if(t.state&&(t.attribute=!1),this.finalize(),this.elementProperties.set(e,t),!t.noAccessor&&!this.prototype.hasOwnProperty(e)){const r="symbol"==typeof e?Symbol():"__"+e,n=this.getPropertyDescriptor(e,r,t);void 0!==n&&Object.defineProperty(this.prototype,e,n)}}static getPropertyDescriptor(e,t,r){return{get(){return this[t]},set(n){const o=this[e];this[t]=n,this.requestUpdate(e,o,r)},configurable:!0,enumerable:!0}}static getPropertyOptions(e){return this.elementProperties.get(e)||v}static finalize(){if(this.hasOwnProperty("finalized"))return!1;this.finalized=!0;const e=Object.getPrototypeOf(this);if(e.finalize(),void 0!==e.h&&(this.h=[...e.h]),this.elementProperties=new Map(e.elementProperties),this._$Ev=new Map,this.hasOwnProperty("properties")){const e=this.properties,t=[...Object.getOwnPropertyNames(e),...Object.getOwnPropertySymbols(e)];for(const r of t)this.createProperty(r,e[r])}return this.elementStyles=this.finalizeStyles(this.styles),!0}static finalizeStyles(e){const t=[];if(Array.isArray(e)){const r=new Set(e.flat(1/0).reverse());for(const e of r)t.unshift(p(e))}else void 0!==e&&t.push(p(e));return t}static _$Ep(e,t){const r=t.attribute;return!1===r?void 0:"string"==typeof r?r:"string"==typeof e?e.toLowerCase():void 0}u(){var e;this._$E_=new Promise((e=>this.enableUpdating=e)),this._$AL=new Map,this._$Eg(),this.requestUpdate(),null===(e=this.constructor.h)||void 0===e||e.forEach((e=>e(this)))}addController(e){var t,r;(null!==(t=this._$ES)&&void 0!==t?t:this._$ES=[]).push(e),void 0!==this.renderRoot&&this.isConnected&&(null===(r=e.hostConnected)||void 0===r||r.call(e))}removeController(e){var t;null===(t=this._$ES)||void 0===t||t.splice(this._$ES.indexOf(e)>>>0,1)}_$Eg(){this.constructor.elementProperties.forEach(((e,t)=>{this.hasOwnProperty(t)&&(this._$Ei.set(t,this[t]),delete this[t])}))}createRenderRoot(){var e;const t=null!==(e=this.shadowRoot)&&void 0!==e?e:this.attachShadow(this.constructor.shadowRootOptions);return((e,t)=>{o?e.adoptedStyleSheets=t.map((e=>e instanceof CSSStyleSheet?e:e.styleSheet)):t.forEach((t=>{const r=document.createElement("style"),o=n.litNonce;void 0!==o&&r.setAttribute("nonce",o),r.textContent=t.cssText,e.appendChild(r)}))})(t,this.constructor.elementStyles),t}connectedCallback(){var e;void 0===this.renderRoot&&(this.renderRoot=this.createRenderRoot()),this.enableUpdating(!0),null===(e=this._$ES)||void 0===e||e.forEach((e=>{var t;return null===(t=e.hostConnected)||void 0===t?void 0:t.call(e)}))}enableUpdating(e){}disconnectedCallback(){var e;null===(e=this._$ES)||void 0===e||e.forEach((e=>{var t;return null===(t=e.hostDisconnected)||void 0===t?void 0:t.call(e)}))}attributeChangedCallback(e,t,r){this._$AK(e,r)}_$EO(e,t,r=v){var n;const o=this.constructor._$Ep(e,r);if(void 0!==o&&!0===r.reflect){const a=(void 0!==(null===(n=r.converter)||void 0===n?void 0:n.toAttribute)?r.converter:y).toAttribute(t,r.type);this._$El=e,null==a?this.removeAttribute(o):this.setAttribute(o,a),this._$El=null}}_$AK(e,t){var r;const n=this.constructor,o=n._$Ev.get(e);if(void 0!==o&&this._$El!==o){const e=n.getPropertyOptions(o),a="function"==typeof e.converter?{fromAttribute:e.converter}:void 0!==(null===(r=e.converter)||void 0===r?void 0:r.fromAttribute)?e.converter:y;this._$El=o,this[o]=a.fromAttribute(t,e.type),this._$El=null}}requestUpdate(e,t,r){let n=!0;void 0!==e&&(((r=r||this.constructor.getPropertyOptions(e)).hasChanged||g)(this[e],t)?(this._$AL.has(e)||this._$AL.set(e,t),!0===r.reflect&&this._$El!==e&&(void 0===this._$EC&&(this._$EC=new Map),this._$EC.set(e,r))):n=!1),!this.isUpdatePending&&n&&(this._$E_=this._$Ej())}async _$Ej(){this.isUpdatePending=!0;try{await this._$E_}catch(e){Promise.reject(e)}const e=this.scheduleUpdate();return null!=e&&await e,!this.isUpdatePending}scheduleUpdate(){return this.performUpdate()}performUpdate(){var e;if(!this.isUpdatePending)return;this.hasUpdated,this._$Ei&&(this._$Ei.forEach(((e,t)=>this[t]=e)),this._$Ei=void 0);let t=!1;const r=this._$AL;try{t=this.shouldUpdate(r),t?(this.willUpdate(r),null===(e=this._$ES)||void 0===e||e.forEach((e=>{var t;return null===(t=e.hostUpdate)||void 0===t?void 0:t.call(e)})),this.update(r)):this._$Ek()}catch(e){throw t=!1,this._$Ek(),e}t&&this._$AE(r)}willUpdate(e){}_$AE(e){var t;null===(t=this._$ES)||void 0===t||t.forEach((e=>{var t;return null===(t=e.hostUpdated)||void 0===t?void 0:t.call(e)})),this.hasUpdated||(this.hasUpdated=!0,this.firstUpdated(e)),this.updated(e)}_$Ek(){this._$AL=new Map,this.isUpdatePending=!1}get updateComplete(){return this.getUpdateComplete()}getUpdateComplete(){return this._$E_}shouldUpdate(e){return!0}update(e){void 0!==this._$EC&&(this._$EC.forEach(((e,t)=>this._$EO(t,this[t],e))),this._$EC=void 0),this._$Ek()}updated(e){}firstUpdated(e){}}var x;b.finalized=!0,b.elementProperties=new Map,b.elementStyles=[],b.shadowRootOptions={mode:"open"},null==m||m({ReactiveElement:b}),(null!==(d=u.reactiveElementVersions)&&void 0!==d?d:u.reactiveElementVersions=[]).push("1.6.1");const w=window,$=w.trustedTypes,k=$?$.createPolicy("lit-html",{createHTML:e=>e}):void 0,S=`lit$${(Math.random()+"").slice(9)}$`,A="?"+S,E=`<${A}>`,O=document,T=(e="")=>O.createComment(e),C=e=>null===e||"object"!=typeof e&&"function"!=typeof e,j=Array.isArray,I=e=>j(e)||"function"==typeof(null==e?void 0:e[Symbol.iterator]),_=/<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g,P=/-->/g,R=/>/g,L=RegExp(">|[ \t\n\f\r](?:([^\\s\"'>=/]+)([ \t\n\f\r]*=[ \t\n\f\r]*(?:[^ \t\n\f\r\"'`<>=]|(\"|')|))|$)","g"),F=/'/g,D=/"/g,B=/^(?:script|style|textarea|title)$/i,N=e=>(t,...r)=>({_$litType$:e,strings:t,values:r}),q=N(1),U=(N(2),Symbol.for("lit-noChange")),z=Symbol.for("lit-nothing"),M=new WeakMap,H=O.createTreeWalker(O,129,null,!1),W=(e,t)=>{const r=e.length-1,n=[];let o,a=2===t?"":"",i=_;for(let t=0;t"===l[0]?(i=null!=o?o:_,c=-1):void 0===l[1]?c=-2:(c=i.lastIndex-l[2].length,s=l[1],i=void 0===l[3]?L:'"'===l[3]?D:F):i===D||i===F?i=L:i===P||i===R?i=_:(i=L,o=void 0);const d=i===L&&e[t+1].startsWith("/>")?" ":"";a+=i===_?r+E:c>=0?(n.push(s),r.slice(0,c)+"$lit$"+r.slice(c)+S+d):r+S+(-2===c?(n.push(void 0),t):d)}const s=a+(e[r]||"")+(2===t?"":"");if(!Array.isArray(e)||!e.hasOwnProperty("raw"))throw Error("invalid template strings array");return[void 0!==k?k.createHTML(s):s,n]};class V{constructor({strings:e,_$litType$:t},r){let n;this.parts=[];let o=0,a=0;const i=e.length-1,s=this.parts,[l,c]=W(e,t);if(this.el=V.createElement(l,r),H.currentNode=this.el.content,2===t){const e=this.el.content,t=e.firstChild;t.remove(),e.append(...t.childNodes)}for(;null!==(n=H.nextNode())&&s.length0){n.textContent=$?$.emptyScript:"";for(let r=0;r2||""!==r[0]||""!==r[1]?(this._$AH=Array(r.length-1).fill(new String),this.strings=r):this._$AH=z}get tagName(){return this.element.tagName}get _$AU(){return this._$AM._$AU}_$AI(e,t=this,r,n){const o=this.strings;let a=!1;if(void 0===o)e=G(this,e,t,0),a=!C(e)||e!==this._$AH&&e!==U,a&&(this._$AH=e);else{const n=e;let i,s;for(e=o[0],i=0;i{var n,o;const a=null!==(n=null==r?void 0:r.renderBefore)&&void 0!==n?n:t;let i=a._$litPart$;if(void 0===i){const e=null!==(o=null==r?void 0:r.renderBefore)&&void 0!==o?o:null;a._$litPart$=i=new J(t.insertBefore(T(),e),e,void 0,null!=r?r:{})}return i._$AI(e),i})(t,this.renderRoot,this.renderOptions)}connectedCallback(){var e;super.connectedCallback(),null===(e=this._$Dt)||void 0===e||e.setConnected(!0)}disconnectedCallback(){var e;super.disconnectedCallback(),null===(e=this._$Dt)||void 0===e||e.setConnected(!1)}render(){return U}}ie.finalized=!0,ie._$litElement$=!0,null===(oe=globalThis.litElementHydrateSupport)||void 0===oe||oe.call(globalThis,{LitElement:ie});const se=globalThis.litElementPolyfillSupport;null==se||se({LitElement:ie});function le(){return{async:!1,baseUrl:null,breaks:!1,extensions:null,gfm:!0,headerIds:!0,headerPrefix:"",highlight:null,langPrefix:"language-",mangle:!0,pedantic:!1,renderer:null,sanitize:!1,sanitizer:null,silent:!1,smartypants:!1,tokenizer:null,walkTokens:null,xhtml:!1}}(null!==(ae=globalThis.litElementVersions)&&void 0!==ae?ae:globalThis.litElementVersions=[]).push("3.2.0");let ce={async:!1,baseUrl:null,breaks:!1,extensions:null,gfm:!0,headerIds:!0,headerPrefix:"",highlight:null,langPrefix:"language-",mangle:!0,pedantic:!1,renderer:null,sanitize:!1,sanitizer:null,silent:!1,smartypants:!1,tokenizer:null,walkTokens:null,xhtml:!1};const pe=/[&<>"']/,de=new RegExp(pe.source,"g"),ue=/[<>"']|&(?!(#\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\w+);)/,he=new RegExp(ue.source,"g"),fe={"&":"&","<":"<",">":">",'"':""","'":"'"},me=e=>fe[e];function ye(e,t){if(t){if(pe.test(e))return e.replace(de,me)}else if(ue.test(e))return e.replace(he,me);return e}const ge=/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/gi;function ve(e){return e.replace(ge,((e,t)=>"colon"===(t=t.toLowerCase())?":":"#"===t.charAt(0)?"x"===t.charAt(1)?String.fromCharCode(parseInt(t.substring(2),16)):String.fromCharCode(+t.substring(1)):""))}const be=/(^|[^\[])\^/g;function xe(e,t){e="string"==typeof e?e:e.source,t=t||"";const r={replace:(t,n)=>(n=(n=n.source||n).replace(be,"$1"),e=e.replace(t,n),r),getRegex:()=>new RegExp(e,t)};return r}const we=/[^\w:]/g,$e=/^$|^[a-z][a-z0-9+.-]*:|^[?#]/i;function ke(e,t,r){if(e){let e;try{e=decodeURIComponent(ve(r)).replace(we,"").toLowerCase()}catch(e){return null}if(0===e.indexOf("javascript:")||0===e.indexOf("vbscript:")||0===e.indexOf("data:"))return null}t&&!$e.test(r)&&(r=function(e,t){Se[" "+e]||(Ae.test(e)?Se[" "+e]=e+"/":Se[" "+e]=Ie(e,"/",!0));const r=-1===(e=Se[" "+e]).indexOf(":");return"//"===t.substring(0,2)?r?t:e.replace(Ee,"$1")+t:"/"===t.charAt(0)?r?t:e.replace(Oe,"$1")+t:e+t}(t,r));try{r=encodeURI(r).replace(/%25/g,"%")}catch(e){return null}return r}const Se={},Ae=/^[^:]+:\/*[^/]*$/,Ee=/^([^:]+:)[\s\S]*$/,Oe=/^([^:]+:\/*[^/]*)[\s\S]*$/;const Te={exec:function(){}};function Ce(e){let t,r,n=1;for(;n{let n=!1,o=t;for(;--o>=0&&"\\"===r[o];)n=!n;return n?"|":" |"})).split(/ \|/);let n=0;if(r[0].trim()||r.shift(),r.length>0&&!r[r.length-1].trim()&&r.pop(),r.length>t)r.splice(t);else for(;r.length1;)1&t&&(r+=e),t>>=1,e+=e;return r+e}function Re(e,t,r,n){const o=t.href,a=t.title?ye(t.title):null,i=e[1].replace(/\\([\[\]])/g,"$1");if("!"!==e[0].charAt(0)){n.state.inLink=!0;const e={type:"link",raw:r,href:o,title:a,text:i,tokens:n.inlineTokens(i)};return n.state.inLink=!1,e}return{type:"image",raw:r,href:o,title:a,text:ye(i)}}class Le{constructor(e){this.options=e||ce}space(e){const t=this.rules.block.newline.exec(e);if(t&&t[0].length>0)return{type:"space",raw:t[0]}}code(e){const t=this.rules.block.code.exec(e);if(t){const e=t[0].replace(/^ {1,4}/gm,"");return{type:"code",raw:t[0],codeBlockStyle:"indented",text:this.options.pedantic?e:Ie(e,"\n")}}}fences(e){const t=this.rules.block.fences.exec(e);if(t){const e=t[0],r=function(e,t){const r=e.match(/^(\s+)(?:```)/);if(null===r)return t;const n=r[1];return t.split("\n").map((e=>{const t=e.match(/^\s+/);if(null===t)return e;const[r]=t;return r.length>=n.length?e.slice(n.length):e})).join("\n")}(e,t[3]||"");return{type:"code",raw:e,lang:t[2]?t[2].trim().replace(this.rules.inline._escapes,"$1"):t[2],text:r}}}heading(e){const t=this.rules.block.heading.exec(e);if(t){let e=t[2].trim();if(/#$/.test(e)){const t=Ie(e,"#");this.options.pedantic?e=t.trim():t&&!/ $/.test(t)||(e=t.trim())}return{type:"heading",raw:t[0],depth:t[1].length,text:e,tokens:this.lexer.inline(e)}}}hr(e){const t=this.rules.block.hr.exec(e);if(t)return{type:"hr",raw:t[0]}}blockquote(e){const t=this.rules.block.blockquote.exec(e);if(t){const e=t[0].replace(/^ *>[ \t]?/gm,""),r=this.lexer.state.top;this.lexer.state.top=!0;const n=this.lexer.blockTokens(e);return this.lexer.state.top=r,{type:"blockquote",raw:t[0],tokens:n,text:e}}}list(e){let t=this.rules.block.list.exec(e);if(t){let r,n,o,a,i,s,l,c,p,d,u,h,f=t[1].trim();const m=f.length>1,y={type:"list",raw:"",ordered:m,start:m?+f.slice(0,-1):"",loose:!1,items:[]};f=m?`\\d{1,9}\\${f.slice(-1)}`:`\\${f}`,this.options.pedantic&&(f=m?f:"[*+-]");const g=new RegExp(`^( {0,3}${f})((?:[\t ][^\\n]*)?(?:\\n|$))`);for(;e&&(h=!1,t=g.exec(e))&&!this.rules.block.hr.test(e);){if(r=t[0],e=e.substring(r.length),c=t[2].split("\n",1)[0].replace(/^\t+/,(e=>" ".repeat(3*e.length))),p=e.split("\n",1)[0],this.options.pedantic?(a=2,u=c.trimLeft()):(a=t[2].search(/[^ ]/),a=a>4?1:a,u=c.slice(a),a+=t[1].length),s=!1,!c&&/^ *$/.test(p)&&(r+=p+"\n",e=e.substring(p.length+1),h=!0),!h){const t=new RegExp(`^ {0,${Math.min(3,a-1)}}(?:[*+-]|\\d{1,9}[.)])((?:[ \t][^\\n]*)?(?:\\n|$))`),n=new RegExp(`^ {0,${Math.min(3,a-1)}}((?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$)`),o=new RegExp(`^ {0,${Math.min(3,a-1)}}(?:\`\`\`|~~~)`),i=new RegExp(`^ {0,${Math.min(3,a-1)}}#`);for(;e&&(d=e.split("\n",1)[0],p=d,this.options.pedantic&&(p=p.replace(/^ {1,4}(?=( {4})*[^ ])/g," ")),!o.test(p))&&!i.test(p)&&!t.test(p)&&!n.test(e);){if(p.search(/[^ ]/)>=a||!p.trim())u+="\n"+p.slice(a);else{if(s)break;if(c.search(/[^ ]/)>=4)break;if(o.test(c))break;if(i.test(c))break;if(n.test(c))break;u+="\n"+p}s||p.trim()||(s=!0),r+=d+"\n",e=e.substring(d.length+1),c=p.slice(a)}}y.loose||(l?y.loose=!0:/\n *\n *$/.test(r)&&(l=!0)),this.options.gfm&&(n=/^\[[ xX]\] /.exec(u),n&&(o="[ ] "!==n[0],u=u.replace(/^\[[ xX]\] +/,""))),y.items.push({type:"list_item",raw:r,task:!!n,checked:o,loose:!1,text:u}),y.raw+=r}y.items[y.items.length-1].raw=r.trimRight(),y.items[y.items.length-1].text=u.trimRight(),y.raw=y.raw.trimRight();const v=y.items.length;for(i=0;i"space"===e.type)),t=e.length>0&&e.some((e=>/\n.*\n/.test(e.raw)));y.loose=t}if(y.loose)for(i=0;i$/,"$1").replace(this.rules.inline._escapes,"$1"):"",n=t[3]?t[3].substring(1,t[3].length-1).replace(this.rules.inline._escapes,"$1"):t[3];return{type:"def",tag:e,raw:t[0],href:r,title:n}}}table(e){const t=this.rules.block.table.exec(e);if(t){const e={type:"table",header:je(t[1]).map((e=>({text:e}))),align:t[2].replace(/^ *|\| *$/g,"").split(/ *\| */),rows:t[3]&&t[3].trim()?t[3].replace(/\n[ \t]*$/,"").split("\n"):[]};if(e.header.length===e.align.length){e.raw=t[0];let r,n,o,a,i=e.align.length;for(r=0;r({text:e})));for(i=e.header.length,n=0;n/i.test(t[0])&&(this.lexer.state.inLink=!1),!this.lexer.state.inRawBlock&&/^<(pre|code|kbd|script)(\s|>)/i.test(t[0])?this.lexer.state.inRawBlock=!0:this.lexer.state.inRawBlock&&/^<\/(pre|code|kbd|script)(\s|>)/i.test(t[0])&&(this.lexer.state.inRawBlock=!1),{type:this.options.sanitize?"text":"html",raw:t[0],inLink:this.lexer.state.inLink,inRawBlock:this.lexer.state.inRawBlock,text:this.options.sanitize?this.options.sanitizer?this.options.sanitizer(t[0]):ye(t[0]):t[0]}}link(e){const t=this.rules.inline.link.exec(e);if(t){const e=t[2].trim();if(!this.options.pedantic&&/^$/.test(e))return;const t=Ie(e.slice(0,-1),"\\");if((e.length-t.length)%2==0)return}else{const e=function(e,t){if(-1===e.indexOf(t[1]))return-1;const r=e.length;let n=0,o=0;for(;o-1){const r=(0===t[0].indexOf("!")?5:4)+t[1].length+e;t[2]=t[2].substring(0,e),t[0]=t[0].substring(0,r).trim(),t[3]=""}}let r=t[2],n="";if(this.options.pedantic){const e=/^([^'"]*[^\s])\s+(['"])(.*)\2/.exec(r);e&&(r=e[1],n=e[3])}else n=t[3]?t[3].slice(1,-1):"";return r=r.trim(),/^$/.test(e)?r.slice(1):r.slice(1,-1)),Re(t,{href:r?r.replace(this.rules.inline._escapes,"$1"):r,title:n?n.replace(this.rules.inline._escapes,"$1"):n},t[0],this.lexer)}}reflink(e,t){let r;if((r=this.rules.inline.reflink.exec(e))||(r=this.rules.inline.nolink.exec(e))){let e=(r[2]||r[1]).replace(/\s+/g," ");if(e=t[e.toLowerCase()],!e){const e=r[0].charAt(0);return{type:"text",raw:e,text:e}}return Re(r,e,r[0],this.lexer)}}emStrong(e,t,r=""){let n=this.rules.inline.emStrong.lDelim.exec(e);if(!n)return;if(n[3]&&r.match(/[\p{L}\p{N}]/u))return;const o=n[1]||n[2]||"";if(!o||o&&(""===r||this.rules.inline.punctuation.exec(r))){const r=n[0].length-1;let o,a,i=r,s=0;const l="*"===n[0][0]?this.rules.inline.emStrong.rDelimAst:this.rules.inline.emStrong.rDelimUnd;for(l.lastIndex=0,t=t.slice(-1*e.length+r);null!=(n=l.exec(t));){if(o=n[1]||n[2]||n[3]||n[4]||n[5]||n[6],!o)continue;if(a=o.length,n[3]||n[4]){i+=a;continue}if((n[5]||n[6])&&r%3&&!((r+a)%3)){s+=a;continue}if(i-=a,i>0)continue;a=Math.min(a,a+i+s);const t=e.slice(0,r+n.index+(n[0].length-o.length)+a);if(Math.min(r,a)%2){const e=t.slice(1,-1);return{type:"em",raw:t,text:e,tokens:this.lexer.inlineTokens(e)}}const l=t.slice(2,-2);return{type:"strong",raw:t,text:l,tokens:this.lexer.inlineTokens(l)}}}}codespan(e){const t=this.rules.inline.code.exec(e);if(t){let e=t[2].replace(/\n/g," ");const r=/[^ ]/.test(e),n=/^ /.test(e)&&/ $/.test(e);return r&&n&&(e=e.substring(1,e.length-1)),e=ye(e,!0),{type:"codespan",raw:t[0],text:e}}}br(e){const t=this.rules.inline.br.exec(e);if(t)return{type:"br",raw:t[0]}}del(e){const t=this.rules.inline.del.exec(e);if(t)return{type:"del",raw:t[0],text:t[2],tokens:this.lexer.inlineTokens(t[2])}}autolink(e,t){const r=this.rules.inline.autolink.exec(e);if(r){let e,n;return"@"===r[2]?(e=ye(this.options.mangle?t(r[1]):r[1]),n="mailto:"+e):(e=ye(r[1]),n=e),{type:"link",raw:r[0],text:e,href:n,tokens:[{type:"text",raw:e,text:e}]}}}url(e,t){let r;if(r=this.rules.inline.url.exec(e)){let e,n;if("@"===r[2])e=ye(this.options.mangle?t(r[0]):r[0]),n="mailto:"+e;else{let t;do{t=r[0],r[0]=this.rules.inline._backpedal.exec(r[0])[0]}while(t!==r[0]);e=ye(r[0]),n="www."===r[1]?"http://"+r[0]:r[0]}return{type:"link",raw:r[0],text:e,href:n,tokens:[{type:"text",raw:e,text:e}]}}}inlineText(e,t){const r=this.rules.inline.text.exec(e);if(r){let e;return e=this.lexer.state.inRawBlock?this.options.sanitize?this.options.sanitizer?this.options.sanitizer(r[0]):ye(r[0]):r[0]:ye(this.options.smartypants?t(r[0]):r[0]),{type:"text",raw:r[0],text:e}}}}const Fe={newline:/^(?: *(?:\n|$))+/,code:/^( {4}[^\n]+(?:\n(?: *(?:\n|$))*)?)+/,fences:/^ {0,3}(`{3,}(?=[^`\n]*\n)|~{3,})([^\n]*)\n(?:|([\s\S]*?)\n)(?: {0,3}\1[~`]* *(?=\n|$)|$)/,hr:/^ {0,3}((?:-[\t ]*){3,}|(?:_[ \t]*){3,}|(?:\*[ \t]*){3,})(?:\n+|$)/,heading:/^ {0,3}(#{1,6})(?=\s|$)(.*)(?:\n+|$)/,blockquote:/^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/,list:/^( {0,3}bull)([ \t][^\n]+?)?(?:\n|$)/,html:"^ {0,3}(?:<(script|pre|style|textarea)[\\s>][\\s\\S]*?(?:[^\\n]*\\n+|$)|comment[^\\n]*(\\n+|$)|<\\?[\\s\\S]*?(?:\\?>\\n*|$)|\\n*|$)|\\n*|$)|)[\\s\\S]*?(?:(?:\\n *)+\\n|$)|<(?!script|pre|style|textarea)([a-z][\\w-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n *)+\\n|$)|(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n *)+\\n|$))",def:/^ {0,3}\[(label)\]: *(?:\n *)?([^<\s][^\s]*|<.*?>)(?:(?: +(?:\n *)?| *\n *)(title))? *(?:\n+|$)/,table:Te,lheading:/^((?:.|\n(?!\n))+?)\n {0,3}(=+|-+) *(?:\n+|$)/,_paragraph:/^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html|table| +\n)[^\n]+)*)/,text:/^[^\n]+/,_label:/(?!\s*\])(?:\\.|[^\[\]\\])+/,_title:/(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/};Fe.def=xe(Fe.def).replace("label",Fe._label).replace("title",Fe._title).getRegex(),Fe.bullet=/(?:[*+-]|\d{1,9}[.)])/,Fe.listItemStart=xe(/^( *)(bull) */).replace("bull",Fe.bullet).getRegex(),Fe.list=xe(Fe.list).replace(/bull/g,Fe.bullet).replace("hr","\\n+(?=\\1?(?:(?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$))").replace("def","\\n+(?="+Fe.def.source+")").getRegex(),Fe._tag="address|article|aside|base|basefont|blockquote|body|caption|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option|p|param|section|source|summary|table|tbody|td|tfoot|th|thead|title|tr|track|ul",Fe._comment=/|$)/,Fe.html=xe(Fe.html,"i").replace("comment",Fe._comment).replace("tag",Fe._tag).replace("attribute",/ +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/).getRegex(),Fe.paragraph=xe(Fe._paragraph).replace("hr",Fe.hr).replace("heading"," {0,3}#{1,6} ").replace("|lheading","").replace("|table","").replace("blockquote"," {0,3}>").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html",")|<(?:script|pre|style|textarea|!--)").replace("tag",Fe._tag).getRegex(),Fe.blockquote=xe(Fe.blockquote).replace("paragraph",Fe.paragraph).getRegex(),Fe.normal=Ce({},Fe),Fe.gfm=Ce({},Fe.normal,{table:"^ *([^\\n ].*\\|.*)\\n {0,3}(?:\\| *)?(:?-+:? *(?:\\| *:?-+:? *)*)(?:\\| *)?(?:\\n((?:(?! *\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)"}),Fe.gfm.table=xe(Fe.gfm.table).replace("hr",Fe.hr).replace("heading"," {0,3}#{1,6} ").replace("blockquote"," {0,3}>").replace("code"," {4}[^\\n]").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html",")|<(?:script|pre|style|textarea|!--)").replace("tag",Fe._tag).getRegex(),Fe.gfm.paragraph=xe(Fe._paragraph).replace("hr",Fe.hr).replace("heading"," {0,3}#{1,6} ").replace("|lheading","").replace("table",Fe.gfm.table).replace("blockquote"," {0,3}>").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html",")|<(?:script|pre|style|textarea|!--)").replace("tag",Fe._tag).getRegex(),Fe.pedantic=Ce({},Fe.normal,{html:xe("^ *(?:comment *(?:\\n|\\s*$)|<(tag)[\\s\\S]+? *(?:\\n{2,}|\\s*$)|\\s]*)*?/?> *(?:\\n{2,}|\\s*$))").replace("comment",Fe._comment).replace(/tag/g,"(?!(?:a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)\\b)\\w+(?!:|[^\\w\\s@]*@)\\b").getRegex(),def:/^ *\[([^\]]+)\]: *]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/,heading:/^(#{1,6})(.*)(?:\n+|$)/,fences:Te,lheading:/^(.+?)\n {0,3}(=+|-+) *(?:\n+|$)/,paragraph:xe(Fe.normal._paragraph).replace("hr",Fe.hr).replace("heading"," *#{1,6} *[^\n]").replace("lheading",Fe.lheading).replace("blockquote"," {0,3}>").replace("|fences","").replace("|list","").replace("|html","").getRegex()});const De={escape:/^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/,autolink:/^<(scheme:[^\s\x00-\x1f<>]*|email)>/,url:Te,tag:"^comment|^|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>|^<\\?[\\s\\S]*?\\?>|^|^",link:/^!?\[(label)\]\(\s*(href)(?:\s+(title))?\s*\)/,reflink:/^!?\[(label)\]\[(ref)\]/,nolink:/^!?\[(ref)\](?:\[\])?/,reflinkSearch:"reflink|nolink(?!\\()",emStrong:{lDelim:/^(?:\*+(?:([punct_])|[^\s*]))|^_+(?:([punct*])|([^\s_]))/,rDelimAst:/^(?:[^_*\\]|\\.)*?\_\_(?:[^_*\\]|\\.)*?\*(?:[^_*\\]|\\.)*?(?=\_\_)|(?:[^*\\]|\\.)+(?=[^*])|[punct_](\*+)(?=[\s]|$)|(?:[^punct*_\s\\]|\\.)(\*+)(?=[punct_\s]|$)|[punct_\s](\*+)(?=[^punct*_\s])|[\s](\*+)(?=[punct_])|[punct_](\*+)(?=[punct_])|(?:[^punct*_\s\\]|\\.)(\*+)(?=[^punct*_\s])/,rDelimUnd:/^(?:[^_*\\]|\\.)*?\*\*(?:[^_*\\]|\\.)*?\_(?:[^_*\\]|\\.)*?(?=\*\*)|(?:[^_\\]|\\.)+(?=[^_])|[punct*](\_+)(?=[\s]|$)|(?:[^punct*_\s\\]|\\.)(\_+)(?=[punct*\s]|$)|[punct*\s](\_+)(?=[^punct*_\s])|[\s](\_+)(?=[punct*])|[punct*](\_+)(?=[punct*])/},code:/^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/,br:/^( {2,}|\\)\n(?!\s*$)/,del:Te,text:/^(`+|[^`])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\.5&&(r="x"+r.toString(16)),n+="&#"+r+";";return n}De._punctuation="!\"#$%&'()+\\-.,/:;<=>?@\\[\\]`^{|}~",De.punctuation=xe(De.punctuation).replace(/punctuation/g,De._punctuation).getRegex(),De.blockSkip=/\[[^\]]*?\]\([^\)]*?\)|`[^`]*?`|<[^>]*?>/g,De.escapedEmSt=/(?:^|[^\\])(?:\\\\)*\\[*_]/g,De._comment=xe(Fe._comment).replace("(?:--\x3e|$)","--\x3e").getRegex(),De.emStrong.lDelim=xe(De.emStrong.lDelim).replace(/punct/g,De._punctuation).getRegex(),De.emStrong.rDelimAst=xe(De.emStrong.rDelimAst,"g").replace(/punct/g,De._punctuation).getRegex(),De.emStrong.rDelimUnd=xe(De.emStrong.rDelimUnd,"g").replace(/punct/g,De._punctuation).getRegex(),De._escapes=/\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/g,De._scheme=/[a-zA-Z][a-zA-Z0-9+.-]{1,31}/,De._email=/[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+(@)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(?![-_])/,De.autolink=xe(De.autolink).replace("scheme",De._scheme).replace("email",De._email).getRegex(),De._attribute=/\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/,De.tag=xe(De.tag).replace("comment",De._comment).replace("attribute",De._attribute).getRegex(),De._label=/(?:\[(?:\\.|[^\[\]\\])*\]|\\.|`[^`]*`|[^\[\]\\`])*?/,De._href=/<(?:\\.|[^\n<>\\])+>|[^\s\x00-\x1f]*/,De._title=/"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/,De.link=xe(De.link).replace("label",De._label).replace("href",De._href).replace("title",De._title).getRegex(),De.reflink=xe(De.reflink).replace("label",De._label).replace("ref",Fe._label).getRegex(),De.nolink=xe(De.nolink).replace("ref",Fe._label).getRegex(),De.reflinkSearch=xe(De.reflinkSearch,"g").replace("reflink",De.reflink).replace("nolink",De.nolink).getRegex(),De.normal=Ce({},De),De.pedantic=Ce({},De.normal,{strong:{start:/^__|\*\*/,middle:/^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,endAst:/\*\*(?!\*)/g,endUnd:/__(?!_)/g},em:{start:/^_|\*/,middle:/^()\*(?=\S)([\s\S]*?\S)\*(?!\*)|^_(?=\S)([\s\S]*?\S)_(?!_)/,endAst:/\*(?!\*)/g,endUnd:/_(?!_)/g},link:xe(/^!?\[(label)\]\((.*?)\)/).replace("label",De._label).getRegex(),reflink:xe(/^!?\[(label)\]\s*\[([^\]]*)\]/).replace("label",De._label).getRegex()}),De.gfm=Ce({},De.normal,{escape:xe(De.escape).replace("])","~|])").getRegex(),_extended_email:/[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/,url:/^((?:ftp|https?):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/,_backpedal:/(?:[^?!.,:;*_'"~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_'"~)]+(?!$))+/,del:/^(~~?)(?=[^\s~])([\s\S]*?[^\s~])\1(?=[^~]|$)/,text:/^([`~]+|[^`~])(?:(?= {2,}\n)|(?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)|[\s\S]*?(?:(?=[\\t+" ".repeat(r.length)));e;)if(!(this.options.extensions&&this.options.extensions.block&&this.options.extensions.block.some((n=>!!(r=n.call({lexer:this},e,t))&&(e=e.substring(r.raw.length),t.push(r),!0)))))if(r=this.tokenizer.space(e))e=e.substring(r.raw.length),1===r.raw.length&&t.length>0?t[t.length-1].raw+="\n":t.push(r);else if(r=this.tokenizer.code(e))e=e.substring(r.raw.length),n=t[t.length-1],!n||"paragraph"!==n.type&&"text"!==n.type?t.push(r):(n.raw+="\n"+r.raw,n.text+="\n"+r.text,this.inlineQueue[this.inlineQueue.length-1].src=n.text);else if(r=this.tokenizer.fences(e))e=e.substring(r.raw.length),t.push(r);else if(r=this.tokenizer.heading(e))e=e.substring(r.raw.length),t.push(r);else if(r=this.tokenizer.hr(e))e=e.substring(r.raw.length),t.push(r);else if(r=this.tokenizer.blockquote(e))e=e.substring(r.raw.length),t.push(r);else if(r=this.tokenizer.list(e))e=e.substring(r.raw.length),t.push(r);else if(r=this.tokenizer.html(e))e=e.substring(r.raw.length),t.push(r);else if(r=this.tokenizer.def(e))e=e.substring(r.raw.length),n=t[t.length-1],!n||"paragraph"!==n.type&&"text"!==n.type?this.tokens.links[r.tag]||(this.tokens.links[r.tag]={href:r.href,title:r.title}):(n.raw+="\n"+r.raw,n.text+="\n"+r.raw,this.inlineQueue[this.inlineQueue.length-1].src=n.text);else if(r=this.tokenizer.table(e))e=e.substring(r.raw.length),t.push(r);else if(r=this.tokenizer.lheading(e))e=e.substring(r.raw.length),t.push(r);else{if(o=e,this.options.extensions&&this.options.extensions.startBlock){let t=1/0;const r=e.slice(1);let n;this.options.extensions.startBlock.forEach((function(e){n=e.call({lexer:this},r),"number"==typeof n&&n>=0&&(t=Math.min(t,n))})),t<1/0&&t>=0&&(o=e.substring(0,t+1))}if(this.state.top&&(r=this.tokenizer.paragraph(o)))n=t[t.length-1],a&&"paragraph"===n.type?(n.raw+="\n"+r.raw,n.text+="\n"+r.text,this.inlineQueue.pop(),this.inlineQueue[this.inlineQueue.length-1].src=n.text):t.push(r),a=o.length!==e.length,e=e.substring(r.raw.length);else if(r=this.tokenizer.text(e))e=e.substring(r.raw.length),n=t[t.length-1],n&&"text"===n.type?(n.raw+="\n"+r.raw,n.text+="\n"+r.text,this.inlineQueue.pop(),this.inlineQueue[this.inlineQueue.length-1].src=n.text):t.push(r);else if(e){const t="Infinite loop on byte: "+e.charCodeAt(0);if(this.options.silent){console.error(t);break}throw new Error(t)}}return this.state.top=!0,t}inline(e,t=[]){return this.inlineQueue.push({src:e,tokens:t}),t}inlineTokens(e,t=[]){let r,n,o,a,i,s,l=e;if(this.tokens.links){const e=Object.keys(this.tokens.links);if(e.length>0)for(;null!=(a=this.tokenizer.rules.inline.reflinkSearch.exec(l));)e.includes(a[0].slice(a[0].lastIndexOf("[")+1,-1))&&(l=l.slice(0,a.index)+"["+Pe("a",a[0].length-2)+"]"+l.slice(this.tokenizer.rules.inline.reflinkSearch.lastIndex))}for(;null!=(a=this.tokenizer.rules.inline.blockSkip.exec(l));)l=l.slice(0,a.index)+"["+Pe("a",a[0].length-2)+"]"+l.slice(this.tokenizer.rules.inline.blockSkip.lastIndex);for(;null!=(a=this.tokenizer.rules.inline.escapedEmSt.exec(l));)l=l.slice(0,a.index+a[0].length-2)+"++"+l.slice(this.tokenizer.rules.inline.escapedEmSt.lastIndex),this.tokenizer.rules.inline.escapedEmSt.lastIndex--;for(;e;)if(i||(s=""),i=!1,!(this.options.extensions&&this.options.extensions.inline&&this.options.extensions.inline.some((n=>!!(r=n.call({lexer:this},e,t))&&(e=e.substring(r.raw.length),t.push(r),!0)))))if(r=this.tokenizer.escape(e))e=e.substring(r.raw.length),t.push(r);else if(r=this.tokenizer.tag(e))e=e.substring(r.raw.length),n=t[t.length-1],n&&"text"===r.type&&"text"===n.type?(n.raw+=r.raw,n.text+=r.text):t.push(r);else if(r=this.tokenizer.link(e))e=e.substring(r.raw.length),t.push(r);else if(r=this.tokenizer.reflink(e,this.tokens.links))e=e.substring(r.raw.length),n=t[t.length-1],n&&"text"===r.type&&"text"===n.type?(n.raw+=r.raw,n.text+=r.text):t.push(r);else if(r=this.tokenizer.emStrong(e,l,s))e=e.substring(r.raw.length),t.push(r);else if(r=this.tokenizer.codespan(e))e=e.substring(r.raw.length),t.push(r);else if(r=this.tokenizer.br(e))e=e.substring(r.raw.length),t.push(r);else if(r=this.tokenizer.del(e))e=e.substring(r.raw.length),t.push(r);else if(r=this.tokenizer.autolink(e,Ne))e=e.substring(r.raw.length),t.push(r);else if(this.state.inLink||!(r=this.tokenizer.url(e,Ne))){if(o=e,this.options.extensions&&this.options.extensions.startInline){let t=1/0;const r=e.slice(1);let n;this.options.extensions.startInline.forEach((function(e){n=e.call({lexer:this},r),"number"==typeof n&&n>=0&&(t=Math.min(t,n))})),t<1/0&&t>=0&&(o=e.substring(0,t+1))}if(r=this.tokenizer.inlineText(o,Be))e=e.substring(r.raw.length),"_"!==r.raw.slice(-1)&&(s=r.raw.slice(-1)),i=!0,n=t[t.length-1],n&&"text"===n.type?(n.raw+=r.raw,n.text+=r.text):t.push(r);else if(e){const t="Infinite loop on byte: "+e.charCodeAt(0);if(this.options.silent){console.error(t);break}throw new Error(t)}}else e=e.substring(r.raw.length),t.push(r);return t}}class Ue{constructor(e){this.options=e||ce}code(e,t,r){const n=(t||"").match(/\S*/)[0];if(this.options.highlight){const t=this.options.highlight(e,n);null!=t&&t!==e&&(r=!0,e=t)}return e=e.replace(/\n$/,"")+"\n",n?'
'+(r?e:ye(e,!0))+"
\n":"
"+(r?e:ye(e,!0))+"
\n"}blockquote(e){return`
\n${e}
\n`}html(e){return e}heading(e,t,r,n){if(this.options.headerIds){return`${e}\n`}return`${e}\n`}hr(){return this.options.xhtml?"
\n":"
\n"}list(e,t,r){const n=t?"ol":"ul";return"<"+n+(t&&1!==r?' start="'+r+'"':"")+">\n"+e+"\n"}listitem(e){return`
  • ${e}
  • \n`}checkbox(e){return" "}paragraph(e){return`

    ${e}

    \n`}table(e,t){return t&&(t=`${t}`),"\n\n"+e+"\n"+t+"
    \n"}tablerow(e){return`\n${e}\n`}tablecell(e,t){const r=t.header?"th":"td";return(t.align?`<${r} align="${t.align}">`:`<${r}>`)+e+`\n`}strong(e){return`${e}`}em(e){return`${e}`}codespan(e){return`${e}`}br(){return this.options.xhtml?"
    ":"
    "}del(e){return`${e}`}link(e,t,r){if(null===(e=ke(this.options.sanitize,this.options.baseUrl,e)))return r;let n='",n}image(e,t,r){if(null===(e=ke(this.options.sanitize,this.options.baseUrl,e)))return r;let n=`${r}":">",n}text(e){return e}}class ze{strong(e){return e}em(e){return e}codespan(e){return e}del(e){return e}html(e){return e}text(e){return e}link(e,t,r){return""+r}image(e,t,r){return""+r}br(){return""}}class Me{constructor(){this.seen={}}serialize(e){return e.toLowerCase().trim().replace(/<[!\/a-z].*?>/gi,"").replace(/[\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&()*+,./:;<=>?@[\]^`{|}~]/g,"").replace(/\s/g,"-")}getNextSafeSlug(e,t){let r=e,n=0;if(this.seen.hasOwnProperty(r)){n=this.seen[e];do{n++,r=e+"-"+n}while(this.seen.hasOwnProperty(r))}return t||(this.seen[e]=n,this.seen[r]=0),r}slug(e,t={}){const r=this.serialize(e);return this.getNextSafeSlug(r,t.dryrun)}}class He{constructor(e){this.options=e||ce,this.options.renderer=this.options.renderer||new Ue,this.renderer=this.options.renderer,this.renderer.options=this.options,this.textRenderer=new ze,this.slugger=new Me}static parse(e,t){return new He(t).parse(e)}static parseInline(e,t){return new He(t).parseInline(e)}parse(e,t=!0){let r,n,o,a,i,s,l,c,p,d,u,h,f,m,y,g,v,b,x,w="";const $=e.length;for(r=0;r<$;r++)if(d=e[r],this.options.extensions&&this.options.extensions.renderers&&this.options.extensions.renderers[d.type]&&(x=this.options.extensions.renderers[d.type].call({parser:this},d),!1!==x||!["space","hr","heading","code","table","blockquote","list","html","paragraph","text"].includes(d.type)))w+=x||"";else switch(d.type){case"space":continue;case"hr":w+=this.renderer.hr();continue;case"heading":w+=this.renderer.heading(this.parseInline(d.tokens),d.depth,ve(this.parseInline(d.tokens,this.textRenderer)),this.slugger);continue;case"code":w+=this.renderer.code(d.text,d.lang,d.escaped);continue;case"table":for(c="",l="",a=d.header.length,n=0;n0&&"paragraph"===y.tokens[0].type?(y.tokens[0].text=b+" "+y.tokens[0].text,y.tokens[0].tokens&&y.tokens[0].tokens.length>0&&"text"===y.tokens[0].tokens[0].type&&(y.tokens[0].tokens[0].text=b+" "+y.tokens[0].tokens[0].text)):y.tokens.unshift({type:"text",text:b}):m+=b),m+=this.parse(y.tokens,f),p+=this.renderer.listitem(m,v,g);w+=this.renderer.list(p,u,h);continue;case"html":w+=this.renderer.html(d.text);continue;case"paragraph":w+=this.renderer.paragraph(this.parseInline(d.tokens));continue;case"text":for(p=d.tokens?this.parseInline(d.tokens):d.text;r+1<$&&"text"===e[r+1].type;)d=e[++r],p+="\n"+(d.tokens?this.parseInline(d.tokens):d.text);w+=t?this.renderer.paragraph(p):p;continue;default:{const e='Token with "'+d.type+'" type was not found.';if(this.options.silent)return void console.error(e);throw new Error(e)}}return w}parseInline(e,t){t=t||this.renderer;let r,n,o,a="";const i=e.length;for(r=0;r{n(e.text,e.lang,(function(t,r){if(t)return a(t);null!=r&&r!==e.text&&(e.text=r,e.escaped=!0),i--,0===i&&a()}))}),0))})),void(0===i&&a())}function n(e){if(e.message+="\nPlease report this to https://github.com/markedjs/marked.",t.silent)return"

    An error occurred:

    "+ye(e.message+"",!0)+"
    ";throw e}try{const r=qe.lex(e,t);if(t.walkTokens){if(t.async)return Promise.all(We.walkTokens(r,t.walkTokens)).then((()=>He.parse(r,t))).catch(n);We.walkTokens(r,t.walkTokens)}return He.parse(r,t)}catch(e){n(e)}}We.options=We.setOptions=function(e){var t;return Ce(We.defaults,e),t=We.defaults,ce=t,We},We.getDefaults=le,We.defaults=ce,We.use=function(...e){const t=We.defaults.extensions||{renderers:{},childTokens:{}};e.forEach((e=>{const r=Ce({},e);if(r.async=We.defaults.async||r.async,e.extensions&&(e.extensions.forEach((e=>{if(!e.name)throw new Error("extension name required");if(e.renderer){const r=t.renderers[e.name];t.renderers[e.name]=r?function(...t){let n=e.renderer.apply(this,t);return!1===n&&(n=r.apply(this,t)),n}:e.renderer}if(e.tokenizer){if(!e.level||"block"!==e.level&&"inline"!==e.level)throw new Error("extension level must be 'block' or 'inline'");t[e.level]?t[e.level].unshift(e.tokenizer):t[e.level]=[e.tokenizer],e.start&&("block"===e.level?t.startBlock?t.startBlock.push(e.start):t.startBlock=[e.start]:"inline"===e.level&&(t.startInline?t.startInline.push(e.start):t.startInline=[e.start]))}e.childTokens&&(t.childTokens[e.name]=e.childTokens)})),r.extensions=t),e.renderer){const t=We.defaults.renderer||new Ue;for(const r in e.renderer){const n=t[r];t[r]=(...o)=>{let a=e.renderer[r].apply(t,o);return!1===a&&(a=n.apply(t,o)),a}}r.renderer=t}if(e.tokenizer){const t=We.defaults.tokenizer||new Le;for(const r in e.tokenizer){const n=t[r];t[r]=(...o)=>{let a=e.tokenizer[r].apply(t,o);return!1===a&&(a=n.apply(t,o)),a}}r.tokenizer=t}if(e.walkTokens){const t=We.defaults.walkTokens;r.walkTokens=function(r){let n=[];return n.push(e.walkTokens.call(this,r)),t&&(n=n.concat(t.call(this,r))),n}}We.setOptions(r)}))},We.walkTokens=function(e,t){let r=[];for(const n of e)switch(r=r.concat(t.call(We,n)),n.type){case"table":for(const e of n.header)r=r.concat(We.walkTokens(e.tokens,t));for(const e of n.rows)for(const n of e)r=r.concat(We.walkTokens(n.tokens,t));break;case"list":r=r.concat(We.walkTokens(n.items,t));break;default:We.defaults.extensions&&We.defaults.extensions.childTokens&&We.defaults.extensions.childTokens[n.type]?We.defaults.extensions.childTokens[n.type].forEach((function(e){r=r.concat(We.walkTokens(n[e],t))})):n.tokens&&(r=r.concat(We.walkTokens(n.tokens,t)))}return r},We.parseInline=function(e,t){if(null==e)throw new Error("marked.parseInline(): input parameter is undefined or null");if("string"!=typeof e)throw new Error("marked.parseInline(): input parameter is of type "+Object.prototype.toString.call(e)+", string expected");_e(t=Ce({},We.defaults,t||{}));try{const r=qe.lexInline(e,t);return t.walkTokens&&We.walkTokens(r,t.walkTokens),He.parseInline(r,t)}catch(e){if(e.message+="\nPlease report this to https://github.com/markedjs/marked.",t.silent)return"

    An error occurred:

    "+ye(e.message+"",!0)+"
    ";throw e}},We.Parser=He,We.parser=He.parse,We.Renderer=Ue,We.TextRenderer=ze,We.Lexer=qe,We.lexer=qe.lex,We.Tokenizer=Le,We.Slugger=Me,We.parse=We;We.options,We.setOptions,We.use,We.walkTokens,We.parseInline,He.parse,qe.lex;var Ve=r(660),Ge=r.n(Ve);r(251),r(358),r(46),r(503),r(277),r(874),r(366),r(57),r(16);const Ke=c` + .hover-bg:hover{ + background: var(--bg3); + } + ::selection { + background: var(--selection-bg); + color: var(--selection-fg); + } + .regular-font{ + font-family:var(--font-regular); + } + .mono-font { + font-family:var(--font-mono); + } + .title { + font-size: calc(var(--font-size-small) + 18px); + font-weight: normal + } + .sub-title{ font-size: 20px;} + .req-res-title { + font-family: var(--font-regular); + font-size: calc(var(--font-size-small) + 4px); + font-weight:bold; + margin-bottom:8px; + text-align:left; + } + .tiny-title { + font-size:calc(var(--font-size-small) + 1px); + font-weight:bold; + } + .regular-font-size { font-size: var(--font-size-regular); } + .small-font-size { font-size: var(--font-size-small); } + .upper { text-transform: uppercase; } + .primary-text{ color: var(--primary-color); } + .bold-text { font-weight:bold; } + .gray-text { color: var(--light-fg); } + .red-text {color: var(--red)} + .blue-text {color: var(--blue)} + .multiline { + overflow: scroll; + max-height: var(--resp-area-height, 400px); + color: var(--fg3); + } + .method-fg.put { color: var(--orange); } + .method-fg.post { color: var(--green); } + .method-fg.get { color: var(--blue); } + .method-fg.delete { color: var(--red); } + .method-fg.options, + .method-fg.head, + .method-fg.patch { + color: var(--yellow); + } + + h1{ font-family:var(--font-regular); font-size:28px; padding-top: 10px; letter-spacing:normal; font-weight:normal; } + h2{ font-family:var(--font-regular); font-size:24px; padding-top: 10px; letter-spacing:normal; font-weight:normal; } + h3{ font-family:var(--font-regular); font-size:18px; padding-top: 10px; letter-spacing:normal; font-weight:normal; } + h4{ font-family:var(--font-regular); font-size:16px; padding-top: 10px; letter-spacing:normal; font-weight:normal; } + h5{ font-family:var(--font-regular); font-size:14px; padding-top: 10px; letter-spacing:normal; font-weight:normal; } + h6{ font-family:var(--font-regular); font-size:14px; padding-top: 10px; letter-spacing:normal; font-weight:normal; } + + h1,h2,h3,h4,h5,h5{ + margin-block-end: 0.2em; + } + p { margin-block-start: 0.5em; } + a { color: var(--blue); cursor:pointer; } + a.inactive-link { + color:var(--fg); + text-decoration: none; + cursor:text; + } + + code, + pre { + margin: 0px; + font-family: var(--font-mono); + font-size: calc(var(--font-size-mono) - 1px); + } + + .m-markdown, + .m-markdown-small { + display:block; + } + + .m-markdown p, + .m-markdown span { + font-size: var(--font-size-regular); + line-height:calc(var(--font-size-regular) + 8px); + } + .m-markdown li { + font-size: var(--font-size-regular); + line-height:calc(var(--font-size-regular) + 10px); + } + + .m-markdown-small p, + .m-markdown-small span, + .m-markdown-small li { + font-size: var(--font-size-small); + line-height: calc(var(--font-size-small) + 6px); + } + .m-markdown-small li { + line-height: calc(var(--font-size-small) + 8px); + } + + .m-markdown p:not(:first-child) { + margin-block-start: 24px; + } + + .m-markdown-small p:not(:first-child) { + margin-block-start: 12px; + } + .m-markdown-small p:first-child { + margin-block-start: 0; + } + + .m-markdown p, + .m-markdown-small p { + margin-block-end: 0 + } + + .m-markdown code span { + font-size:var(--font-size-mono); + } + + .m-markdown-small code, + .m-markdown code { + padding: 1px 6px; + border-radius: 2px; + color: var(--inline-code-fg); + background-color: var(--bg3); + font-size: calc(var(--font-size-mono)); + line-height: 1.2; + } + + .m-markdown-small code { + font-size: calc(var(--font-size-mono) - 1px); + } + + .m-markdown-small pre, + .m-markdown pre { + white-space: pre-wrap; + overflow-x: auto; + line-height: normal; + border-radius: 2px; + border: 1px solid var(--code-border-color); + } + + .m-markdown pre { + padding: 12px; + background-color: var(--code-bg); + color:var(--code-fg); + } + + .m-markdown-small pre { + margin-top: 4px; + padding: 2px 4px; + background-color: var(--bg3); + color: var(--fg2); + } + + .m-markdown-small pre code, + .m-markdown pre code { + border:none; + padding:0; + } + + .m-markdown pre code { + color: var(--code-fg); + background-color: var(--code-bg); + background-color: transparent; + } + + .m-markdown-small pre code { + color: var(--fg2); + background-color: var(--bg3); + } + + .m-markdown ul, + .m-markdown ol { + padding-inline-start: 30px; + } + + .m-markdown-small ul, + .m-markdown-small ol { + padding-inline-start: 20px; + } + + .m-markdown-small a, + .m-markdown a { + color:var(--blue); + } + + .m-markdown-small img, + .m-markdown img { + max-width: 100%; + } + + /* Markdown table */ + + .m-markdown-small table, + .m-markdown table { + border-spacing: 0; + margin: 10px 0; + border-collapse: separate; + border: 1px solid var(--border-color); + border-radius: var(--border-radius); + font-size: calc(var(--font-size-small) + 1px); + line-height: calc(var(--font-size-small) + 4px); + max-width: 100%; + } + + .m-markdown-small table { + font-size: var(--font-size-small); + line-height: calc(var(--font-size-small) + 2px); + margin: 8px 0; + } + + .m-markdown-small td, + .m-markdown-small th, + .m-markdown td, + .m-markdown th { + vertical-align: top; + border-top: 1px solid var(--border-color); + line-height: calc(var(--font-size-small) + 4px); + } + + .m-markdown-small tr:first-child th, + .m-markdown tr:first-child th { + border-top: 0 none; + } + + .m-markdown th, + .m-markdown td { + padding: 10px 12px; + } + + .m-markdown-small th, + .m-markdown-small td { + padding: 8px 8px; + } + + .m-markdown th, + .m-markdown-small th { + font-weight: 600; + background-color: var(--bg2); + vertical-align: middle; + } + + .m-markdown-small table code { + font-size: calc(var(--font-size-mono) - 2px); + } + + .m-markdown table code { + font-size: calc(var(--font-size-mono) - 1px); + } + + .m-markdown blockquote, + .m-markdown-small blockquote { + margin-inline-start: 0; + margin-inline-end: 0; + border-left: 3px solid var(--border-color); + padding: 6px 0 6px 6px; + } + .m-markdown hr{ + border: 1px solid var(--border-color); + } +`,Je=c` +/* Button */ +.m-btn { + border-radius: var(--border-radius); + font-weight: 600; + display: inline-block; + padding: 6px 16px; + font-size: var(--font-size-small); + outline: 0; + line-height: 1; + text-align: center; + white-space: nowrap; + border: 2px solid var(--primary-color); + background-color:transparent; + transition: background-color 0.2s; + user-select: none; + cursor: pointer; + box-shadow: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24); +} +.m-btn.primary { + background-color: var(--primary-color); + color: var(--primary-color-invert); +} +.m-btn.thin-border { border-width: 1px; } +.m-btn.large { padding:8px 14px; } +.m-btn.small { padding:5px 12px; } +.m-btn.tiny { padding:5px 6px; } +.m-btn.circle { border-radius: 50%; } +.m-btn:hover { + background-color: var(--primary-color); + color: var(--primary-color-invert); +} +.m-btn.nav { border: 2px solid var(--nav-accent-color); } +.m-btn.nav:hover { + background-color: var(--nav-accent-color); +} +.m-btn:disabled{ + background-color: var(--bg3); + color: var(--fg3); + border-color: var(--fg3); + cursor: not-allowed; + opacity: 0.4; +} +.toolbar-btn{ + cursor: pointer; + padding: 4px; + margin:0 2px; + font-size: var(--font-size-small); + min-width: 50px; + color: var(--primary-color-invert); + border-radius: 2px; + border: none; + background-color: var(--primary-color); +} + +input, textarea, select, button, pre { + color:var(--fg); + outline: none; + background-color: var(--input-bg); + border: 1px solid var(--border-color); + border-radius: var(--border-radius); +} +button { + font-family: var(--font-regular); +} + +/* Form Inputs */ +pre, +select, +textarea, +input[type="file"], +input[type="text"], +input[type="password"] { + font-family: var(--font-mono); + font-weight: 400; + font-size: var(--font-size-small); + transition: border .2s; + padding: 6px 5px; +} + +select { + font-family: var(--font-regular); + padding: 5px 30px 5px 5px; + background-image: url("data:image/svg+xml;charset=utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2212%22%20height%3D%2212%22%3E%3Cpath%20d%3D%22M10.3%203.3L6%207.6%201.7%203.3A1%201%200%2000.3%204.7l5%205a1%201%200%20001.4%200l5-5a1%201%200%2010-1.4-1.4z%22%20fill%3D%22%23777777%22%2F%3E%3C%2Fsvg%3E"); + background-position: calc(100% - 5px) center; + background-repeat: no-repeat; + background-size: 10px; + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + cursor: pointer; +} + +select:hover { + border-color: var(--primary-color); +} + +textarea::placeholder, +input[type="text"]::placeholder, +input[type="password"]::placeholder { + color: var(--placeholder-color); + opacity:1; +} + + +input[type="file"]{ + font-family: var(--font-regular); + padding:2px; + cursor:pointer; + border: 1px solid var(--primary-color); + min-height: calc(var(--font-size-small) + 18px); +} + +input[type="file"]::-webkit-file-upload-button { + font-family: var(--font-regular); + font-size: var(--font-size-small); + outline: none; + cursor:pointer; + padding: 3px 8px; + border: 1px solid var(--primary-color); + background-color: var(--primary-color); + color: var(--primary-color-invert); + border-radius: var(--border-radius);; + -webkit-appearance: none; +} + +pre, +textarea { + scrollbar-width: thin; + scrollbar-color: var(--border-color) var(--input-bg); +} + +pre::-webkit-scrollbar, +textarea::-webkit-scrollbar { + width: 8px; + height: 8px; +} + +pre::-webkit-scrollbar-track, +textarea::-webkit-scrollbar-track { + background:var(--input-bg); +} + +pre::-webkit-scrollbar-thumb, +textarea::-webkit-scrollbar-thumb { + border-radius: 2px; + background-color: var(--border-color); +} + +.link { + font-size:var(--font-size-small); + text-decoration: underline; + color:var(--blue); + font-family:var(--font-mono); + margin-bottom:2px; +} + +/* Toggle Body */ +input[type="checkbox"] { + appearance: none; + display: inline-block; + background-color: var(--light-bg); + border: 1px solid var(--light-bg); + border-radius: 9px; + cursor: pointer; + height: 18px; + position: relative; + transition: border .25s .15s, box-shadow .25s .3s, padding .25s; + min-width: 36px; + width: 36px; + vertical-align: top; +} +/* Toggle Thumb */ +input[type="checkbox"]:after { + position: absolute; + background-color: var(--bg); + border: 1px solid var(--light-bg); + border-radius: 8px; + content: ''; + top: 0px; + left: 0px; + right: 16px; + display: block; + height: 16px; + transition: border .25s .15s, left .25s .1s, right .15s .175s; +} + +/* Toggle Body - Checked */ +input[type="checkbox"]:checked { + background-color: var(--green); + border-color: var(--green); +} +/* Toggle Thumb - Checked*/ +input[type="checkbox"]:checked:after { + border: 1px solid var(--green); + left: 16px; + right: 1px; + transition: border .25s, left .15s .25s, right .25s .175s; +}`,Ye=c` +.row, .col{ + display:flex; +} +.row { + align-items:center; + flex-direction: row; +} +.col { + align-items:stretch; + flex-direction: column; +} +`,Ze=c` +.m-table { + border-spacing: 0; + border-collapse: separate; + border: 1px solid var(--light-border-color); + border-radius: var(--border-radius); + margin: 0; + max-width: 100%; + direction: ltr; +} +.m-table tr:first-child td, +.m-table tr:first-child th { + border-top: 0 none; +} +.m-table td, +.m-table th { + font-size: var(--font-size-small); + line-height: calc(var(--font-size-small) + 4px); + padding: 4px 5px 4px; + vertical-align: top; +} + +.m-table.padded-12 td, +.m-table.padded-12 th { + padding: 12px; +} + +.m-table td:not([align]), +.m-table th:not([align]) { + text-align: left; +} + +.m-table th { + color: var(--fg2); + font-size: var(--font-size-small); + line-height: calc(var(--font-size-small) + 18px); + font-weight: 600; + letter-spacing: normal; + background-color: var(--bg2); + vertical-align: bottom; + border-bottom: 1px solid var(--light-border-color); +} + +.m-table > tbody > tr > td, +.m-table > tr > td { + border-top: 1px solid var(--light-border-color); + text-overflow: ellipsis; + overflow: hidden; +} +.table-title { + font-size:var(--font-size-small); + font-weight:bold; + vertical-align: middle; + margin: 12px 0 4px 0; +} +`,Qe=c` +.only-large-screen { display:none; } +.endpoint-head .path{ + display: flex; + font-family:var(--font-mono); + font-size: var(--font-size-small); + align-items: center; + overflow-wrap: break-word; + word-break: break-all; +} + +.endpoint-head .descr { + font-size: var(--font-size-small); + color:var(--light-fg); + font-weight:400; + align-items: center; + overflow-wrap: break-word; + word-break: break-all; + display:none; +} + +.m-endpoint.expanded{margin-bottom:16px; } +.m-endpoint > .endpoint-head{ + border-width:1px 1px 1px 5px; + border-style:solid; + border-color:transparent; + border-top-color:var(--light-border-color); + display:flex; + padding:6px 16px; + align-items: center; + cursor: pointer; +} +.m-endpoint > .endpoint-head.put:hover, +.m-endpoint > .endpoint-head.put.expanded{ + border-color:var(--orange); + background-color:var(--light-orange); +} +.m-endpoint > .endpoint-head.post:hover, +.m-endpoint > .endpoint-head.post.expanded { + border-color:var(--green); + background-color:var(--light-green); +} +.m-endpoint > .endpoint-head.get:hover, +.m-endpoint > .endpoint-head.get.expanded { + border-color:var(--blue); + background-color:var(--light-blue); +} +.m-endpoint > .endpoint-head.delete:hover, +.m-endpoint > .endpoint-head.delete.expanded { + border-color:var(--red); + background-color:var(--light-red); +} + +.m-endpoint > .endpoint-head.head:hover, +.m-endpoint > .endpoint-head.head.expanded, +.m-endpoint > .endpoint-head.patch:hover, +.m-endpoint > .endpoint-head.patch.expanded, +.m-endpoint > .endpoint-head.options:hover, +.m-endpoint > .endpoint-head.options.expanded { + border-color:var(--yellow); + background-color:var(--light-yellow); +} + +.m-endpoint > .endpoint-head.deprecated:hover, +.m-endpoint > .endpoint-head.deprecated.expanded { + border-color:var(--border-color); + filter:opacity(0.6); +} + +.m-endpoint .endpoint-body { + flex-wrap:wrap; + padding:16px 0px 0 0px; + border-width:0px 1px 1px 5px; + border-style:solid; + box-shadow: 0px 4px 3px -3px rgba(0, 0, 0, 0.15); +} +.m-endpoint .endpoint-body.delete{ border-color:var(--red); } +.m-endpoint .endpoint-body.put{ border-color:var(--orange); } +.m-endpoint .endpoint-body.post{border-color:var(--green);} +.m-endpoint .endpoint-body.get{ border-color:var(--blue); } +.m-endpoint .endpoint-body.head, +.m-endpoint .endpoint-body.patch, +.m-endpoint .endpoint-body.options { + border-color:var(--yellow); +} + +.m-endpoint .endpoint-body.deprecated{ + border-color:var(--border-color); + filter:opacity(0.6); +} + +.endpoint-head .deprecated{ + color: var(--light-fg); + filter:opacity(0.6); +} + +.summary{ + padding:8px 8px; +} +.summary .title{ + font-size:calc(var(--font-size-regular) + 2px); + margin-bottom: 6px; + word-break: break-all; +} + +.endpoint-head .method{ + padding:2px 5px; + vertical-align: middle; + font-size:var(--font-size-small); + height: calc(var(--font-size-small) + 16px); + line-height: calc(var(--font-size-small) + 8px); + width: 60px; + border-radius: 2px; + display:inline-block; + text-align: center; + font-weight: bold; + text-transform:uppercase; + margin-right:5px; +} +.endpoint-head .method.delete{ border: 2px solid var(--red);} +.endpoint-head .method.put{ border: 2px solid var(--orange); } +.endpoint-head .method.post{ border: 2px solid var(--green); } +.endpoint-head .method.get{ border: 2px solid var(--blue); } +.endpoint-head .method.get.deprecated{ border: 2px solid var(--border-color); } +.endpoint-head .method.head, +.endpoint-head .method.patch, +.endpoint-head .method.options { + border: 2px solid var(--yellow); +} + +.req-resp-container { + display: flex; + margin-top:16px; + align-items: stretch; + flex-wrap: wrap; + flex-direction: column; + border-top:1px solid var(--light-border-color); +} + +.view-mode-request, +api-response.view-mode { + flex:1; + min-height:100px; + padding:16px 8px; + overflow:hidden; +} +.view-mode-request { + border-width:0 0 1px 0; + border-style:dashed; +} + +.head .view-mode-request, +.patch .view-mode-request, +.options .view-mode-request { + border-color:var(--yellow); +} +.put .view-mode-request { + border-color:var(--orange); +} +.post .view-mode-request { + border-color:var(--green); +} +.get .view-mode-request { + border-color:var(--blue); +} +.delete .view-mode-request { + border-color:var(--red); +} + +@media only screen and (min-width: 1024px) { + .only-large-screen { display:block; } + .endpoint-head .path{ + font-size: var(--font-size-regular); + } + .endpoint-head .descr{ + display: flex; + } + .endpoint-head .m-markdown-small, + .descr .m-markdown-small{ + display:block; + } + .req-resp-container{ + flex-direction: var(--layout, row); + flex-wrap: nowrap; + } + api-response.view-mode { + padding:16px; + } + .view-mode-request.row-layout { + border-width:0 1px 0 0; + padding:16px; + } + .summary{ + padding:8px 16px; + } +} +`,Xe=c` +code[class*="language-"], +pre[class*="language-"] { + text-align: left; + white-space: pre; + word-spacing: normal; + word-break: normal; + word-wrap: normal; + line-height: 1.5; + tab-size: 2; + + -webkit-hyphens: none; + -moz-hyphens: none; + -ms-hyphens: none; + hyphens: none; +} + +/* Code blocks */ +pre[class*="language-"] { + padding: 1em; + margin: .5em 0; + overflow: auto; +} + +/* Inline code */ +:not(pre) > code[class*="language-"] { + white-space: normal; +} + +.token.comment, +.token.block-comment, +.token.prolog, +.token.doctype, +.token.cdata { + color: var(--light-fg) +} + +.token.punctuation { + color: var(--fg); +} + +.token.tag, +.token.attr-name, +.token.namespace, +.token.deleted { + color:var(--pink); +} + +.token.function-name { + color: var(--blue); +} + +.token.boolean, +.token.number, +.token.function { + color: var(--red); +} + +.token.property, +.token.class-name, +.token.constant, +.token.symbol { + color: var(--code-property-color); +} + +.token.selector, +.token.important, +.token.atrule, +.token.keyword, +.token.builtin { + color: var(--code-keyword-color); +} + +.token.string, +.token.char, +.token.attr-value, +.token.regex, +.token.variable { + color: var(--green); +} + +.token.operator, +.token.entity, +.token.url { + color: var(--code-operator-color); +} + +.token.important, +.token.bold { + font-weight: bold; +} +.token.italic { + font-style: italic; +} + +.token.entity { + cursor: help; +} + +.token.inserted { + color: green; +} +`,et=c` +.tab-panel { + border: none; +} +.tab-buttons { + height:30px; + padding: 4px 4px 0 4px; + border-bottom: 1px solid var(--light-border-color) ; + align-items: stretch; + overflow-y: hidden; + overflow-x: auto; + scrollbar-width: thin; +} +.tab-buttons::-webkit-scrollbar { + height: 1px; + background-color: var(--border-color); +} +.tab-btn { + border: none; + border-bottom: 3px solid transparent; + color: var(--light-fg); + background-color: transparent; + white-space: nowrap; + cursor:pointer; + outline:none; + font-family:var(--font-regular); + font-size:var(--font-size-small); + margin-right:16px; + padding:1px; +} +.tab-btn.active { + border-bottom: 3px solid var(--primary-color); + font-weight:bold; + color:var(--primary-color); +} + +.tab-btn:hover { + color:var(--primary-color); +} +.tab-content { + margin:-1px 0 0 0; + position:relative; + min-height: 50px; +} +`,tt=c` +.nav-bar-info:focus-visible, +.nav-bar-tag:focus-visible, +.nav-bar-path:focus-visible { + outline: 1px solid; + box-shadow: none; + outline-offset: -4px; +} +.nav-bar-expand-all:focus-visible, +.nav-bar-collapse-all:focus-visible, +.nav-bar-tag-icon:focus-visible { + outline: 1px solid; + box-shadow: none; + outline-offset: 2px; +} +.nav-bar { + width:0; + height:100%; + overflow: hidden; + color:var(--nav-text-color); + background-color: var(--nav-bg-color); + background-blend-mode: multiply; + line-height: calc(var(--font-size-small) + 4px); + display:none; + position:relative; + flex-direction:column; + flex-wrap:nowrap; + word-break:break-word; +} +::slotted([slot=nav-logo]){ + padding:16px 16px 0 16px; +} +.nav-scroll { + overflow-x: hidden; + overflow-y: auto; + overflow-y: overlay; + scrollbar-width: thin; + scrollbar-color: var(--nav-hover-bg-color) transparent; +} + +.nav-bar-tag { + display: flex; + align-items: center; + justify-content: space-between; + flex-direction: row; +} +.nav-bar.read .nav-bar-tag-icon { + display:none; +} +.nav-bar-paths-under-tag { + overflow:hidden; + transition: max-height .2s ease-out, visibility .3s; +} +.collapsed .nav-bar-paths-under-tag { + visibility: hidden; +} + +.nav-bar-expand-all { + transform: rotate(90deg); + cursor:pointer; + margin-right:10px; +} +.nav-bar-collapse-all { + transform: rotate(270deg); + cursor:pointer; +} +.nav-bar-expand-all:hover, .nav-bar-collapse-all:hover { + color: var(--primary-color); +} + +.nav-bar-tag-icon { + color: var(--nav-text-color); + font-size: 20px; +} +.nav-bar-tag-icon:hover { + color:var(--nav-hover-text-color); +} +.nav-bar.focused .nav-bar-tag-and-paths.collapsed .nav-bar-tag-icon::after { + content: '⌵'; + width:16px; + height:16px; + text-align: center; + display: inline-block; + transform: rotate(-90deg); + transition: transform 0.2s ease-out 0s; +} +.nav-bar.focused .nav-bar-tag-and-paths.expanded .nav-bar-tag-icon::after { + content: '⌵'; + width:16px; + height:16px; + text-align: center; + display: inline-block; + transition: transform 0.2s ease-out 0s; +} +.nav-scroll::-webkit-scrollbar { + width: var(--scroll-bar-width, 8px); +} +.nav-scroll::-webkit-scrollbar-track { + background:transparent; +} +.nav-scroll::-webkit-scrollbar-thumb { + background-color: var(--nav-hover-bg-color); +} + +.nav-bar-tag { + font-size: var(--font-size-regular); + color: var(--nav-accent-color); + border-left:4px solid transparent; + font-weight:bold; + padding: 15px 15px 15px 10px; + text-transform: capitalize; +} + +.nav-bar-components, +.nav-bar-h1, +.nav-bar-h2, +.nav-bar-info, +.nav-bar-tag, +.nav-bar-path { + display:flex; + cursor: pointer; + width: 100%; + border: none; + border-radius:4px; + color: var(--nav-text-color); + background: transparent; + border-left:4px solid transparent; +} + +.nav-bar-h1, +.nav-bar-h2, +.nav-bar-path { + font-size: calc(var(--font-size-small) + 1px); + padding: var(--nav-item-padding); +} +.nav-bar-path.small-font { + font-size: var(--font-size-small); +} + +.nav-bar-info { + font-size: var(--font-size-regular); + padding: 16px 10px; + font-weight:bold; +} +.nav-bar-section { + display: flex; + flex-direction: row; + justify-content: space-between; + font-size: var(--font-size-small); + color: var(--nav-text-color); + padding: var(--nav-item-padding); + font-weight:bold; +} +.nav-bar-section.operations { + cursor:pointer; +} +.nav-bar-section.operations:hover { + color:var(--nav-hover-text-color); + background-color:var(--nav-hover-bg-color); +} + +.nav-bar-section:first-child { + display: none; +} +.nav-bar-h2 {margin-left:12px;} + +.nav-bar-h1.left-bar.active, +.nav-bar-h2.left-bar.active, +.nav-bar-info.left-bar.active, +.nav-bar-tag.left-bar.active, +.nav-bar-path.left-bar.active, +.nav-bar-section.left-bar.operations.active { + border-left:4px solid var(--nav-accent-color); + color:var(--nav-hover-text-color); +} + +.nav-bar-h1.colored-block.active, +.nav-bar-h2.colored-block.active, +.nav-bar-info.colored-block.active, +.nav-bar-tag.colored-block.active, +.nav-bar-path.colored-block.active, +.nav-bar-section.colored-block.operations.active { + background-color: var(--nav-accent-color); + color: var(--nav-accent-text-color); + border-radius: 0; +} + +.nav-bar-h1:hover, +.nav-bar-h2:hover, +.nav-bar-info:hover, +.nav-bar-tag:hover, +.nav-bar-path:hover { + color:var(--nav-hover-text-color); + background-color:var(--nav-hover-bg-color); +} +`,rt=c` +#api-info { + font-size: calc(var(--font-size-regular) - 1px); + margin-top: 8px; + margin-left: -15px; +} + +#api-info span:before { + content: "|"; + display: inline-block; + opacity: 0.5; + width: 15px; + text-align: center; +} +#api-info span:first-child:before { + content: ""; + width: 0px; +} +`,nt=c` + +`;const ot=/[\s#:?&={}]/g,at="_rapidoc_api_key";function it(e){return new Promise((t=>setTimeout(t,e)))}function st(e,t){const r=t.target,n=document.createElement("textarea");n.value=e,n.style.position="fixed",document.body.appendChild(n),n.focus(),n.select();try{document.execCommand("copy"),r.innerText="Copied",setTimeout((()=>{r.innerText="Copy"}),5e3)}catch(e){console.error("Unable to copy",e)}document.body.removeChild(n)}function lt(e,t,r="includes"){if("includes"===r){return`${t.method} ${t.path} ${t.summary||t.description||""} ${t.operationId||""}`.toLowerCase().includes(e.toLowerCase())}return new RegExp(e,"i").test(`${t.method} ${t.path}`)}function ct(e,t=new Set){return e?(Object.keys(e).forEach((r=>{var n;if(t.add(r),e[r].properties)ct(e[r].properties,t);else if(null!==(n=e[r].items)&&void 0!==n&&n.properties){var o;ct(null===(o=e[r].items)||void 0===o?void 0:o.properties,t)}})),t):t}function pt(e,t){if(e){const r=document.createElement("a");document.body.appendChild(r),r.style="display: none",r.href=e,r.download=t,r.click(),r.remove()}}function dt(e){if(e){const t=document.createElement("a");document.body.appendChild(t),t.style="display: none",t.href=e,t.target="_blank",t.click(),t.remove()}}function ut(e){return e&&e.t&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}var ht=function(e){return e&&e.Math==Math&&e},ft=ht("object"==typeof globalThis&&globalThis)||ht("object"==typeof window&&window)||ht("object"==typeof self&&self)||ht("object"==typeof ft&&ft)||function(){return this}()||Function("return this")(),mt=function(e){try{return!!e()}catch(e){return!0}},yt=!mt((function(){var e=function(){}.bind();return"function"!=typeof e||e.hasOwnProperty("prototype")})),gt=yt,vt=Function.prototype,bt=vt.apply,xt=vt.call,wt="object"==typeof Reflect&&Reflect.apply||(gt?xt.bind(bt):function(){return xt.apply(bt,arguments)}),$t=yt,kt=Function.prototype,St=kt.bind,At=kt.call,Et=$t&&St.bind(At,At),Ot=$t?function(e){return e&&Et(e)}:function(e){return e&&function(){return At.apply(e,arguments)}},Tt=function(e){return"function"==typeof e},Ct={},jt=!mt((function(){return 7!=Object.defineProperty({},1,{get:function(){return 7}})[1]})),It=yt,_t=Function.prototype.call,Pt=It?_t.bind(_t):function(){return _t.apply(_t,arguments)},Rt={},Lt={}.propertyIsEnumerable,Ft=Object.getOwnPropertyDescriptor,Dt=Ft&&!Lt.call({1:2},1);Rt.f=Dt?function(e){var t=Ft(this,e);return!!t&&t.enumerable}:Lt;var Bt,Nt,qt=function(e,t){return{enumerable:!(1&e),configurable:!(2&e),writable:!(4&e),value:t}},Ut=Ot,zt=Ut({}.toString),Mt=Ut("".slice),Ht=function(e){return Mt(zt(e),8,-1)},Wt=Ot,Vt=mt,Gt=Ht,Kt=ft.Object,Jt=Wt("".split),Yt=Vt((function(){return!Kt("z").propertyIsEnumerable(0)}))?function(e){return"String"==Gt(e)?Jt(e,""):Kt(e)}:Kt,Zt=ft.TypeError,Qt=function(e){if(null==e)throw Zt("Can't call method on "+e);return e},Xt=Yt,er=Qt,tr=function(e){return Xt(er(e))},rr=Tt,nr=function(e){return"object"==typeof e?null!==e:rr(e)},or={},ar=or,ir=ft,sr=Tt,lr=function(e){return sr(e)?e:void 0},cr=function(e,t){return arguments.length<2?lr(ar[e])||lr(ir[e]):ar[e]&&ar[e][t]||ir[e]&&ir[e][t]},pr=Ot({}.isPrototypeOf),dr=cr("navigator","userAgent")||"",ur=ft,hr=dr,fr=ur.process,mr=ur.Deno,yr=fr&&fr.versions||mr&&mr.version,gr=yr&&yr.v8;gr&&(Nt=(Bt=gr.split("."))[0]>0&&Bt[0]<4?1:+(Bt[0]+Bt[1])),!Nt&&hr&&(!(Bt=hr.match(/Edge\/(\d+)/))||Bt[1]>=74)&&(Bt=hr.match(/Chrome\/(\d+)/))&&(Nt=+Bt[1]);var vr=Nt,br=vr,xr=mt,wr=!!Object.getOwnPropertySymbols&&!xr((function(){var e=Symbol();return!String(e)||!(Object(e)instanceof Symbol)||!Symbol.sham&&br&&br<41})),$r=wr&&!Symbol.sham&&"symbol"==typeof Symbol.iterator,kr=cr,Sr=Tt,Ar=pr,Er=$r,Or=ft.Object,Tr=Er?function(e){return"symbol"==typeof e}:function(e){var t=kr("Symbol");return Sr(t)&&Ar(t.prototype,Or(e))},Cr=ft.String,jr=function(e){try{return Cr(e)}catch(e){return"Object"}},Ir=Tt,_r=jr,Pr=ft.TypeError,Rr=function(e){if(Ir(e))return e;throw Pr(_r(e)+" is not a function")},Lr=Rr,Fr=function(e,t){var r=e[t];return null==r?void 0:Lr(r)},Dr=Pt,Br=Tt,Nr=nr,qr=ft.TypeError,Ur={exports:{}},zr=ft,Mr=Object.defineProperty,Hr=ft.i||function(e,t){try{Mr(zr,e,{value:t,configurable:!0,writable:!0})}catch(r){zr[e]=t}return t}("__core-js_shared__",{}),Wr=Hr;(Ur.exports=function(e,t){return Wr[e]||(Wr[e]=void 0!==t?t:{})})("versions",[]).push({version:"3.21.1",mode:"pure",copyright:"© 2014-2022 Denis Pushkarev (zloirock.ru)",license:"https://github.com/zloirock/core-js/blob/v3.21.1/LICENSE",source:"https://github.com/zloirock/core-js"});var Vr=Qt,Gr=ft.Object,Kr=function(e){return Gr(Vr(e))},Jr=Kr,Yr=Ot({}.hasOwnProperty),Zr=Object.hasOwn||function(e,t){return Yr(Jr(e),t)},Qr=Ot,Xr=0,en=Math.random(),tn=Qr(1..toString),rn=function(e){return"Symbol("+(void 0===e?"":e)+")_"+tn(++Xr+en,36)},nn=ft,on=Ur.exports,an=Zr,sn=rn,ln=wr,cn=$r,pn=on("wks"),dn=nn.Symbol,un=dn&&dn.for,hn=cn?dn:dn&&dn.withoutSetter||sn,fn=function(e){if(!an(pn,e)||!ln&&"string"!=typeof pn[e]){var t="Symbol."+e;ln&&an(dn,e)?pn[e]=dn[e]:pn[e]=cn&&un?un(t):hn(t)}return pn[e]},mn=Pt,yn=nr,gn=Tr,vn=Fr,bn=fn,xn=ft.TypeError,wn=bn("toPrimitive"),$n=function(e,t){if(!yn(e)||gn(e))return e;var r,n=vn(e,wn);if(n){if(void 0===t&&(t="default"),r=mn(n,e,t),!yn(r)||gn(r))return r;throw xn("Can't convert object to primitive value")}return void 0===t&&(t="number"),function(e,t){var r,n;if("string"===t&&Br(r=e.toString)&&!Nr(n=Dr(r,e)))return n;if(Br(r=e.valueOf)&&!Nr(n=Dr(r,e)))return n;if("string"!==t&&Br(r=e.toString)&&!Nr(n=Dr(r,e)))return n;throw qr("Can't convert object to primitive value")}(e,t)},kn=Tr,Sn=function(e){var t=$n(e,"string");return kn(t)?t:t+""},An=nr,En=ft.document,On=An(En)&&An(En.createElement),Tn=function(e){return On?En.createElement(e):{}},Cn=Tn,jn=!jt&&!mt((function(){return 7!=Object.defineProperty(Cn("div"),"a",{get:function(){return 7}}).a})),In=jt,_n=Pt,Pn=Rt,Rn=qt,Ln=tr,Fn=Sn,Dn=Zr,Bn=jn,Nn=Object.getOwnPropertyDescriptor;Ct.f=In?Nn:function(e,t){if(e=Ln(e),t=Fn(t),Bn)try{return Nn(e,t)}catch(e){}if(Dn(e,t))return Rn(!_n(Pn.f,e,t),e[t])};var qn=mt,Un=Tt,zn=/#|\.prototype\./,Mn=function(e,t){var r=Wn[Hn(e)];return r==Gn||r!=Vn&&(Un(t)?qn(t):!!t)},Hn=Mn.normalize=function(e){return String(e).replace(zn,".").toLowerCase()},Wn=Mn.data={},Vn=Mn.NATIVE="N",Gn=Mn.POLYFILL="P",Kn=Mn,Jn=Rr,Yn=yt,Zn=Ot(Ot.bind),Qn=function(e,t){return Jn(e),void 0===t?e:Yn?Zn(e,t):function(){return e.apply(t,arguments)}},Xn={},eo=jt&&mt((function(){return 42!=Object.defineProperty((function(){}),"prototype",{value:42,writable:!1}).prototype})),to=ft,ro=nr,no=to.String,oo=to.TypeError,ao=function(e){if(ro(e))return e;throw oo(no(e)+" is not an object")},io=jt,so=jn,lo=eo,co=ao,po=Sn,uo=ft.TypeError,ho=Object.defineProperty,fo=Object.getOwnPropertyDescriptor;Xn.f=io?lo?function(e,t,r){if(co(e),t=po(t),co(r),"function"==typeof e&&"prototype"===t&&"value"in r&&"writable"in r&&!r.writable){var n=fo(e,t);n&&n.writable&&(e[t]=r.value,r={configurable:"configurable"in r?r.configurable:n.configurable,enumerable:"enumerable"in r?r.enumerable:n.enumerable,writable:!1})}return ho(e,t,r)}:ho:function(e,t,r){if(co(e),t=po(t),co(r),so)try{return ho(e,t,r)}catch(e){}if("get"in r||"set"in r)throw uo("Accessors not supported");return"value"in r&&(e[t]=r.value),e};var mo=Xn,yo=qt,go=jt?function(e,t,r){return mo.f(e,t,yo(1,r))}:function(e,t,r){return e[t]=r,e},vo=ft,bo=wt,xo=Ot,wo=Tt,$o=Ct.f,ko=Kn,So=or,Ao=Qn,Eo=go,Oo=Zr,To=function(e){var t=function(r,n,o){if(this instanceof t){switch(arguments.length){case 0:return new e;case 1:return new e(r);case 2:return new e(r,n)}return new e(r,n,o)}return bo(e,this,arguments)};return t.prototype=e.prototype,t},Co=function(e,t){var r,n,o,a,i,s,l,c,p=e.target,d=e.global,u=e.stat,h=e.proto,f=d?vo:u?vo[p]:(vo[p]||{}).prototype,m=d?So:So[p]||Eo(So,p,{})[p],y=m.prototype;for(o in t)r=!ko(d?o:p+(u?".":"#")+o,e.forced)&&f&&Oo(f,o),i=m[o],r&&(s=e.noTargetGet?(c=$o(f,o))&&c.value:f[o]),a=r&&s?s:t[o],r&&typeof i==typeof a||(l=e.bind&&r?Ao(a,vo):e.wrap&&r?To(a):h&&wo(a)?xo(a):a,(e.sham||a&&a.sham||i&&i.sham)&&Eo(l,"sham",!0),Eo(m,o,l),h&&(Oo(So,n=p+"Prototype")||Eo(So,n,{}),Eo(So[n],o,a),e.real&&y&&!y[o]&&Eo(y,o,a)))},jo=Math.ceil,Io=Math.floor,_o=function(e){var t=+e;return t!=t||0===t?0:(t>0?Io:jo)(t)},Po=_o,Ro=Math.max,Lo=Math.min,Fo=function(e,t){var r=Po(e);return r<0?Ro(r+t,0):Lo(r,t)},Do=_o,Bo=Math.min,No=function(e){return e>0?Bo(Do(e),9007199254740991):0},qo=No,Uo=function(e){return qo(e.length)},zo=tr,Mo=Fo,Ho=Uo,Wo=function(e){return function(t,r,n){var o,a=zo(t),i=Ho(a),s=Mo(n,i);if(e&&r!=r){for(;i>s;)if((o=a[s++])!=o)return!0}else for(;i>s;s++)if((e||s in a)&&a[s]===r)return e||s||0;return!e&&-1}},Vo={includes:Wo(!0),indexOf:Wo(!1)},Go={},Ko=Zr,Jo=tr,Yo=Vo.indexOf,Zo=Go,Qo=Ot([].push),Xo=function(e,t){var r,n=Jo(e),o=0,a=[];for(r in n)!Ko(Zo,r)&&Ko(n,r)&&Qo(a,r);for(;t.length>o;)Ko(n,r=t[o++])&&(~Yo(a,r)||Qo(a,r));return a},ea=["constructor","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","toLocaleString","toString","valueOf"],ta=Xo,ra=ea,na=Object.keys||function(e){return ta(e,ra)},oa=Kr,aa=na;Co({target:"Object",stat:!0,forced:mt((function(){aa(1)}))},{keys:function(e){return aa(oa(e))}});var ia=or.Object.keys;const sa=ut({exports:{}}.exports=ia);var la=Ht,ca=Array.isArray||function(e){return"Array"==la(e)},pa={};pa[fn("toStringTag")]="z";var da="[object z]"===String(pa),ua=ft,ha=da,fa=Tt,ma=Ht,ya=fn("toStringTag"),ga=ua.Object,va="Arguments"==ma(function(){return arguments}()),ba=ha?ma:function(e){var t,r,n;return void 0===e?"Undefined":null===e?"Null":"string"==typeof(r=function(e,t){try{return e[t]}catch(e){}}(t=ga(e),ya))?r:va?ma(t):"Object"==(n=ma(t))&&fa(t.callee)?"Arguments":n},xa=ba,wa=ft.String,$a=function(e){if("Symbol"===xa(e))throw TypeError("Cannot convert a Symbol value to a string");return wa(e)},ka={},Sa=jt,Aa=eo,Ea=Xn,Oa=ao,Ta=tr,Ca=na;ka.f=Sa&&!Aa?Object.defineProperties:function(e,t){Oa(e);for(var r,n=Ta(t),o=Ca(t),a=o.length,i=0;a>i;)Ea.f(e,r=o[i++],n[r]);return e};var ja,Ia=cr("document","documentElement"),_a=Ur.exports,Pa=rn,Ra=_a("keys"),La=function(e){return Ra[e]||(Ra[e]=Pa(e))},Fa=ao,Da=ka,Ba=ea,Na=Go,qa=Ia,Ua=Tn,za=La("IE_PROTO"),Ma=function(){},Ha=function(e){return" - - - - - - \ No newline at end of file diff --git a/cli/unitctl/www/rapidoc-min-9.3.4.js b/cli/unitctl/www/rapidoc-min-9.3.4.js deleted file mode 100644 index 0104e904a..000000000 --- a/cli/unitctl/www/rapidoc-min-9.3.4.js +++ /dev/null @@ -1,3895 +0,0 @@ -/*! RapiDoc 9.3.4 | Author - Mrinmoy Majumdar | License information can be found in rapidoc-min.js.LICENSE.txt */ -(()=>{var e,t,r={656:(e,t,r)=>{"use strict";const n=window,o=n.ShadowRoot&&(void 0===n.ShadyCSS||n.ShadyCSS.nativeShadow)&&"adoptedStyleSheets"in Document.prototype&&"replace"in CSSStyleSheet.prototype,a=Symbol(),i=new WeakMap;class s{constructor(e,t,r){if(this._$cssResult$=!0,r!==a)throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");this.cssText=e,this.t=t}get styleSheet(){let e=this.o;const t=this.t;if(o&&void 0===e){const r=void 0!==t&&1===t.length;r&&(e=i.get(t)),void 0===e&&((this.o=e=new CSSStyleSheet).replaceSync(this.cssText),r&&i.set(t,e))}return e}toString(){return this.cssText}}const l=e=>new s("string"==typeof e?e:e+"",void 0,a),c=(e,...t)=>{const r=1===e.length?e[0]:t.reduce(((t,r,n)=>t+(e=>{if(!0===e._$cssResult$)return e.cssText;if("number"==typeof e)return e;throw Error("Value passed to 'css' function must be a 'css' function result: "+e+". Use 'unsafeCSS' to pass non-literal values, but take care to ensure page security.")})(r)+e[n+1]),e[0]);return new s(r,e,a)},p=o?e=>e:e=>e instanceof CSSStyleSheet?(e=>{let t="";for(const r of e.cssRules)t+=r.cssText;return l(t)})(e):e;var d;const u=window,h=u.trustedTypes,f=h?h.emptyScript:"",m=u.reactiveElementPolyfillSupport,y={toAttribute(e,t){switch(t){case Boolean:e=e?f:null;break;case Object:case Array:e=null==e?e:JSON.stringify(e)}return e},fromAttribute(e,t){let r=e;switch(t){case Boolean:r=null!==e;break;case Number:r=null===e?null:Number(e);break;case Object:case Array:try{r=JSON.parse(e)}catch(e){r=null}}return r}},g=(e,t)=>t!==e&&(t==t||e==e),v={attribute:!0,type:String,converter:y,reflect:!1,hasChanged:g};class b extends HTMLElement{constructor(){super(),this._$Ei=new Map,this.isUpdatePending=!1,this.hasUpdated=!1,this._$El=null,this.u()}static addInitializer(e){var t;this.finalize(),(null!==(t=this.h)&&void 0!==t?t:this.h=[]).push(e)}static get observedAttributes(){this.finalize();const e=[];return this.elementProperties.forEach(((t,r)=>{const n=this._$Ep(r,t);void 0!==n&&(this._$Ev.set(n,r),e.push(n))})),e}static createProperty(e,t=v){if(t.state&&(t.attribute=!1),this.finalize(),this.elementProperties.set(e,t),!t.noAccessor&&!this.prototype.hasOwnProperty(e)){const r="symbol"==typeof e?Symbol():"__"+e,n=this.getPropertyDescriptor(e,r,t);void 0!==n&&Object.defineProperty(this.prototype,e,n)}}static getPropertyDescriptor(e,t,r){return{get(){return this[t]},set(n){const o=this[e];this[t]=n,this.requestUpdate(e,o,r)},configurable:!0,enumerable:!0}}static getPropertyOptions(e){return this.elementProperties.get(e)||v}static finalize(){if(this.hasOwnProperty("finalized"))return!1;this.finalized=!0;const e=Object.getPrototypeOf(this);if(e.finalize(),void 0!==e.h&&(this.h=[...e.h]),this.elementProperties=new Map(e.elementProperties),this._$Ev=new Map,this.hasOwnProperty("properties")){const e=this.properties,t=[...Object.getOwnPropertyNames(e),...Object.getOwnPropertySymbols(e)];for(const r of t)this.createProperty(r,e[r])}return this.elementStyles=this.finalizeStyles(this.styles),!0}static finalizeStyles(e){const t=[];if(Array.isArray(e)){const r=new Set(e.flat(1/0).reverse());for(const e of r)t.unshift(p(e))}else void 0!==e&&t.push(p(e));return t}static _$Ep(e,t){const r=t.attribute;return!1===r?void 0:"string"==typeof r?r:"string"==typeof e?e.toLowerCase():void 0}u(){var e;this._$E_=new Promise((e=>this.enableUpdating=e)),this._$AL=new Map,this._$Eg(),this.requestUpdate(),null===(e=this.constructor.h)||void 0===e||e.forEach((e=>e(this)))}addController(e){var t,r;(null!==(t=this._$ES)&&void 0!==t?t:this._$ES=[]).push(e),void 0!==this.renderRoot&&this.isConnected&&(null===(r=e.hostConnected)||void 0===r||r.call(e))}removeController(e){var t;null===(t=this._$ES)||void 0===t||t.splice(this._$ES.indexOf(e)>>>0,1)}_$Eg(){this.constructor.elementProperties.forEach(((e,t)=>{this.hasOwnProperty(t)&&(this._$Ei.set(t,this[t]),delete this[t])}))}createRenderRoot(){var e;const t=null!==(e=this.shadowRoot)&&void 0!==e?e:this.attachShadow(this.constructor.shadowRootOptions);return((e,t)=>{o?e.adoptedStyleSheets=t.map((e=>e instanceof CSSStyleSheet?e:e.styleSheet)):t.forEach((t=>{const r=document.createElement("style"),o=n.litNonce;void 0!==o&&r.setAttribute("nonce",o),r.textContent=t.cssText,e.appendChild(r)}))})(t,this.constructor.elementStyles),t}connectedCallback(){var e;void 0===this.renderRoot&&(this.renderRoot=this.createRenderRoot()),this.enableUpdating(!0),null===(e=this._$ES)||void 0===e||e.forEach((e=>{var t;return null===(t=e.hostConnected)||void 0===t?void 0:t.call(e)}))}enableUpdating(e){}disconnectedCallback(){var e;null===(e=this._$ES)||void 0===e||e.forEach((e=>{var t;return null===(t=e.hostDisconnected)||void 0===t?void 0:t.call(e)}))}attributeChangedCallback(e,t,r){this._$AK(e,r)}_$EO(e,t,r=v){var n;const o=this.constructor._$Ep(e,r);if(void 0!==o&&!0===r.reflect){const a=(void 0!==(null===(n=r.converter)||void 0===n?void 0:n.toAttribute)?r.converter:y).toAttribute(t,r.type);this._$El=e,null==a?this.removeAttribute(o):this.setAttribute(o,a),this._$El=null}}_$AK(e,t){var r;const n=this.constructor,o=n._$Ev.get(e);if(void 0!==o&&this._$El!==o){const e=n.getPropertyOptions(o),a="function"==typeof e.converter?{fromAttribute:e.converter}:void 0!==(null===(r=e.converter)||void 0===r?void 0:r.fromAttribute)?e.converter:y;this._$El=o,this[o]=a.fromAttribute(t,e.type),this._$El=null}}requestUpdate(e,t,r){let n=!0;void 0!==e&&(((r=r||this.constructor.getPropertyOptions(e)).hasChanged||g)(this[e],t)?(this._$AL.has(e)||this._$AL.set(e,t),!0===r.reflect&&this._$El!==e&&(void 0===this._$EC&&(this._$EC=new Map),this._$EC.set(e,r))):n=!1),!this.isUpdatePending&&n&&(this._$E_=this._$Ej())}async _$Ej(){this.isUpdatePending=!0;try{await this._$E_}catch(e){Promise.reject(e)}const e=this.scheduleUpdate();return null!=e&&await e,!this.isUpdatePending}scheduleUpdate(){return this.performUpdate()}performUpdate(){var e;if(!this.isUpdatePending)return;this.hasUpdated,this._$Ei&&(this._$Ei.forEach(((e,t)=>this[t]=e)),this._$Ei=void 0);let t=!1;const r=this._$AL;try{t=this.shouldUpdate(r),t?(this.willUpdate(r),null===(e=this._$ES)||void 0===e||e.forEach((e=>{var t;return null===(t=e.hostUpdate)||void 0===t?void 0:t.call(e)})),this.update(r)):this._$Ek()}catch(e){throw t=!1,this._$Ek(),e}t&&this._$AE(r)}willUpdate(e){}_$AE(e){var t;null===(t=this._$ES)||void 0===t||t.forEach((e=>{var t;return null===(t=e.hostUpdated)||void 0===t?void 0:t.call(e)})),this.hasUpdated||(this.hasUpdated=!0,this.firstUpdated(e)),this.updated(e)}_$Ek(){this._$AL=new Map,this.isUpdatePending=!1}get updateComplete(){return this.getUpdateComplete()}getUpdateComplete(){return this._$E_}shouldUpdate(e){return!0}update(e){void 0!==this._$EC&&(this._$EC.forEach(((e,t)=>this._$EO(t,this[t],e))),this._$EC=void 0),this._$Ek()}updated(e){}firstUpdated(e){}}var x;b.finalized=!0,b.elementProperties=new Map,b.elementStyles=[],b.shadowRootOptions={mode:"open"},null==m||m({ReactiveElement:b}),(null!==(d=u.reactiveElementVersions)&&void 0!==d?d:u.reactiveElementVersions=[]).push("1.6.1");const w=window,$=w.trustedTypes,k=$?$.createPolicy("lit-html",{createHTML:e=>e}):void 0,S=`lit$${(Math.random()+"").slice(9)}$`,A="?"+S,E=`<${A}>`,O=document,T=(e="")=>O.createComment(e),C=e=>null===e||"object"!=typeof e&&"function"!=typeof e,j=Array.isArray,I=e=>j(e)||"function"==typeof(null==e?void 0:e[Symbol.iterator]),_=/<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g,P=/-->/g,R=/>/g,L=RegExp(">|[ \t\n\f\r](?:([^\\s\"'>=/]+)([ \t\n\f\r]*=[ \t\n\f\r]*(?:[^ \t\n\f\r\"'`<>=]|(\"|')|))|$)","g"),F=/'/g,D=/"/g,B=/^(?:script|style|textarea|title)$/i,N=e=>(t,...r)=>({_$litType$:e,strings:t,values:r}),q=N(1),U=(N(2),Symbol.for("lit-noChange")),z=Symbol.for("lit-nothing"),M=new WeakMap,H=O.createTreeWalker(O,129,null,!1),W=(e,t)=>{const r=e.length-1,n=[];let o,a=2===t?"":"",i=_;for(let t=0;t"===l[0]?(i=null!=o?o:_,c=-1):void 0===l[1]?c=-2:(c=i.lastIndex-l[2].length,s=l[1],i=void 0===l[3]?L:'"'===l[3]?D:F):i===D||i===F?i=L:i===P||i===R?i=_:(i=L,o=void 0);const d=i===L&&e[t+1].startsWith("/>")?" ":"";a+=i===_?r+E:c>=0?(n.push(s),r.slice(0,c)+"$lit$"+r.slice(c)+S+d):r+S+(-2===c?(n.push(void 0),t):d)}const s=a+(e[r]||"")+(2===t?"":"");if(!Array.isArray(e)||!e.hasOwnProperty("raw"))throw Error("invalid template strings array");return[void 0!==k?k.createHTML(s):s,n]};class V{constructor({strings:e,_$litType$:t},r){let n;this.parts=[];let o=0,a=0;const i=e.length-1,s=this.parts,[l,c]=W(e,t);if(this.el=V.createElement(l,r),H.currentNode=this.el.content,2===t){const e=this.el.content,t=e.firstChild;t.remove(),e.append(...t.childNodes)}for(;null!==(n=H.nextNode())&&s.length0){n.textContent=$?$.emptyScript:"";for(let r=0;r2||""!==r[0]||""!==r[1]?(this._$AH=Array(r.length-1).fill(new String),this.strings=r):this._$AH=z}get tagName(){return this.element.tagName}get _$AU(){return this._$AM._$AU}_$AI(e,t=this,r,n){const o=this.strings;let a=!1;if(void 0===o)e=G(this,e,t,0),a=!C(e)||e!==this._$AH&&e!==U,a&&(this._$AH=e);else{const n=e;let i,s;for(e=o[0],i=0;i{var n,o;const a=null!==(n=null==r?void 0:r.renderBefore)&&void 0!==n?n:t;let i=a._$litPart$;if(void 0===i){const e=null!==(o=null==r?void 0:r.renderBefore)&&void 0!==o?o:null;a._$litPart$=i=new J(t.insertBefore(T(),e),e,void 0,null!=r?r:{})}return i._$AI(e),i})(t,this.renderRoot,this.renderOptions)}connectedCallback(){var e;super.connectedCallback(),null===(e=this._$Dt)||void 0===e||e.setConnected(!0)}disconnectedCallback(){var e;super.disconnectedCallback(),null===(e=this._$Dt)||void 0===e||e.setConnected(!1)}render(){return U}}ie.finalized=!0,ie._$litElement$=!0,null===(oe=globalThis.litElementHydrateSupport)||void 0===oe||oe.call(globalThis,{LitElement:ie});const se=globalThis.litElementPolyfillSupport;null==se||se({LitElement:ie});function le(){return{async:!1,baseUrl:null,breaks:!1,extensions:null,gfm:!0,headerIds:!0,headerPrefix:"",highlight:null,langPrefix:"language-",mangle:!0,pedantic:!1,renderer:null,sanitize:!1,sanitizer:null,silent:!1,smartypants:!1,tokenizer:null,walkTokens:null,xhtml:!1}}(null!==(ae=globalThis.litElementVersions)&&void 0!==ae?ae:globalThis.litElementVersions=[]).push("3.2.0");let ce={async:!1,baseUrl:null,breaks:!1,extensions:null,gfm:!0,headerIds:!0,headerPrefix:"",highlight:null,langPrefix:"language-",mangle:!0,pedantic:!1,renderer:null,sanitize:!1,sanitizer:null,silent:!1,smartypants:!1,tokenizer:null,walkTokens:null,xhtml:!1};const pe=/[&<>"']/,de=new RegExp(pe.source,"g"),ue=/[<>"']|&(?!(#\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\w+);)/,he=new RegExp(ue.source,"g"),fe={"&":"&","<":"<",">":">",'"':""","'":"'"},me=e=>fe[e];function ye(e,t){if(t){if(pe.test(e))return e.replace(de,me)}else if(ue.test(e))return e.replace(he,me);return e}const ge=/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/gi;function ve(e){return e.replace(ge,((e,t)=>"colon"===(t=t.toLowerCase())?":":"#"===t.charAt(0)?"x"===t.charAt(1)?String.fromCharCode(parseInt(t.substring(2),16)):String.fromCharCode(+t.substring(1)):""))}const be=/(^|[^\[])\^/g;function xe(e,t){e="string"==typeof e?e:e.source,t=t||"";const r={replace:(t,n)=>(n=(n=n.source||n).replace(be,"$1"),e=e.replace(t,n),r),getRegex:()=>new RegExp(e,t)};return r}const we=/[^\w:]/g,$e=/^$|^[a-z][a-z0-9+.-]*:|^[?#]/i;function ke(e,t,r){if(e){let e;try{e=decodeURIComponent(ve(r)).replace(we,"").toLowerCase()}catch(e){return null}if(0===e.indexOf("javascript:")||0===e.indexOf("vbscript:")||0===e.indexOf("data:"))return null}t&&!$e.test(r)&&(r=function(e,t){Se[" "+e]||(Ae.test(e)?Se[" "+e]=e+"/":Se[" "+e]=Ie(e,"/",!0));const r=-1===(e=Se[" "+e]).indexOf(":");return"//"===t.substring(0,2)?r?t:e.replace(Ee,"$1")+t:"/"===t.charAt(0)?r?t:e.replace(Oe,"$1")+t:e+t}(t,r));try{r=encodeURI(r).replace(/%25/g,"%")}catch(e){return null}return r}const Se={},Ae=/^[^:]+:\/*[^/]*$/,Ee=/^([^:]+:)[\s\S]*$/,Oe=/^([^:]+:\/*[^/]*)[\s\S]*$/;const Te={exec:function(){}};function Ce(e){let t,r,n=1;for(;n{let n=!1,o=t;for(;--o>=0&&"\\"===r[o];)n=!n;return n?"|":" |"})).split(/ \|/);let n=0;if(r[0].trim()||r.shift(),r.length>0&&!r[r.length-1].trim()&&r.pop(),r.length>t)r.splice(t);else for(;r.length1;)1&t&&(r+=e),t>>=1,e+=e;return r+e}function Re(e,t,r,n){const o=t.href,a=t.title?ye(t.title):null,i=e[1].replace(/\\([\[\]])/g,"$1");if("!"!==e[0].charAt(0)){n.state.inLink=!0;const e={type:"link",raw:r,href:o,title:a,text:i,tokens:n.inlineTokens(i)};return n.state.inLink=!1,e}return{type:"image",raw:r,href:o,title:a,text:ye(i)}}class Le{constructor(e){this.options=e||ce}space(e){const t=this.rules.block.newline.exec(e);if(t&&t[0].length>0)return{type:"space",raw:t[0]}}code(e){const t=this.rules.block.code.exec(e);if(t){const e=t[0].replace(/^ {1,4}/gm,"");return{type:"code",raw:t[0],codeBlockStyle:"indented",text:this.options.pedantic?e:Ie(e,"\n")}}}fences(e){const t=this.rules.block.fences.exec(e);if(t){const e=t[0],r=function(e,t){const r=e.match(/^(\s+)(?:```)/);if(null===r)return t;const n=r[1];return t.split("\n").map((e=>{const t=e.match(/^\s+/);if(null===t)return e;const[r]=t;return r.length>=n.length?e.slice(n.length):e})).join("\n")}(e,t[3]||"");return{type:"code",raw:e,lang:t[2]?t[2].trim().replace(this.rules.inline._escapes,"$1"):t[2],text:r}}}heading(e){const t=this.rules.block.heading.exec(e);if(t){let e=t[2].trim();if(/#$/.test(e)){const t=Ie(e,"#");this.options.pedantic?e=t.trim():t&&!/ $/.test(t)||(e=t.trim())}return{type:"heading",raw:t[0],depth:t[1].length,text:e,tokens:this.lexer.inline(e)}}}hr(e){const t=this.rules.block.hr.exec(e);if(t)return{type:"hr",raw:t[0]}}blockquote(e){const t=this.rules.block.blockquote.exec(e);if(t){const e=t[0].replace(/^ *>[ \t]?/gm,""),r=this.lexer.state.top;this.lexer.state.top=!0;const n=this.lexer.blockTokens(e);return this.lexer.state.top=r,{type:"blockquote",raw:t[0],tokens:n,text:e}}}list(e){let t=this.rules.block.list.exec(e);if(t){let r,n,o,a,i,s,l,c,p,d,u,h,f=t[1].trim();const m=f.length>1,y={type:"list",raw:"",ordered:m,start:m?+f.slice(0,-1):"",loose:!1,items:[]};f=m?`\\d{1,9}\\${f.slice(-1)}`:`\\${f}`,this.options.pedantic&&(f=m?f:"[*+-]");const g=new RegExp(`^( {0,3}${f})((?:[\t ][^\\n]*)?(?:\\n|$))`);for(;e&&(h=!1,t=g.exec(e))&&!this.rules.block.hr.test(e);){if(r=t[0],e=e.substring(r.length),c=t[2].split("\n",1)[0].replace(/^\t+/,(e=>" ".repeat(3*e.length))),p=e.split("\n",1)[0],this.options.pedantic?(a=2,u=c.trimLeft()):(a=t[2].search(/[^ ]/),a=a>4?1:a,u=c.slice(a),a+=t[1].length),s=!1,!c&&/^ *$/.test(p)&&(r+=p+"\n",e=e.substring(p.length+1),h=!0),!h){const t=new RegExp(`^ {0,${Math.min(3,a-1)}}(?:[*+-]|\\d{1,9}[.)])((?:[ \t][^\\n]*)?(?:\\n|$))`),n=new RegExp(`^ {0,${Math.min(3,a-1)}}((?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$)`),o=new RegExp(`^ {0,${Math.min(3,a-1)}}(?:\`\`\`|~~~)`),i=new RegExp(`^ {0,${Math.min(3,a-1)}}#`);for(;e&&(d=e.split("\n",1)[0],p=d,this.options.pedantic&&(p=p.replace(/^ {1,4}(?=( {4})*[^ ])/g," ")),!o.test(p))&&!i.test(p)&&!t.test(p)&&!n.test(e);){if(p.search(/[^ ]/)>=a||!p.trim())u+="\n"+p.slice(a);else{if(s)break;if(c.search(/[^ ]/)>=4)break;if(o.test(c))break;if(i.test(c))break;if(n.test(c))break;u+="\n"+p}s||p.trim()||(s=!0),r+=d+"\n",e=e.substring(d.length+1),c=p.slice(a)}}y.loose||(l?y.loose=!0:/\n *\n *$/.test(r)&&(l=!0)),this.options.gfm&&(n=/^\[[ xX]\] /.exec(u),n&&(o="[ ] "!==n[0],u=u.replace(/^\[[ xX]\] +/,""))),y.items.push({type:"list_item",raw:r,task:!!n,checked:o,loose:!1,text:u}),y.raw+=r}y.items[y.items.length-1].raw=r.trimRight(),y.items[y.items.length-1].text=u.trimRight(),y.raw=y.raw.trimRight();const v=y.items.length;for(i=0;i"space"===e.type)),t=e.length>0&&e.some((e=>/\n.*\n/.test(e.raw)));y.loose=t}if(y.loose)for(i=0;i$/,"$1").replace(this.rules.inline._escapes,"$1"):"",n=t[3]?t[3].substring(1,t[3].length-1).replace(this.rules.inline._escapes,"$1"):t[3];return{type:"def",tag:e,raw:t[0],href:r,title:n}}}table(e){const t=this.rules.block.table.exec(e);if(t){const e={type:"table",header:je(t[1]).map((e=>({text:e}))),align:t[2].replace(/^ *|\| *$/g,"").split(/ *\| */),rows:t[3]&&t[3].trim()?t[3].replace(/\n[ \t]*$/,"").split("\n"):[]};if(e.header.length===e.align.length){e.raw=t[0];let r,n,o,a,i=e.align.length;for(r=0;r({text:e})));for(i=e.header.length,n=0;n/i.test(t[0])&&(this.lexer.state.inLink=!1),!this.lexer.state.inRawBlock&&/^<(pre|code|kbd|script)(\s|>)/i.test(t[0])?this.lexer.state.inRawBlock=!0:this.lexer.state.inRawBlock&&/^<\/(pre|code|kbd|script)(\s|>)/i.test(t[0])&&(this.lexer.state.inRawBlock=!1),{type:this.options.sanitize?"text":"html",raw:t[0],inLink:this.lexer.state.inLink,inRawBlock:this.lexer.state.inRawBlock,text:this.options.sanitize?this.options.sanitizer?this.options.sanitizer(t[0]):ye(t[0]):t[0]}}link(e){const t=this.rules.inline.link.exec(e);if(t){const e=t[2].trim();if(!this.options.pedantic&&/^$/.test(e))return;const t=Ie(e.slice(0,-1),"\\");if((e.length-t.length)%2==0)return}else{const e=function(e,t){if(-1===e.indexOf(t[1]))return-1;const r=e.length;let n=0,o=0;for(;o-1){const r=(0===t[0].indexOf("!")?5:4)+t[1].length+e;t[2]=t[2].substring(0,e),t[0]=t[0].substring(0,r).trim(),t[3]=""}}let r=t[2],n="";if(this.options.pedantic){const e=/^([^'"]*[^\s])\s+(['"])(.*)\2/.exec(r);e&&(r=e[1],n=e[3])}else n=t[3]?t[3].slice(1,-1):"";return r=r.trim(),/^$/.test(e)?r.slice(1):r.slice(1,-1)),Re(t,{href:r?r.replace(this.rules.inline._escapes,"$1"):r,title:n?n.replace(this.rules.inline._escapes,"$1"):n},t[0],this.lexer)}}reflink(e,t){let r;if((r=this.rules.inline.reflink.exec(e))||(r=this.rules.inline.nolink.exec(e))){let e=(r[2]||r[1]).replace(/\s+/g," ");if(e=t[e.toLowerCase()],!e){const e=r[0].charAt(0);return{type:"text",raw:e,text:e}}return Re(r,e,r[0],this.lexer)}}emStrong(e,t,r=""){let n=this.rules.inline.emStrong.lDelim.exec(e);if(!n)return;if(n[3]&&r.match(/[\p{L}\p{N}]/u))return;const o=n[1]||n[2]||"";if(!o||o&&(""===r||this.rules.inline.punctuation.exec(r))){const r=n[0].length-1;let o,a,i=r,s=0;const l="*"===n[0][0]?this.rules.inline.emStrong.rDelimAst:this.rules.inline.emStrong.rDelimUnd;for(l.lastIndex=0,t=t.slice(-1*e.length+r);null!=(n=l.exec(t));){if(o=n[1]||n[2]||n[3]||n[4]||n[5]||n[6],!o)continue;if(a=o.length,n[3]||n[4]){i+=a;continue}if((n[5]||n[6])&&r%3&&!((r+a)%3)){s+=a;continue}if(i-=a,i>0)continue;a=Math.min(a,a+i+s);const t=e.slice(0,r+n.index+(n[0].length-o.length)+a);if(Math.min(r,a)%2){const e=t.slice(1,-1);return{type:"em",raw:t,text:e,tokens:this.lexer.inlineTokens(e)}}const l=t.slice(2,-2);return{type:"strong",raw:t,text:l,tokens:this.lexer.inlineTokens(l)}}}}codespan(e){const t=this.rules.inline.code.exec(e);if(t){let e=t[2].replace(/\n/g," ");const r=/[^ ]/.test(e),n=/^ /.test(e)&&/ $/.test(e);return r&&n&&(e=e.substring(1,e.length-1)),e=ye(e,!0),{type:"codespan",raw:t[0],text:e}}}br(e){const t=this.rules.inline.br.exec(e);if(t)return{type:"br",raw:t[0]}}del(e){const t=this.rules.inline.del.exec(e);if(t)return{type:"del",raw:t[0],text:t[2],tokens:this.lexer.inlineTokens(t[2])}}autolink(e,t){const r=this.rules.inline.autolink.exec(e);if(r){let e,n;return"@"===r[2]?(e=ye(this.options.mangle?t(r[1]):r[1]),n="mailto:"+e):(e=ye(r[1]),n=e),{type:"link",raw:r[0],text:e,href:n,tokens:[{type:"text",raw:e,text:e}]}}}url(e,t){let r;if(r=this.rules.inline.url.exec(e)){let e,n;if("@"===r[2])e=ye(this.options.mangle?t(r[0]):r[0]),n="mailto:"+e;else{let t;do{t=r[0],r[0]=this.rules.inline._backpedal.exec(r[0])[0]}while(t!==r[0]);e=ye(r[0]),n="www."===r[1]?"http://"+r[0]:r[0]}return{type:"link",raw:r[0],text:e,href:n,tokens:[{type:"text",raw:e,text:e}]}}}inlineText(e,t){const r=this.rules.inline.text.exec(e);if(r){let e;return e=this.lexer.state.inRawBlock?this.options.sanitize?this.options.sanitizer?this.options.sanitizer(r[0]):ye(r[0]):r[0]:ye(this.options.smartypants?t(r[0]):r[0]),{type:"text",raw:r[0],text:e}}}}const Fe={newline:/^(?: *(?:\n|$))+/,code:/^( {4}[^\n]+(?:\n(?: *(?:\n|$))*)?)+/,fences:/^ {0,3}(`{3,}(?=[^`\n]*\n)|~{3,})([^\n]*)\n(?:|([\s\S]*?)\n)(?: {0,3}\1[~`]* *(?=\n|$)|$)/,hr:/^ {0,3}((?:-[\t ]*){3,}|(?:_[ \t]*){3,}|(?:\*[ \t]*){3,})(?:\n+|$)/,heading:/^ {0,3}(#{1,6})(?=\s|$)(.*)(?:\n+|$)/,blockquote:/^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/,list:/^( {0,3}bull)([ \t][^\n]+?)?(?:\n|$)/,html:"^ {0,3}(?:<(script|pre|style|textarea)[\\s>][\\s\\S]*?(?:[^\\n]*\\n+|$)|comment[^\\n]*(\\n+|$)|<\\?[\\s\\S]*?(?:\\?>\\n*|$)|\\n*|$)|\\n*|$)|)[\\s\\S]*?(?:(?:\\n *)+\\n|$)|<(?!script|pre|style|textarea)([a-z][\\w-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n *)+\\n|$)|(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n *)+\\n|$))",def:/^ {0,3}\[(label)\]: *(?:\n *)?([^<\s][^\s]*|<.*?>)(?:(?: +(?:\n *)?| *\n *)(title))? *(?:\n+|$)/,table:Te,lheading:/^((?:.|\n(?!\n))+?)\n {0,3}(=+|-+) *(?:\n+|$)/,_paragraph:/^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html|table| +\n)[^\n]+)*)/,text:/^[^\n]+/,_label:/(?!\s*\])(?:\\.|[^\[\]\\])+/,_title:/(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/};Fe.def=xe(Fe.def).replace("label",Fe._label).replace("title",Fe._title).getRegex(),Fe.bullet=/(?:[*+-]|\d{1,9}[.)])/,Fe.listItemStart=xe(/^( *)(bull) */).replace("bull",Fe.bullet).getRegex(),Fe.list=xe(Fe.list).replace(/bull/g,Fe.bullet).replace("hr","\\n+(?=\\1?(?:(?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$))").replace("def","\\n+(?="+Fe.def.source+")").getRegex(),Fe._tag="address|article|aside|base|basefont|blockquote|body|caption|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option|p|param|section|source|summary|table|tbody|td|tfoot|th|thead|title|tr|track|ul",Fe._comment=/|$)/,Fe.html=xe(Fe.html,"i").replace("comment",Fe._comment).replace("tag",Fe._tag).replace("attribute",/ +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/).getRegex(),Fe.paragraph=xe(Fe._paragraph).replace("hr",Fe.hr).replace("heading"," {0,3}#{1,6} ").replace("|lheading","").replace("|table","").replace("blockquote"," {0,3}>").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html",")|<(?:script|pre|style|textarea|!--)").replace("tag",Fe._tag).getRegex(),Fe.blockquote=xe(Fe.blockquote).replace("paragraph",Fe.paragraph).getRegex(),Fe.normal=Ce({},Fe),Fe.gfm=Ce({},Fe.normal,{table:"^ *([^\\n ].*\\|.*)\\n {0,3}(?:\\| *)?(:?-+:? *(?:\\| *:?-+:? *)*)(?:\\| *)?(?:\\n((?:(?! *\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)"}),Fe.gfm.table=xe(Fe.gfm.table).replace("hr",Fe.hr).replace("heading"," {0,3}#{1,6} ").replace("blockquote"," {0,3}>").replace("code"," {4}[^\\n]").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html",")|<(?:script|pre|style|textarea|!--)").replace("tag",Fe._tag).getRegex(),Fe.gfm.paragraph=xe(Fe._paragraph).replace("hr",Fe.hr).replace("heading"," {0,3}#{1,6} ").replace("|lheading","").replace("table",Fe.gfm.table).replace("blockquote"," {0,3}>").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html",")|<(?:script|pre|style|textarea|!--)").replace("tag",Fe._tag).getRegex(),Fe.pedantic=Ce({},Fe.normal,{html:xe("^ *(?:comment *(?:\\n|\\s*$)|<(tag)[\\s\\S]+? *(?:\\n{2,}|\\s*$)|\\s]*)*?/?> *(?:\\n{2,}|\\s*$))").replace("comment",Fe._comment).replace(/tag/g,"(?!(?:a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)\\b)\\w+(?!:|[^\\w\\s@]*@)\\b").getRegex(),def:/^ *\[([^\]]+)\]: *]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/,heading:/^(#{1,6})(.*)(?:\n+|$)/,fences:Te,lheading:/^(.+?)\n {0,3}(=+|-+) *(?:\n+|$)/,paragraph:xe(Fe.normal._paragraph).replace("hr",Fe.hr).replace("heading"," *#{1,6} *[^\n]").replace("lheading",Fe.lheading).replace("blockquote"," {0,3}>").replace("|fences","").replace("|list","").replace("|html","").getRegex()});const De={escape:/^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/,autolink:/^<(scheme:[^\s\x00-\x1f<>]*|email)>/,url:Te,tag:"^comment|^|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>|^<\\?[\\s\\S]*?\\?>|^|^",link:/^!?\[(label)\]\(\s*(href)(?:\s+(title))?\s*\)/,reflink:/^!?\[(label)\]\[(ref)\]/,nolink:/^!?\[(ref)\](?:\[\])?/,reflinkSearch:"reflink|nolink(?!\\()",emStrong:{lDelim:/^(?:\*+(?:([punct_])|[^\s*]))|^_+(?:([punct*])|([^\s_]))/,rDelimAst:/^(?:[^_*\\]|\\.)*?\_\_(?:[^_*\\]|\\.)*?\*(?:[^_*\\]|\\.)*?(?=\_\_)|(?:[^*\\]|\\.)+(?=[^*])|[punct_](\*+)(?=[\s]|$)|(?:[^punct*_\s\\]|\\.)(\*+)(?=[punct_\s]|$)|[punct_\s](\*+)(?=[^punct*_\s])|[\s](\*+)(?=[punct_])|[punct_](\*+)(?=[punct_])|(?:[^punct*_\s\\]|\\.)(\*+)(?=[^punct*_\s])/,rDelimUnd:/^(?:[^_*\\]|\\.)*?\*\*(?:[^_*\\]|\\.)*?\_(?:[^_*\\]|\\.)*?(?=\*\*)|(?:[^_\\]|\\.)+(?=[^_])|[punct*](\_+)(?=[\s]|$)|(?:[^punct*_\s\\]|\\.)(\_+)(?=[punct*\s]|$)|[punct*\s](\_+)(?=[^punct*_\s])|[\s](\_+)(?=[punct*])|[punct*](\_+)(?=[punct*])/},code:/^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/,br:/^( {2,}|\\)\n(?!\s*$)/,del:Te,text:/^(`+|[^`])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\.5&&(r="x"+r.toString(16)),n+="&#"+r+";";return n}De._punctuation="!\"#$%&'()+\\-.,/:;<=>?@\\[\\]`^{|}~",De.punctuation=xe(De.punctuation).replace(/punctuation/g,De._punctuation).getRegex(),De.blockSkip=/\[[^\]]*?\]\([^\)]*?\)|`[^`]*?`|<[^>]*?>/g,De.escapedEmSt=/(?:^|[^\\])(?:\\\\)*\\[*_]/g,De._comment=xe(Fe._comment).replace("(?:--\x3e|$)","--\x3e").getRegex(),De.emStrong.lDelim=xe(De.emStrong.lDelim).replace(/punct/g,De._punctuation).getRegex(),De.emStrong.rDelimAst=xe(De.emStrong.rDelimAst,"g").replace(/punct/g,De._punctuation).getRegex(),De.emStrong.rDelimUnd=xe(De.emStrong.rDelimUnd,"g").replace(/punct/g,De._punctuation).getRegex(),De._escapes=/\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/g,De._scheme=/[a-zA-Z][a-zA-Z0-9+.-]{1,31}/,De._email=/[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+(@)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(?![-_])/,De.autolink=xe(De.autolink).replace("scheme",De._scheme).replace("email",De._email).getRegex(),De._attribute=/\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/,De.tag=xe(De.tag).replace("comment",De._comment).replace("attribute",De._attribute).getRegex(),De._label=/(?:\[(?:\\.|[^\[\]\\])*\]|\\.|`[^`]*`|[^\[\]\\`])*?/,De._href=/<(?:\\.|[^\n<>\\])+>|[^\s\x00-\x1f]*/,De._title=/"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/,De.link=xe(De.link).replace("label",De._label).replace("href",De._href).replace("title",De._title).getRegex(),De.reflink=xe(De.reflink).replace("label",De._label).replace("ref",Fe._label).getRegex(),De.nolink=xe(De.nolink).replace("ref",Fe._label).getRegex(),De.reflinkSearch=xe(De.reflinkSearch,"g").replace("reflink",De.reflink).replace("nolink",De.nolink).getRegex(),De.normal=Ce({},De),De.pedantic=Ce({},De.normal,{strong:{start:/^__|\*\*/,middle:/^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,endAst:/\*\*(?!\*)/g,endUnd:/__(?!_)/g},em:{start:/^_|\*/,middle:/^()\*(?=\S)([\s\S]*?\S)\*(?!\*)|^_(?=\S)([\s\S]*?\S)_(?!_)/,endAst:/\*(?!\*)/g,endUnd:/_(?!_)/g},link:xe(/^!?\[(label)\]\((.*?)\)/).replace("label",De._label).getRegex(),reflink:xe(/^!?\[(label)\]\s*\[([^\]]*)\]/).replace("label",De._label).getRegex()}),De.gfm=Ce({},De.normal,{escape:xe(De.escape).replace("])","~|])").getRegex(),_extended_email:/[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/,url:/^((?:ftp|https?):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/,_backpedal:/(?:[^?!.,:;*_'"~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_'"~)]+(?!$))+/,del:/^(~~?)(?=[^\s~])([\s\S]*?[^\s~])\1(?=[^~]|$)/,text:/^([`~]+|[^`~])(?:(?= {2,}\n)|(?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)|[\s\S]*?(?:(?=[\\t+" ".repeat(r.length)));e;)if(!(this.options.extensions&&this.options.extensions.block&&this.options.extensions.block.some((n=>!!(r=n.call({lexer:this},e,t))&&(e=e.substring(r.raw.length),t.push(r),!0)))))if(r=this.tokenizer.space(e))e=e.substring(r.raw.length),1===r.raw.length&&t.length>0?t[t.length-1].raw+="\n":t.push(r);else if(r=this.tokenizer.code(e))e=e.substring(r.raw.length),n=t[t.length-1],!n||"paragraph"!==n.type&&"text"!==n.type?t.push(r):(n.raw+="\n"+r.raw,n.text+="\n"+r.text,this.inlineQueue[this.inlineQueue.length-1].src=n.text);else if(r=this.tokenizer.fences(e))e=e.substring(r.raw.length),t.push(r);else if(r=this.tokenizer.heading(e))e=e.substring(r.raw.length),t.push(r);else if(r=this.tokenizer.hr(e))e=e.substring(r.raw.length),t.push(r);else if(r=this.tokenizer.blockquote(e))e=e.substring(r.raw.length),t.push(r);else if(r=this.tokenizer.list(e))e=e.substring(r.raw.length),t.push(r);else if(r=this.tokenizer.html(e))e=e.substring(r.raw.length),t.push(r);else if(r=this.tokenizer.def(e))e=e.substring(r.raw.length),n=t[t.length-1],!n||"paragraph"!==n.type&&"text"!==n.type?this.tokens.links[r.tag]||(this.tokens.links[r.tag]={href:r.href,title:r.title}):(n.raw+="\n"+r.raw,n.text+="\n"+r.raw,this.inlineQueue[this.inlineQueue.length-1].src=n.text);else if(r=this.tokenizer.table(e))e=e.substring(r.raw.length),t.push(r);else if(r=this.tokenizer.lheading(e))e=e.substring(r.raw.length),t.push(r);else{if(o=e,this.options.extensions&&this.options.extensions.startBlock){let t=1/0;const r=e.slice(1);let n;this.options.extensions.startBlock.forEach((function(e){n=e.call({lexer:this},r),"number"==typeof n&&n>=0&&(t=Math.min(t,n))})),t<1/0&&t>=0&&(o=e.substring(0,t+1))}if(this.state.top&&(r=this.tokenizer.paragraph(o)))n=t[t.length-1],a&&"paragraph"===n.type?(n.raw+="\n"+r.raw,n.text+="\n"+r.text,this.inlineQueue.pop(),this.inlineQueue[this.inlineQueue.length-1].src=n.text):t.push(r),a=o.length!==e.length,e=e.substring(r.raw.length);else if(r=this.tokenizer.text(e))e=e.substring(r.raw.length),n=t[t.length-1],n&&"text"===n.type?(n.raw+="\n"+r.raw,n.text+="\n"+r.text,this.inlineQueue.pop(),this.inlineQueue[this.inlineQueue.length-1].src=n.text):t.push(r);else if(e){const t="Infinite loop on byte: "+e.charCodeAt(0);if(this.options.silent){console.error(t);break}throw new Error(t)}}return this.state.top=!0,t}inline(e,t=[]){return this.inlineQueue.push({src:e,tokens:t}),t}inlineTokens(e,t=[]){let r,n,o,a,i,s,l=e;if(this.tokens.links){const e=Object.keys(this.tokens.links);if(e.length>0)for(;null!=(a=this.tokenizer.rules.inline.reflinkSearch.exec(l));)e.includes(a[0].slice(a[0].lastIndexOf("[")+1,-1))&&(l=l.slice(0,a.index)+"["+Pe("a",a[0].length-2)+"]"+l.slice(this.tokenizer.rules.inline.reflinkSearch.lastIndex))}for(;null!=(a=this.tokenizer.rules.inline.blockSkip.exec(l));)l=l.slice(0,a.index)+"["+Pe("a",a[0].length-2)+"]"+l.slice(this.tokenizer.rules.inline.blockSkip.lastIndex);for(;null!=(a=this.tokenizer.rules.inline.escapedEmSt.exec(l));)l=l.slice(0,a.index+a[0].length-2)+"++"+l.slice(this.tokenizer.rules.inline.escapedEmSt.lastIndex),this.tokenizer.rules.inline.escapedEmSt.lastIndex--;for(;e;)if(i||(s=""),i=!1,!(this.options.extensions&&this.options.extensions.inline&&this.options.extensions.inline.some((n=>!!(r=n.call({lexer:this},e,t))&&(e=e.substring(r.raw.length),t.push(r),!0)))))if(r=this.tokenizer.escape(e))e=e.substring(r.raw.length),t.push(r);else if(r=this.tokenizer.tag(e))e=e.substring(r.raw.length),n=t[t.length-1],n&&"text"===r.type&&"text"===n.type?(n.raw+=r.raw,n.text+=r.text):t.push(r);else if(r=this.tokenizer.link(e))e=e.substring(r.raw.length),t.push(r);else if(r=this.tokenizer.reflink(e,this.tokens.links))e=e.substring(r.raw.length),n=t[t.length-1],n&&"text"===r.type&&"text"===n.type?(n.raw+=r.raw,n.text+=r.text):t.push(r);else if(r=this.tokenizer.emStrong(e,l,s))e=e.substring(r.raw.length),t.push(r);else if(r=this.tokenizer.codespan(e))e=e.substring(r.raw.length),t.push(r);else if(r=this.tokenizer.br(e))e=e.substring(r.raw.length),t.push(r);else if(r=this.tokenizer.del(e))e=e.substring(r.raw.length),t.push(r);else if(r=this.tokenizer.autolink(e,Ne))e=e.substring(r.raw.length),t.push(r);else if(this.state.inLink||!(r=this.tokenizer.url(e,Ne))){if(o=e,this.options.extensions&&this.options.extensions.startInline){let t=1/0;const r=e.slice(1);let n;this.options.extensions.startInline.forEach((function(e){n=e.call({lexer:this},r),"number"==typeof n&&n>=0&&(t=Math.min(t,n))})),t<1/0&&t>=0&&(o=e.substring(0,t+1))}if(r=this.tokenizer.inlineText(o,Be))e=e.substring(r.raw.length),"_"!==r.raw.slice(-1)&&(s=r.raw.slice(-1)),i=!0,n=t[t.length-1],n&&"text"===n.type?(n.raw+=r.raw,n.text+=r.text):t.push(r);else if(e){const t="Infinite loop on byte: "+e.charCodeAt(0);if(this.options.silent){console.error(t);break}throw new Error(t)}}else e=e.substring(r.raw.length),t.push(r);return t}}class Ue{constructor(e){this.options=e||ce}code(e,t,r){const n=(t||"").match(/\S*/)[0];if(this.options.highlight){const t=this.options.highlight(e,n);null!=t&&t!==e&&(r=!0,e=t)}return e=e.replace(/\n$/,"")+"\n",n?'
    '+(r?e:ye(e,!0))+"
    \n":"
    "+(r?e:ye(e,!0))+"
    \n"}blockquote(e){return`
    \n${e}
    \n`}html(e){return e}heading(e,t,r,n){if(this.options.headerIds){return`${e}\n`}return`${e}\n`}hr(){return this.options.xhtml?"
    \n":"
    \n"}list(e,t,r){const n=t?"ol":"ul";return"<"+n+(t&&1!==r?' start="'+r+'"':"")+">\n"+e+"\n"}listitem(e){return`
  • ${e}
  • \n`}checkbox(e){return" "}paragraph(e){return`

    ${e}

    \n`}table(e,t){return t&&(t=`${t}`),"\n\n"+e+"\n"+t+"
    \n"}tablerow(e){return`\n${e}\n`}tablecell(e,t){const r=t.header?"th":"td";return(t.align?`<${r} align="${t.align}">`:`<${r}>`)+e+`\n`}strong(e){return`${e}`}em(e){return`${e}`}codespan(e){return`${e}`}br(){return this.options.xhtml?"
    ":"
    "}del(e){return`${e}`}link(e,t,r){if(null===(e=ke(this.options.sanitize,this.options.baseUrl,e)))return r;let n='
    ",n}image(e,t,r){if(null===(e=ke(this.options.sanitize,this.options.baseUrl,e)))return r;let n=`${r}":">",n}text(e){return e}}class ze{strong(e){return e}em(e){return e}codespan(e){return e}del(e){return e}html(e){return e}text(e){return e}link(e,t,r){return""+r}image(e,t,r){return""+r}br(){return""}}class Me{constructor(){this.seen={}}serialize(e){return e.toLowerCase().trim().replace(/<[!\/a-z].*?>/gi,"").replace(/[\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&()*+,./:;<=>?@[\]^`{|}~]/g,"").replace(/\s/g,"-")}getNextSafeSlug(e,t){let r=e,n=0;if(this.seen.hasOwnProperty(r)){n=this.seen[e];do{n++,r=e+"-"+n}while(this.seen.hasOwnProperty(r))}return t||(this.seen[e]=n,this.seen[r]=0),r}slug(e,t={}){const r=this.serialize(e);return this.getNextSafeSlug(r,t.dryrun)}}class He{constructor(e){this.options=e||ce,this.options.renderer=this.options.renderer||new Ue,this.renderer=this.options.renderer,this.renderer.options=this.options,this.textRenderer=new ze,this.slugger=new Me}static parse(e,t){return new He(t).parse(e)}static parseInline(e,t){return new He(t).parseInline(e)}parse(e,t=!0){let r,n,o,a,i,s,l,c,p,d,u,h,f,m,y,g,v,b,x,w="";const $=e.length;for(r=0;r<$;r++)if(d=e[r],this.options.extensions&&this.options.extensions.renderers&&this.options.extensions.renderers[d.type]&&(x=this.options.extensions.renderers[d.type].call({parser:this},d),!1!==x||!["space","hr","heading","code","table","blockquote","list","html","paragraph","text"].includes(d.type)))w+=x||"";else switch(d.type){case"space":continue;case"hr":w+=this.renderer.hr();continue;case"heading":w+=this.renderer.heading(this.parseInline(d.tokens),d.depth,ve(this.parseInline(d.tokens,this.textRenderer)),this.slugger);continue;case"code":w+=this.renderer.code(d.text,d.lang,d.escaped);continue;case"table":for(c="",l="",a=d.header.length,n=0;n0&&"paragraph"===y.tokens[0].type?(y.tokens[0].text=b+" "+y.tokens[0].text,y.tokens[0].tokens&&y.tokens[0].tokens.length>0&&"text"===y.tokens[0].tokens[0].type&&(y.tokens[0].tokens[0].text=b+" "+y.tokens[0].tokens[0].text)):y.tokens.unshift({type:"text",text:b}):m+=b),m+=this.parse(y.tokens,f),p+=this.renderer.listitem(m,v,g);w+=this.renderer.list(p,u,h);continue;case"html":w+=this.renderer.html(d.text);continue;case"paragraph":w+=this.renderer.paragraph(this.parseInline(d.tokens));continue;case"text":for(p=d.tokens?this.parseInline(d.tokens):d.text;r+1<$&&"text"===e[r+1].type;)d=e[++r],p+="\n"+(d.tokens?this.parseInline(d.tokens):d.text);w+=t?this.renderer.paragraph(p):p;continue;default:{const e='Token with "'+d.type+'" type was not found.';if(this.options.silent)return void console.error(e);throw new Error(e)}}return w}parseInline(e,t){t=t||this.renderer;let r,n,o,a="";const i=e.length;for(r=0;r{n(e.text,e.lang,(function(t,r){if(t)return a(t);null!=r&&r!==e.text&&(e.text=r,e.escaped=!0),i--,0===i&&a()}))}),0))})),void(0===i&&a())}function n(e){if(e.message+="\nPlease report this to https://github.com/markedjs/marked.",t.silent)return"

    An error occurred:

    "+ye(e.message+"",!0)+"
    ";throw e}try{const r=qe.lex(e,t);if(t.walkTokens){if(t.async)return Promise.all(We.walkTokens(r,t.walkTokens)).then((()=>He.parse(r,t))).catch(n);We.walkTokens(r,t.walkTokens)}return He.parse(r,t)}catch(e){n(e)}}We.options=We.setOptions=function(e){var t;return Ce(We.defaults,e),t=We.defaults,ce=t,We},We.getDefaults=le,We.defaults=ce,We.use=function(...e){const t=We.defaults.extensions||{renderers:{},childTokens:{}};e.forEach((e=>{const r=Ce({},e);if(r.async=We.defaults.async||r.async,e.extensions&&(e.extensions.forEach((e=>{if(!e.name)throw new Error("extension name required");if(e.renderer){const r=t.renderers[e.name];t.renderers[e.name]=r?function(...t){let n=e.renderer.apply(this,t);return!1===n&&(n=r.apply(this,t)),n}:e.renderer}if(e.tokenizer){if(!e.level||"block"!==e.level&&"inline"!==e.level)throw new Error("extension level must be 'block' or 'inline'");t[e.level]?t[e.level].unshift(e.tokenizer):t[e.level]=[e.tokenizer],e.start&&("block"===e.level?t.startBlock?t.startBlock.push(e.start):t.startBlock=[e.start]:"inline"===e.level&&(t.startInline?t.startInline.push(e.start):t.startInline=[e.start]))}e.childTokens&&(t.childTokens[e.name]=e.childTokens)})),r.extensions=t),e.renderer){const t=We.defaults.renderer||new Ue;for(const r in e.renderer){const n=t[r];t[r]=(...o)=>{let a=e.renderer[r].apply(t,o);return!1===a&&(a=n.apply(t,o)),a}}r.renderer=t}if(e.tokenizer){const t=We.defaults.tokenizer||new Le;for(const r in e.tokenizer){const n=t[r];t[r]=(...o)=>{let a=e.tokenizer[r].apply(t,o);return!1===a&&(a=n.apply(t,o)),a}}r.tokenizer=t}if(e.walkTokens){const t=We.defaults.walkTokens;r.walkTokens=function(r){let n=[];return n.push(e.walkTokens.call(this,r)),t&&(n=n.concat(t.call(this,r))),n}}We.setOptions(r)}))},We.walkTokens=function(e,t){let r=[];for(const n of e)switch(r=r.concat(t.call(We,n)),n.type){case"table":for(const e of n.header)r=r.concat(We.walkTokens(e.tokens,t));for(const e of n.rows)for(const n of e)r=r.concat(We.walkTokens(n.tokens,t));break;case"list":r=r.concat(We.walkTokens(n.items,t));break;default:We.defaults.extensions&&We.defaults.extensions.childTokens&&We.defaults.extensions.childTokens[n.type]?We.defaults.extensions.childTokens[n.type].forEach((function(e){r=r.concat(We.walkTokens(n[e],t))})):n.tokens&&(r=r.concat(We.walkTokens(n.tokens,t)))}return r},We.parseInline=function(e,t){if(null==e)throw new Error("marked.parseInline(): input parameter is undefined or null");if("string"!=typeof e)throw new Error("marked.parseInline(): input parameter is of type "+Object.prototype.toString.call(e)+", string expected");_e(t=Ce({},We.defaults,t||{}));try{const r=qe.lexInline(e,t);return t.walkTokens&&We.walkTokens(r,t.walkTokens),He.parseInline(r,t)}catch(e){if(e.message+="\nPlease report this to https://github.com/markedjs/marked.",t.silent)return"

    An error occurred:

    "+ye(e.message+"",!0)+"
    ";throw e}},We.Parser=He,We.parser=He.parse,We.Renderer=Ue,We.TextRenderer=ze,We.Lexer=qe,We.lexer=qe.lex,We.Tokenizer=Le,We.Slugger=Me,We.parse=We;We.options,We.setOptions,We.use,We.walkTokens,We.parseInline,He.parse,qe.lex;var Ve=r(660),Ge=r.n(Ve);r(251),r(358),r(46),r(503),r(277),r(874),r(366),r(57),r(16);const Ke=c` - .hover-bg:hover{ - background: var(--bg3); - } - ::selection { - background: var(--selection-bg); - color: var(--selection-fg); - } - .regular-font{ - font-family:var(--font-regular); - } - .mono-font { - font-family:var(--font-mono); - } - .title { - font-size: calc(var(--font-size-small) + 18px); - font-weight: normal - } - .sub-title{ font-size: 20px;} - .req-res-title { - font-family: var(--font-regular); - font-size: calc(var(--font-size-small) + 4px); - font-weight:bold; - margin-bottom:8px; - text-align:left; - } - .tiny-title { - font-size:calc(var(--font-size-small) + 1px); - font-weight:bold; - } - .regular-font-size { font-size: var(--font-size-regular); } - .small-font-size { font-size: var(--font-size-small); } - .upper { text-transform: uppercase; } - .primary-text{ color: var(--primary-color); } - .bold-text { font-weight:bold; } - .gray-text { color: var(--light-fg); } - .red-text {color: var(--red)} - .blue-text {color: var(--blue)} - .multiline { - overflow: scroll; - max-height: var(--resp-area-height, 400px); - color: var(--fg3); - } - .method-fg.put { color: var(--orange); } - .method-fg.post { color: var(--green); } - .method-fg.get { color: var(--blue); } - .method-fg.delete { color: var(--red); } - .method-fg.options, - .method-fg.head, - .method-fg.patch { - color: var(--yellow); - } - - h1{ font-family:var(--font-regular); font-size:28px; padding-top: 10px; letter-spacing:normal; font-weight:normal; } - h2{ font-family:var(--font-regular); font-size:24px; padding-top: 10px; letter-spacing:normal; font-weight:normal; } - h3{ font-family:var(--font-regular); font-size:18px; padding-top: 10px; letter-spacing:normal; font-weight:normal; } - h4{ font-family:var(--font-regular); font-size:16px; padding-top: 10px; letter-spacing:normal; font-weight:normal; } - h5{ font-family:var(--font-regular); font-size:14px; padding-top: 10px; letter-spacing:normal; font-weight:normal; } - h6{ font-family:var(--font-regular); font-size:14px; padding-top: 10px; letter-spacing:normal; font-weight:normal; } - - h1,h2,h3,h4,h5,h5{ - margin-block-end: 0.2em; - } - p { margin-block-start: 0.5em; } - a { color: var(--blue); cursor:pointer; } - a.inactive-link { - color:var(--fg); - text-decoration: none; - cursor:text; - } - - code, - pre { - margin: 0px; - font-family: var(--font-mono); - font-size: calc(var(--font-size-mono) - 1px); - } - - .m-markdown, - .m-markdown-small { - display:block; - } - - .m-markdown p, - .m-markdown span { - font-size: var(--font-size-regular); - line-height:calc(var(--font-size-regular) + 8px); - } - .m-markdown li { - font-size: var(--font-size-regular); - line-height:calc(var(--font-size-regular) + 10px); - } - - .m-markdown-small p, - .m-markdown-small span, - .m-markdown-small li { - font-size: var(--font-size-small); - line-height: calc(var(--font-size-small) + 6px); - } - .m-markdown-small li { - line-height: calc(var(--font-size-small) + 8px); - } - - .m-markdown p:not(:first-child) { - margin-block-start: 24px; - } - - .m-markdown-small p:not(:first-child) { - margin-block-start: 12px; - } - .m-markdown-small p:first-child { - margin-block-start: 0; - } - - .m-markdown p, - .m-markdown-small p { - margin-block-end: 0 - } - - .m-markdown code span { - font-size:var(--font-size-mono); - } - - .m-markdown-small code, - .m-markdown code { - padding: 1px 6px; - border-radius: 2px; - color: var(--inline-code-fg); - background-color: var(--bg3); - font-size: calc(var(--font-size-mono)); - line-height: 1.2; - } - - .m-markdown-small code { - font-size: calc(var(--font-size-mono) - 1px); - } - - .m-markdown-small pre, - .m-markdown pre { - white-space: pre-wrap; - overflow-x: auto; - line-height: normal; - border-radius: 2px; - border: 1px solid var(--code-border-color); - } - - .m-markdown pre { - padding: 12px; - background-color: var(--code-bg); - color:var(--code-fg); - } - - .m-markdown-small pre { - margin-top: 4px; - padding: 2px 4px; - background-color: var(--bg3); - color: var(--fg2); - } - - .m-markdown-small pre code, - .m-markdown pre code { - border:none; - padding:0; - } - - .m-markdown pre code { - color: var(--code-fg); - background-color: var(--code-bg); - background-color: transparent; - } - - .m-markdown-small pre code { - color: var(--fg2); - background-color: var(--bg3); - } - - .m-markdown ul, - .m-markdown ol { - padding-inline-start: 30px; - } - - .m-markdown-small ul, - .m-markdown-small ol { - padding-inline-start: 20px; - } - - .m-markdown-small a, - .m-markdown a { - color:var(--blue); - } - - .m-markdown-small img, - .m-markdown img { - max-width: 100%; - } - - /* Markdown table */ - - .m-markdown-small table, - .m-markdown table { - border-spacing: 0; - margin: 10px 0; - border-collapse: separate; - border: 1px solid var(--border-color); - border-radius: var(--border-radius); - font-size: calc(var(--font-size-small) + 1px); - line-height: calc(var(--font-size-small) + 4px); - max-width: 100%; - } - - .m-markdown-small table { - font-size: var(--font-size-small); - line-height: calc(var(--font-size-small) + 2px); - margin: 8px 0; - } - - .m-markdown-small td, - .m-markdown-small th, - .m-markdown td, - .m-markdown th { - vertical-align: top; - border-top: 1px solid var(--border-color); - line-height: calc(var(--font-size-small) + 4px); - } - - .m-markdown-small tr:first-child th, - .m-markdown tr:first-child th { - border-top: 0 none; - } - - .m-markdown th, - .m-markdown td { - padding: 10px 12px; - } - - .m-markdown-small th, - .m-markdown-small td { - padding: 8px 8px; - } - - .m-markdown th, - .m-markdown-small th { - font-weight: 600; - background-color: var(--bg2); - vertical-align: middle; - } - - .m-markdown-small table code { - font-size: calc(var(--font-size-mono) - 2px); - } - - .m-markdown table code { - font-size: calc(var(--font-size-mono) - 1px); - } - - .m-markdown blockquote, - .m-markdown-small blockquote { - margin-inline-start: 0; - margin-inline-end: 0; - border-left: 3px solid var(--border-color); - padding: 6px 0 6px 6px; - } - .m-markdown hr{ - border: 1px solid var(--border-color); - } -`,Je=c` -/* Button */ -.m-btn { - border-radius: var(--border-radius); - font-weight: 600; - display: inline-block; - padding: 6px 16px; - font-size: var(--font-size-small); - outline: 0; - line-height: 1; - text-align: center; - white-space: nowrap; - border: 2px solid var(--primary-color); - background-color:transparent; - transition: background-color 0.2s; - user-select: none; - cursor: pointer; - box-shadow: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24); -} -.m-btn.primary { - background-color: var(--primary-color); - color: var(--primary-color-invert); -} -.m-btn.thin-border { border-width: 1px; } -.m-btn.large { padding:8px 14px; } -.m-btn.small { padding:5px 12px; } -.m-btn.tiny { padding:5px 6px; } -.m-btn.circle { border-radius: 50%; } -.m-btn:hover { - background-color: var(--primary-color); - color: var(--primary-color-invert); -} -.m-btn.nav { border: 2px solid var(--nav-accent-color); } -.m-btn.nav:hover { - background-color: var(--nav-accent-color); -} -.m-btn:disabled{ - background-color: var(--bg3); - color: var(--fg3); - border-color: var(--fg3); - cursor: not-allowed; - opacity: 0.4; -} -.toolbar-btn{ - cursor: pointer; - padding: 4px; - margin:0 2px; - font-size: var(--font-size-small); - min-width: 50px; - color: var(--primary-color-invert); - border-radius: 2px; - border: none; - background-color: var(--primary-color); -} - -input, textarea, select, button, pre { - color:var(--fg); - outline: none; - background-color: var(--input-bg); - border: 1px solid var(--border-color); - border-radius: var(--border-radius); -} -button { - font-family: var(--font-regular); -} - -/* Form Inputs */ -pre, -select, -textarea, -input[type="file"], -input[type="text"], -input[type="password"] { - font-family: var(--font-mono); - font-weight: 400; - font-size: var(--font-size-small); - transition: border .2s; - padding: 6px 5px; -} - -select { - font-family: var(--font-regular); - padding: 5px 30px 5px 5px; - background-image: url("data:image/svg+xml;charset=utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2212%22%20height%3D%2212%22%3E%3Cpath%20d%3D%22M10.3%203.3L6%207.6%201.7%203.3A1%201%200%2000.3%204.7l5%205a1%201%200%20001.4%200l5-5a1%201%200%2010-1.4-1.4z%22%20fill%3D%22%23777777%22%2F%3E%3C%2Fsvg%3E"); - background-position: calc(100% - 5px) center; - background-repeat: no-repeat; - background-size: 10px; - -webkit-appearance: none; - -moz-appearance: none; - appearance: none; - cursor: pointer; -} - -select:hover { - border-color: var(--primary-color); -} - -textarea::placeholder, -input[type="text"]::placeholder, -input[type="password"]::placeholder { - color: var(--placeholder-color); - opacity:1; -} - - -input[type="file"]{ - font-family: var(--font-regular); - padding:2px; - cursor:pointer; - border: 1px solid var(--primary-color); - min-height: calc(var(--font-size-small) + 18px); -} - -input[type="file"]::-webkit-file-upload-button { - font-family: var(--font-regular); - font-size: var(--font-size-small); - outline: none; - cursor:pointer; - padding: 3px 8px; - border: 1px solid var(--primary-color); - background-color: var(--primary-color); - color: var(--primary-color-invert); - border-radius: var(--border-radius);; - -webkit-appearance: none; -} - -pre, -textarea { - scrollbar-width: thin; - scrollbar-color: var(--border-color) var(--input-bg); -} - -pre::-webkit-scrollbar, -textarea::-webkit-scrollbar { - width: 8px; - height: 8px; -} - -pre::-webkit-scrollbar-track, -textarea::-webkit-scrollbar-track { - background:var(--input-bg); -} - -pre::-webkit-scrollbar-thumb, -textarea::-webkit-scrollbar-thumb { - border-radius: 2px; - background-color: var(--border-color); -} - -.link { - font-size:var(--font-size-small); - text-decoration: underline; - color:var(--blue); - font-family:var(--font-mono); - margin-bottom:2px; -} - -/* Toggle Body */ -input[type="checkbox"] { - appearance: none; - display: inline-block; - background-color: var(--light-bg); - border: 1px solid var(--light-bg); - border-radius: 9px; - cursor: pointer; - height: 18px; - position: relative; - transition: border .25s .15s, box-shadow .25s .3s, padding .25s; - min-width: 36px; - width: 36px; - vertical-align: top; -} -/* Toggle Thumb */ -input[type="checkbox"]:after { - position: absolute; - background-color: var(--bg); - border: 1px solid var(--light-bg); - border-radius: 8px; - content: ''; - top: 0px; - left: 0px; - right: 16px; - display: block; - height: 16px; - transition: border .25s .15s, left .25s .1s, right .15s .175s; -} - -/* Toggle Body - Checked */ -input[type="checkbox"]:checked { - background-color: var(--green); - border-color: var(--green); -} -/* Toggle Thumb - Checked*/ -input[type="checkbox"]:checked:after { - border: 1px solid var(--green); - left: 16px; - right: 1px; - transition: border .25s, left .15s .25s, right .25s .175s; -}`,Ye=c` -.row, .col{ - display:flex; -} -.row { - align-items:center; - flex-direction: row; -} -.col { - align-items:stretch; - flex-direction: column; -} -`,Ze=c` -.m-table { - border-spacing: 0; - border-collapse: separate; - border: 1px solid var(--light-border-color); - border-radius: var(--border-radius); - margin: 0; - max-width: 100%; - direction: ltr; -} -.m-table tr:first-child td, -.m-table tr:first-child th { - border-top: 0 none; -} -.m-table td, -.m-table th { - font-size: var(--font-size-small); - line-height: calc(var(--font-size-small) + 4px); - padding: 4px 5px 4px; - vertical-align: top; -} - -.m-table.padded-12 td, -.m-table.padded-12 th { - padding: 12px; -} - -.m-table td:not([align]), -.m-table th:not([align]) { - text-align: left; -} - -.m-table th { - color: var(--fg2); - font-size: var(--font-size-small); - line-height: calc(var(--font-size-small) + 18px); - font-weight: 600; - letter-spacing: normal; - background-color: var(--bg2); - vertical-align: bottom; - border-bottom: 1px solid var(--light-border-color); -} - -.m-table > tbody > tr > td, -.m-table > tr > td { - border-top: 1px solid var(--light-border-color); - text-overflow: ellipsis; - overflow: hidden; -} -.table-title { - font-size:var(--font-size-small); - font-weight:bold; - vertical-align: middle; - margin: 12px 0 4px 0; -} -`,Qe=c` -.only-large-screen { display:none; } -.endpoint-head .path{ - display: flex; - font-family:var(--font-mono); - font-size: var(--font-size-small); - align-items: center; - overflow-wrap: break-word; - word-break: break-all; -} - -.endpoint-head .descr { - font-size: var(--font-size-small); - color:var(--light-fg); - font-weight:400; - align-items: center; - overflow-wrap: break-word; - word-break: break-all; - display:none; -} - -.m-endpoint.expanded{margin-bottom:16px; } -.m-endpoint > .endpoint-head{ - border-width:1px 1px 1px 5px; - border-style:solid; - border-color:transparent; - border-top-color:var(--light-border-color); - display:flex; - padding:6px 16px; - align-items: center; - cursor: pointer; -} -.m-endpoint > .endpoint-head.put:hover, -.m-endpoint > .endpoint-head.put.expanded{ - border-color:var(--orange); - background-color:var(--light-orange); -} -.m-endpoint > .endpoint-head.post:hover, -.m-endpoint > .endpoint-head.post.expanded { - border-color:var(--green); - background-color:var(--light-green); -} -.m-endpoint > .endpoint-head.get:hover, -.m-endpoint > .endpoint-head.get.expanded { - border-color:var(--blue); - background-color:var(--light-blue); -} -.m-endpoint > .endpoint-head.delete:hover, -.m-endpoint > .endpoint-head.delete.expanded { - border-color:var(--red); - background-color:var(--light-red); -} - -.m-endpoint > .endpoint-head.head:hover, -.m-endpoint > .endpoint-head.head.expanded, -.m-endpoint > .endpoint-head.patch:hover, -.m-endpoint > .endpoint-head.patch.expanded, -.m-endpoint > .endpoint-head.options:hover, -.m-endpoint > .endpoint-head.options.expanded { - border-color:var(--yellow); - background-color:var(--light-yellow); -} - -.m-endpoint > .endpoint-head.deprecated:hover, -.m-endpoint > .endpoint-head.deprecated.expanded { - border-color:var(--border-color); - filter:opacity(0.6); -} - -.m-endpoint .endpoint-body { - flex-wrap:wrap; - padding:16px 0px 0 0px; - border-width:0px 1px 1px 5px; - border-style:solid; - box-shadow: 0px 4px 3px -3px rgba(0, 0, 0, 0.15); -} -.m-endpoint .endpoint-body.delete{ border-color:var(--red); } -.m-endpoint .endpoint-body.put{ border-color:var(--orange); } -.m-endpoint .endpoint-body.post{border-color:var(--green);} -.m-endpoint .endpoint-body.get{ border-color:var(--blue); } -.m-endpoint .endpoint-body.head, -.m-endpoint .endpoint-body.patch, -.m-endpoint .endpoint-body.options { - border-color:var(--yellow); -} - -.m-endpoint .endpoint-body.deprecated{ - border-color:var(--border-color); - filter:opacity(0.6); -} - -.endpoint-head .deprecated{ - color: var(--light-fg); - filter:opacity(0.6); -} - -.summary{ - padding:8px 8px; -} -.summary .title{ - font-size:calc(var(--font-size-regular) + 2px); - margin-bottom: 6px; - word-break: break-all; -} - -.endpoint-head .method{ - padding:2px 5px; - vertical-align: middle; - font-size:var(--font-size-small); - height: calc(var(--font-size-small) + 16px); - line-height: calc(var(--font-size-small) + 8px); - width: 60px; - border-radius: 2px; - display:inline-block; - text-align: center; - font-weight: bold; - text-transform:uppercase; - margin-right:5px; -} -.endpoint-head .method.delete{ border: 2px solid var(--red);} -.endpoint-head .method.put{ border: 2px solid var(--orange); } -.endpoint-head .method.post{ border: 2px solid var(--green); } -.endpoint-head .method.get{ border: 2px solid var(--blue); } -.endpoint-head .method.get.deprecated{ border: 2px solid var(--border-color); } -.endpoint-head .method.head, -.endpoint-head .method.patch, -.endpoint-head .method.options { - border: 2px solid var(--yellow); -} - -.req-resp-container { - display: flex; - margin-top:16px; - align-items: stretch; - flex-wrap: wrap; - flex-direction: column; - border-top:1px solid var(--light-border-color); -} - -.view-mode-request, -api-response.view-mode { - flex:1; - min-height:100px; - padding:16px 8px; - overflow:hidden; -} -.view-mode-request { - border-width:0 0 1px 0; - border-style:dashed; -} - -.head .view-mode-request, -.patch .view-mode-request, -.options .view-mode-request { - border-color:var(--yellow); -} -.put .view-mode-request { - border-color:var(--orange); -} -.post .view-mode-request { - border-color:var(--green); -} -.get .view-mode-request { - border-color:var(--blue); -} -.delete .view-mode-request { - border-color:var(--red); -} - -@media only screen and (min-width: 1024px) { - .only-large-screen { display:block; } - .endpoint-head .path{ - font-size: var(--font-size-regular); - } - .endpoint-head .descr{ - display: flex; - } - .endpoint-head .m-markdown-small, - .descr .m-markdown-small{ - display:block; - } - .req-resp-container{ - flex-direction: var(--layout, row); - flex-wrap: nowrap; - } - api-response.view-mode { - padding:16px; - } - .view-mode-request.row-layout { - border-width:0 1px 0 0; - padding:16px; - } - .summary{ - padding:8px 16px; - } -} -`,Xe=c` -code[class*="language-"], -pre[class*="language-"] { - text-align: left; - white-space: pre; - word-spacing: normal; - word-break: normal; - word-wrap: normal; - line-height: 1.5; - tab-size: 2; - - -webkit-hyphens: none; - -moz-hyphens: none; - -ms-hyphens: none; - hyphens: none; -} - -/* Code blocks */ -pre[class*="language-"] { - padding: 1em; - margin: .5em 0; - overflow: auto; -} - -/* Inline code */ -:not(pre) > code[class*="language-"] { - white-space: normal; -} - -.token.comment, -.token.block-comment, -.token.prolog, -.token.doctype, -.token.cdata { - color: var(--light-fg) -} - -.token.punctuation { - color: var(--fg); -} - -.token.tag, -.token.attr-name, -.token.namespace, -.token.deleted { - color:var(--pink); -} - -.token.function-name { - color: var(--blue); -} - -.token.boolean, -.token.number, -.token.function { - color: var(--red); -} - -.token.property, -.token.class-name, -.token.constant, -.token.symbol { - color: var(--code-property-color); -} - -.token.selector, -.token.important, -.token.atrule, -.token.keyword, -.token.builtin { - color: var(--code-keyword-color); -} - -.token.string, -.token.char, -.token.attr-value, -.token.regex, -.token.variable { - color: var(--green); -} - -.token.operator, -.token.entity, -.token.url { - color: var(--code-operator-color); -} - -.token.important, -.token.bold { - font-weight: bold; -} -.token.italic { - font-style: italic; -} - -.token.entity { - cursor: help; -} - -.token.inserted { - color: green; -} -`,et=c` -.tab-panel { - border: none; -} -.tab-buttons { - height:30px; - padding: 4px 4px 0 4px; - border-bottom: 1px solid var(--light-border-color) ; - align-items: stretch; - overflow-y: hidden; - overflow-x: auto; - scrollbar-width: thin; -} -.tab-buttons::-webkit-scrollbar { - height: 1px; - background-color: var(--border-color); -} -.tab-btn { - border: none; - border-bottom: 3px solid transparent; - color: var(--light-fg); - background-color: transparent; - white-space: nowrap; - cursor:pointer; - outline:none; - font-family:var(--font-regular); - font-size:var(--font-size-small); - margin-right:16px; - padding:1px; -} -.tab-btn.active { - border-bottom: 3px solid var(--primary-color); - font-weight:bold; - color:var(--primary-color); -} - -.tab-btn:hover { - color:var(--primary-color); -} -.tab-content { - margin:-1px 0 0 0; - position:relative; - min-height: 50px; -} -`,tt=c` -.nav-bar-info:focus-visible, -.nav-bar-tag:focus-visible, -.nav-bar-path:focus-visible { - outline: 1px solid; - box-shadow: none; - outline-offset: -4px; -} -.nav-bar-expand-all:focus-visible, -.nav-bar-collapse-all:focus-visible, -.nav-bar-tag-icon:focus-visible { - outline: 1px solid; - box-shadow: none; - outline-offset: 2px; -} -.nav-bar { - width:0; - height:100%; - overflow: hidden; - color:var(--nav-text-color); - background-color: var(--nav-bg-color); - background-blend-mode: multiply; - line-height: calc(var(--font-size-small) + 4px); - display:none; - position:relative; - flex-direction:column; - flex-wrap:nowrap; - word-break:break-word; -} -::slotted([slot=nav-logo]){ - padding:16px 16px 0 16px; -} -.nav-scroll { - overflow-x: hidden; - overflow-y: auto; - overflow-y: overlay; - scrollbar-width: thin; - scrollbar-color: var(--nav-hover-bg-color) transparent; -} - -.nav-bar-tag { - display: flex; - align-items: center; - justify-content: space-between; - flex-direction: row; -} -.nav-bar.read .nav-bar-tag-icon { - display:none; -} -.nav-bar-paths-under-tag { - overflow:hidden; - transition: max-height .2s ease-out, visibility .3s; -} -.collapsed .nav-bar-paths-under-tag { - visibility: hidden; -} - -.nav-bar-expand-all { - transform: rotate(90deg); - cursor:pointer; - margin-right:10px; -} -.nav-bar-collapse-all { - transform: rotate(270deg); - cursor:pointer; -} -.nav-bar-expand-all:hover, .nav-bar-collapse-all:hover { - color: var(--primary-color); -} - -.nav-bar-tag-icon { - color: var(--nav-text-color); - font-size: 20px; -} -.nav-bar-tag-icon:hover { - color:var(--nav-hover-text-color); -} -.nav-bar.focused .nav-bar-tag-and-paths.collapsed .nav-bar-tag-icon::after { - content: '⌵'; - width:16px; - height:16px; - text-align: center; - display: inline-block; - transform: rotate(-90deg); - transition: transform 0.2s ease-out 0s; -} -.nav-bar.focused .nav-bar-tag-and-paths.expanded .nav-bar-tag-icon::after { - content: '⌵'; - width:16px; - height:16px; - text-align: center; - display: inline-block; - transition: transform 0.2s ease-out 0s; -} -.nav-scroll::-webkit-scrollbar { - width: var(--scroll-bar-width, 8px); -} -.nav-scroll::-webkit-scrollbar-track { - background:transparent; -} -.nav-scroll::-webkit-scrollbar-thumb { - background-color: var(--nav-hover-bg-color); -} - -.nav-bar-tag { - font-size: var(--font-size-regular); - color: var(--nav-accent-color); - border-left:4px solid transparent; - font-weight:bold; - padding: 15px 15px 15px 10px; - text-transform: capitalize; -} - -.nav-bar-components, -.nav-bar-h1, -.nav-bar-h2, -.nav-bar-info, -.nav-bar-tag, -.nav-bar-path { - display:flex; - cursor: pointer; - width: 100%; - border: none; - border-radius:4px; - color: var(--nav-text-color); - background: transparent; - border-left:4px solid transparent; -} - -.nav-bar-h1, -.nav-bar-h2, -.nav-bar-path { - font-size: calc(var(--font-size-small) + 1px); - padding: var(--nav-item-padding); -} -.nav-bar-path.small-font { - font-size: var(--font-size-small); -} - -.nav-bar-info { - font-size: var(--font-size-regular); - padding: 16px 10px; - font-weight:bold; -} -.nav-bar-section { - display: flex; - flex-direction: row; - justify-content: space-between; - font-size: var(--font-size-small); - color: var(--nav-text-color); - padding: var(--nav-item-padding); - font-weight:bold; -} -.nav-bar-section.operations { - cursor:pointer; -} -.nav-bar-section.operations:hover { - color:var(--nav-hover-text-color); - background-color:var(--nav-hover-bg-color); -} - -.nav-bar-section:first-child { - display: none; -} -.nav-bar-h2 {margin-left:12px;} - -.nav-bar-h1.left-bar.active, -.nav-bar-h2.left-bar.active, -.nav-bar-info.left-bar.active, -.nav-bar-tag.left-bar.active, -.nav-bar-path.left-bar.active, -.nav-bar-section.left-bar.operations.active { - border-left:4px solid var(--nav-accent-color); - color:var(--nav-hover-text-color); -} - -.nav-bar-h1.colored-block.active, -.nav-bar-h2.colored-block.active, -.nav-bar-info.colored-block.active, -.nav-bar-tag.colored-block.active, -.nav-bar-path.colored-block.active, -.nav-bar-section.colored-block.operations.active { - background-color: var(--nav-accent-color); - color: var(--nav-accent-text-color); - border-radius: 0; -} - -.nav-bar-h1:hover, -.nav-bar-h2:hover, -.nav-bar-info:hover, -.nav-bar-tag:hover, -.nav-bar-path:hover { - color:var(--nav-hover-text-color); - background-color:var(--nav-hover-bg-color); -} -`,rt=c` -#api-info { - font-size: calc(var(--font-size-regular) - 1px); - margin-top: 8px; - margin-left: -15px; -} - -#api-info span:before { - content: "|"; - display: inline-block; - opacity: 0.5; - width: 15px; - text-align: center; -} -#api-info span:first-child:before { - content: ""; - width: 0px; -} -`,nt=c` - -`;const ot=/[\s#:?&={}]/g,at="_rapidoc_api_key";function it(e){return new Promise((t=>setTimeout(t,e)))}function st(e,t){const r=t.target,n=document.createElement("textarea");n.value=e,n.style.position="fixed",document.body.appendChild(n),n.focus(),n.select();try{document.execCommand("copy"),r.innerText="Copied",setTimeout((()=>{r.innerText="Copy"}),5e3)}catch(e){console.error("Unable to copy",e)}document.body.removeChild(n)}function lt(e,t,r="includes"){if("includes"===r){return`${t.method} ${t.path} ${t.summary||t.description||""} ${t.operationId||""}`.toLowerCase().includes(e.toLowerCase())}return new RegExp(e,"i").test(`${t.method} ${t.path}`)}function ct(e,t=new Set){return e?(Object.keys(e).forEach((r=>{var n;if(t.add(r),e[r].properties)ct(e[r].properties,t);else if(null!==(n=e[r].items)&&void 0!==n&&n.properties){var o;ct(null===(o=e[r].items)||void 0===o?void 0:o.properties,t)}})),t):t}function pt(e,t){if(e){const r=document.createElement("a");document.body.appendChild(r),r.style="display: none",r.href=e,r.download=t,r.click(),r.remove()}}function dt(e){if(e){const t=document.createElement("a");document.body.appendChild(t),t.style="display: none",t.href=e,t.target="_blank",t.click(),t.remove()}}function ut(e){return e&&e.t&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}var ht=function(e){return e&&e.Math==Math&&e},ft=ht("object"==typeof globalThis&&globalThis)||ht("object"==typeof window&&window)||ht("object"==typeof self&&self)||ht("object"==typeof ft&&ft)||function(){return this}()||Function("return this")(),mt=function(e){try{return!!e()}catch(e){return!0}},yt=!mt((function(){var e=function(){}.bind();return"function"!=typeof e||e.hasOwnProperty("prototype")})),gt=yt,vt=Function.prototype,bt=vt.apply,xt=vt.call,wt="object"==typeof Reflect&&Reflect.apply||(gt?xt.bind(bt):function(){return xt.apply(bt,arguments)}),$t=yt,kt=Function.prototype,St=kt.bind,At=kt.call,Et=$t&&St.bind(At,At),Ot=$t?function(e){return e&&Et(e)}:function(e){return e&&function(){return At.apply(e,arguments)}},Tt=function(e){return"function"==typeof e},Ct={},jt=!mt((function(){return 7!=Object.defineProperty({},1,{get:function(){return 7}})[1]})),It=yt,_t=Function.prototype.call,Pt=It?_t.bind(_t):function(){return _t.apply(_t,arguments)},Rt={},Lt={}.propertyIsEnumerable,Ft=Object.getOwnPropertyDescriptor,Dt=Ft&&!Lt.call({1:2},1);Rt.f=Dt?function(e){var t=Ft(this,e);return!!t&&t.enumerable}:Lt;var Bt,Nt,qt=function(e,t){return{enumerable:!(1&e),configurable:!(2&e),writable:!(4&e),value:t}},Ut=Ot,zt=Ut({}.toString),Mt=Ut("".slice),Ht=function(e){return Mt(zt(e),8,-1)},Wt=Ot,Vt=mt,Gt=Ht,Kt=ft.Object,Jt=Wt("".split),Yt=Vt((function(){return!Kt("z").propertyIsEnumerable(0)}))?function(e){return"String"==Gt(e)?Jt(e,""):Kt(e)}:Kt,Zt=ft.TypeError,Qt=function(e){if(null==e)throw Zt("Can't call method on "+e);return e},Xt=Yt,er=Qt,tr=function(e){return Xt(er(e))},rr=Tt,nr=function(e){return"object"==typeof e?null!==e:rr(e)},or={},ar=or,ir=ft,sr=Tt,lr=function(e){return sr(e)?e:void 0},cr=function(e,t){return arguments.length<2?lr(ar[e])||lr(ir[e]):ar[e]&&ar[e][t]||ir[e]&&ir[e][t]},pr=Ot({}.isPrototypeOf),dr=cr("navigator","userAgent")||"",ur=ft,hr=dr,fr=ur.process,mr=ur.Deno,yr=fr&&fr.versions||mr&&mr.version,gr=yr&&yr.v8;gr&&(Nt=(Bt=gr.split("."))[0]>0&&Bt[0]<4?1:+(Bt[0]+Bt[1])),!Nt&&hr&&(!(Bt=hr.match(/Edge\/(\d+)/))||Bt[1]>=74)&&(Bt=hr.match(/Chrome\/(\d+)/))&&(Nt=+Bt[1]);var vr=Nt,br=vr,xr=mt,wr=!!Object.getOwnPropertySymbols&&!xr((function(){var e=Symbol();return!String(e)||!(Object(e)instanceof Symbol)||!Symbol.sham&&br&&br<41})),$r=wr&&!Symbol.sham&&"symbol"==typeof Symbol.iterator,kr=cr,Sr=Tt,Ar=pr,Er=$r,Or=ft.Object,Tr=Er?function(e){return"symbol"==typeof e}:function(e){var t=kr("Symbol");return Sr(t)&&Ar(t.prototype,Or(e))},Cr=ft.String,jr=function(e){try{return Cr(e)}catch(e){return"Object"}},Ir=Tt,_r=jr,Pr=ft.TypeError,Rr=function(e){if(Ir(e))return e;throw Pr(_r(e)+" is not a function")},Lr=Rr,Fr=function(e,t){var r=e[t];return null==r?void 0:Lr(r)},Dr=Pt,Br=Tt,Nr=nr,qr=ft.TypeError,Ur={exports:{}},zr=ft,Mr=Object.defineProperty,Hr=ft.i||function(e,t){try{Mr(zr,e,{value:t,configurable:!0,writable:!0})}catch(r){zr[e]=t}return t}("__core-js_shared__",{}),Wr=Hr;(Ur.exports=function(e,t){return Wr[e]||(Wr[e]=void 0!==t?t:{})})("versions",[]).push({version:"3.21.1",mode:"pure",copyright:"© 2014-2022 Denis Pushkarev (zloirock.ru)",license:"https://github.com/zloirock/core-js/blob/v3.21.1/LICENSE",source:"https://github.com/zloirock/core-js"});var Vr=Qt,Gr=ft.Object,Kr=function(e){return Gr(Vr(e))},Jr=Kr,Yr=Ot({}.hasOwnProperty),Zr=Object.hasOwn||function(e,t){return Yr(Jr(e),t)},Qr=Ot,Xr=0,en=Math.random(),tn=Qr(1..toString),rn=function(e){return"Symbol("+(void 0===e?"":e)+")_"+tn(++Xr+en,36)},nn=ft,on=Ur.exports,an=Zr,sn=rn,ln=wr,cn=$r,pn=on("wks"),dn=nn.Symbol,un=dn&&dn.for,hn=cn?dn:dn&&dn.withoutSetter||sn,fn=function(e){if(!an(pn,e)||!ln&&"string"!=typeof pn[e]){var t="Symbol."+e;ln&&an(dn,e)?pn[e]=dn[e]:pn[e]=cn&&un?un(t):hn(t)}return pn[e]},mn=Pt,yn=nr,gn=Tr,vn=Fr,bn=fn,xn=ft.TypeError,wn=bn("toPrimitive"),$n=function(e,t){if(!yn(e)||gn(e))return e;var r,n=vn(e,wn);if(n){if(void 0===t&&(t="default"),r=mn(n,e,t),!yn(r)||gn(r))return r;throw xn("Can't convert object to primitive value")}return void 0===t&&(t="number"),function(e,t){var r,n;if("string"===t&&Br(r=e.toString)&&!Nr(n=Dr(r,e)))return n;if(Br(r=e.valueOf)&&!Nr(n=Dr(r,e)))return n;if("string"!==t&&Br(r=e.toString)&&!Nr(n=Dr(r,e)))return n;throw qr("Can't convert object to primitive value")}(e,t)},kn=Tr,Sn=function(e){var t=$n(e,"string");return kn(t)?t:t+""},An=nr,En=ft.document,On=An(En)&&An(En.createElement),Tn=function(e){return On?En.createElement(e):{}},Cn=Tn,jn=!jt&&!mt((function(){return 7!=Object.defineProperty(Cn("div"),"a",{get:function(){return 7}}).a})),In=jt,_n=Pt,Pn=Rt,Rn=qt,Ln=tr,Fn=Sn,Dn=Zr,Bn=jn,Nn=Object.getOwnPropertyDescriptor;Ct.f=In?Nn:function(e,t){if(e=Ln(e),t=Fn(t),Bn)try{return Nn(e,t)}catch(e){}if(Dn(e,t))return Rn(!_n(Pn.f,e,t),e[t])};var qn=mt,Un=Tt,zn=/#|\.prototype\./,Mn=function(e,t){var r=Wn[Hn(e)];return r==Gn||r!=Vn&&(Un(t)?qn(t):!!t)},Hn=Mn.normalize=function(e){return String(e).replace(zn,".").toLowerCase()},Wn=Mn.data={},Vn=Mn.NATIVE="N",Gn=Mn.POLYFILL="P",Kn=Mn,Jn=Rr,Yn=yt,Zn=Ot(Ot.bind),Qn=function(e,t){return Jn(e),void 0===t?e:Yn?Zn(e,t):function(){return e.apply(t,arguments)}},Xn={},eo=jt&&mt((function(){return 42!=Object.defineProperty((function(){}),"prototype",{value:42,writable:!1}).prototype})),to=ft,ro=nr,no=to.String,oo=to.TypeError,ao=function(e){if(ro(e))return e;throw oo(no(e)+" is not an object")},io=jt,so=jn,lo=eo,co=ao,po=Sn,uo=ft.TypeError,ho=Object.defineProperty,fo=Object.getOwnPropertyDescriptor;Xn.f=io?lo?function(e,t,r){if(co(e),t=po(t),co(r),"function"==typeof e&&"prototype"===t&&"value"in r&&"writable"in r&&!r.writable){var n=fo(e,t);n&&n.writable&&(e[t]=r.value,r={configurable:"configurable"in r?r.configurable:n.configurable,enumerable:"enumerable"in r?r.enumerable:n.enumerable,writable:!1})}return ho(e,t,r)}:ho:function(e,t,r){if(co(e),t=po(t),co(r),so)try{return ho(e,t,r)}catch(e){}if("get"in r||"set"in r)throw uo("Accessors not supported");return"value"in r&&(e[t]=r.value),e};var mo=Xn,yo=qt,go=jt?function(e,t,r){return mo.f(e,t,yo(1,r))}:function(e,t,r){return e[t]=r,e},vo=ft,bo=wt,xo=Ot,wo=Tt,$o=Ct.f,ko=Kn,So=or,Ao=Qn,Eo=go,Oo=Zr,To=function(e){var t=function(r,n,o){if(this instanceof t){switch(arguments.length){case 0:return new e;case 1:return new e(r);case 2:return new e(r,n)}return new e(r,n,o)}return bo(e,this,arguments)};return t.prototype=e.prototype,t},Co=function(e,t){var r,n,o,a,i,s,l,c,p=e.target,d=e.global,u=e.stat,h=e.proto,f=d?vo:u?vo[p]:(vo[p]||{}).prototype,m=d?So:So[p]||Eo(So,p,{})[p],y=m.prototype;for(o in t)r=!ko(d?o:p+(u?".":"#")+o,e.forced)&&f&&Oo(f,o),i=m[o],r&&(s=e.noTargetGet?(c=$o(f,o))&&c.value:f[o]),a=r&&s?s:t[o],r&&typeof i==typeof a||(l=e.bind&&r?Ao(a,vo):e.wrap&&r?To(a):h&&wo(a)?xo(a):a,(e.sham||a&&a.sham||i&&i.sham)&&Eo(l,"sham",!0),Eo(m,o,l),h&&(Oo(So,n=p+"Prototype")||Eo(So,n,{}),Eo(So[n],o,a),e.real&&y&&!y[o]&&Eo(y,o,a)))},jo=Math.ceil,Io=Math.floor,_o=function(e){var t=+e;return t!=t||0===t?0:(t>0?Io:jo)(t)},Po=_o,Ro=Math.max,Lo=Math.min,Fo=function(e,t){var r=Po(e);return r<0?Ro(r+t,0):Lo(r,t)},Do=_o,Bo=Math.min,No=function(e){return e>0?Bo(Do(e),9007199254740991):0},qo=No,Uo=function(e){return qo(e.length)},zo=tr,Mo=Fo,Ho=Uo,Wo=function(e){return function(t,r,n){var o,a=zo(t),i=Ho(a),s=Mo(n,i);if(e&&r!=r){for(;i>s;)if((o=a[s++])!=o)return!0}else for(;i>s;s++)if((e||s in a)&&a[s]===r)return e||s||0;return!e&&-1}},Vo={includes:Wo(!0),indexOf:Wo(!1)},Go={},Ko=Zr,Jo=tr,Yo=Vo.indexOf,Zo=Go,Qo=Ot([].push),Xo=function(e,t){var r,n=Jo(e),o=0,a=[];for(r in n)!Ko(Zo,r)&&Ko(n,r)&&Qo(a,r);for(;t.length>o;)Ko(n,r=t[o++])&&(~Yo(a,r)||Qo(a,r));return a},ea=["constructor","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","toLocaleString","toString","valueOf"],ta=Xo,ra=ea,na=Object.keys||function(e){return ta(e,ra)},oa=Kr,aa=na;Co({target:"Object",stat:!0,forced:mt((function(){aa(1)}))},{keys:function(e){return aa(oa(e))}});var ia=or.Object.keys;const sa=ut({exports:{}}.exports=ia);var la=Ht,ca=Array.isArray||function(e){return"Array"==la(e)},pa={};pa[fn("toStringTag")]="z";var da="[object z]"===String(pa),ua=ft,ha=da,fa=Tt,ma=Ht,ya=fn("toStringTag"),ga=ua.Object,va="Arguments"==ma(function(){return arguments}()),ba=ha?ma:function(e){var t,r,n;return void 0===e?"Undefined":null===e?"Null":"string"==typeof(r=function(e,t){try{return e[t]}catch(e){}}(t=ga(e),ya))?r:va?ma(t):"Object"==(n=ma(t))&&fa(t.callee)?"Arguments":n},xa=ba,wa=ft.String,$a=function(e){if("Symbol"===xa(e))throw TypeError("Cannot convert a Symbol value to a string");return wa(e)},ka={},Sa=jt,Aa=eo,Ea=Xn,Oa=ao,Ta=tr,Ca=na;ka.f=Sa&&!Aa?Object.defineProperties:function(e,t){Oa(e);for(var r,n=Ta(t),o=Ca(t),a=o.length,i=0;a>i;)Ea.f(e,r=o[i++],n[r]);return e};var ja,Ia=cr("document","documentElement"),_a=Ur.exports,Pa=rn,Ra=_a("keys"),La=function(e){return Ra[e]||(Ra[e]=Pa(e))},Fa=ao,Da=ka,Ba=ea,Na=Go,qa=Ia,Ua=Tn,za=La("IE_PROTO"),Ma=function(){},Ha=function(e){return"