9 Commits

Author SHA1 Message Date
GW_MC
6f5596dc69 Enforce deny unwrap_used
All checks were successful
Test / test-frontend (pull_request) Successful in 26s
Test / lint-frontend (pull_request) Successful in 28s
Test / frontend-build (pull_request) Successful in 32s
Verify / verify-generated-database-code (pull_request) Successful in 1m7s
Verify / verify-generated-agent-code (pull_request) Successful in 1m10s
Verify / verify-openapi-spec (pull_request) Successful in 1m9s
Verify / verify-frontend-api-client (pull_request) Successful in 7s
Test / test-crates (pull_request) Successful in 54s
Test / lint-crates (pull_request) Successful in 1m10s
2025-12-28 19:07:17 +08:00
GW_MC
96e7f36731 feat: integrate AgentService into app service and enhance configuration handling
All checks were successful
Test / test-frontend (pull_request) Successful in 25s
Test / lint-frontend (pull_request) Successful in 28s
Test / frontend-build (pull_request) Successful in 32s
Verify / verify-generated-database-code (pull_request) Successful in 1m7s
Verify / verify-generated-agent-code (pull_request) Successful in 1m11s
Verify / verify-openapi-spec (pull_request) Successful in 1m13s
Verify / verify-frontend-api-client (pull_request) Successful in 8s
Test / test-crates (pull_request) Successful in 55s
Test / lint-crates (pull_request) Successful in 1m9s
2025-12-28 18:35:53 +08:00
GW_MC
410328a2af refactor app service 2025-12-28 18:28:28 +08:00
GW_MC
9f122566d0 feat: add agent settings configuration and update agent client service 2025-12-28 18:08:55 +08:00
GW_MC
c65dc3af47 feat: Basic agent-client service
Some checks failed
Test / test-frontend (pull_request) Successful in 27s
Test / frontend-build (pull_request) Successful in 33s
Verify / verify-openapi-spec (pull_request) Successful in 7s
Verify / verify-generated-agent-code (pull_request) Successful in 1m7s
Verify / verify-generated-database-code (pull_request) Successful in 2m14s
Verify / verify-frontend-api-client (pull_request) Successful in 6s
Test / lint-crates (pull_request) Failing after 1m28s
Test / test-crates (pull_request) Successful in 2m40s
Test / lint-frontend (pull_request) Successful in 29s
2025-12-28 17:53:27 +08:00
GW_MC
6f395ed1ae rename workflows jobs 2025-12-28 16:42:12 +08:00
GW_MC
e6e85564e7 fix: incorrect pnpm cache
All checks were successful
Test / test-frontend (pull_request) Successful in 1m17s
Test / lint-frontend (pull_request) Successful in 1m19s
Test / frontend-build (pull_request) Successful in 1m55s
Verify / verify-openapi-spec (pull_request) Successful in 31s
Verify / verify-generated-agent-code (pull_request) Successful in 2m54s
Verify / verify-generated-code (pull_request) Successful in 3m57s
Verify / verify-frontend-api-client (pull_request) Successful in 8s
Test / lint (pull_request) Successful in 1m25s
Test / test (pull_request) Successful in 3m26s
2025-12-28 16:29:31 +08:00
GW_MC
c7a090f78a fix: frontend deps not installed 2025-12-28 16:23:10 +08:00
GW_MC
8cc2775fe4 feat: auto format generated code, and ignore clippy lint in agent-client 2025-12-28 16:22:41 +08:00
30 changed files with 6807 additions and 7207 deletions

View File

@@ -12,11 +12,8 @@ on:
jobs: jobs:
# setup is now handled by a composite action used by downstream jobs to keep
# the workflow DRY. The composite action performs checkout, cache restore and
# toolchain setup.
test: test-crates:
needs: frontend-build needs: frontend-build
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
@@ -39,7 +36,7 @@ jobs:
- name: Run tests - name: Run tests
run: cargo test --all-features run: cargo test --all-features
lint: lint-crates:
needs: frontend-build needs: frontend-build
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
@@ -83,7 +80,7 @@ jobs:
with: with:
node-version: 22 node-version: 22
cache: 'pnpm' cache: 'pnpm'
cache-dependency-path: apps/frontend/pnpm-lock.yaml cache-dependency-path: pnpm-lock.yaml
- name: Install frontend dependencies - name: Install frontend dependencies
run: | run: |
@@ -114,7 +111,7 @@ jobs:
with: with:
node-version: 22 node-version: 22
cache: 'pnpm' cache: 'pnpm'
cache-dependency-path: apps/frontend/pnpm-lock.yaml cache-dependency-path: pnpm-lock.yaml
- name: Install frontend dependencies - name: Install frontend dependencies
run: | run: |
@@ -142,12 +139,12 @@ jobs:
with: with:
node-version: 22 node-version: 22
cache: 'pnpm' cache: 'pnpm'
cache-dependency-path: apps/frontend/pnpm-lock.yaml cache-dependency-path: pnpm-lock.yaml
- name: Install frontend dependencies - name: Install frontend dependencies
run: | run: |
cd apps/frontend cd apps/frontend
pnpm install pnpm install --frozen-lockfile
- name: Build frontend - name: Build frontend
run: | run: |

View File

@@ -11,11 +11,8 @@ on:
jobs: jobs:
# setup is now handled by a composite action used by downstream jobs to keep
# the workflow DRY. The composite action performs checkout, cache restore and
# toolchain setup.
verify-generated-code: verify-generated-database-code:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout repository - name: Checkout repository
@@ -213,7 +210,7 @@ jobs:
with: with:
node-version: 22 node-version: 22
cache: 'pnpm' cache: 'pnpm'
cache-dependency-path: apps/frontend/pnpm-lock.yaml cache-dependency-path: pnpm-lock.yaml
- name: Install frontend dependencies - name: Install frontend dependencies
if: steps.check_swagger_changes.outputs.changed == 'true' if: steps.check_swagger_changes.outputs.changed == 'true'

82
Cargo.lock generated
View File

@@ -542,7 +542,7 @@ dependencies = [
"num-traits", "num-traits",
"serde", "serde",
"wasm-bindgen", "wasm-bindgen",
"windows-link", "windows-link 0.2.1",
] ]
[[package]] [[package]]
@@ -1709,9 +1709,11 @@ dependencies = [
"percent-encoding", "percent-encoding",
"pin-project-lite", "pin-project-lite",
"socket2", "socket2",
"system-configuration",
"tokio", "tokio",
"tower-service", "tower-service",
"tracing", "tracing",
"windows-registry",
] ]
[[package]] [[package]]
@@ -2468,7 +2470,7 @@ dependencies = [
"libc", "libc",
"redox_syscall", "redox_syscall",
"smallvec", "smallvec",
"windows-link", "windows-link 0.2.1",
] ]
[[package]] [[package]]
@@ -3073,8 +3075,10 @@ checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147"
dependencies = [ dependencies = [
"base64 0.22.1", "base64 0.22.1",
"bytes", "bytes",
"encoding_rs",
"futures-core", "futures-core",
"futures-util", "futures-util",
"h2",
"http", "http",
"http-body", "http-body",
"http-body-util", "http-body-util",
@@ -3084,6 +3088,7 @@ dependencies = [
"hyper-util", "hyper-util",
"js-sys", "js-sys",
"log", "log",
"mime",
"mime_guess", "mime_guess",
"native-tls", "native-tls",
"percent-encoding", "percent-encoding",
@@ -4193,6 +4198,27 @@ dependencies = [
"syn 2.0.111", "syn 2.0.111",
] ]
[[package]]
name = "system-configuration"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b"
dependencies = [
"bitflags",
"core-foundation 0.9.4",
"system-configuration-sys",
]
[[package]]
name = "system-configuration-sys"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4"
dependencies = [
"core-foundation-sys",
"libc",
]
[[package]] [[package]]
name = "tap" name = "tap"
version = "1.0.1" version = "1.0.1"
@@ -5008,9 +5034,9 @@ checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb"
dependencies = [ dependencies = [
"windows-implement", "windows-implement",
"windows-interface", "windows-interface",
"windows-link", "windows-link 0.2.1",
"windows-result", "windows-result 0.4.1",
"windows-strings", "windows-strings 0.5.1",
] ]
[[package]] [[package]]
@@ -5035,19 +5061,54 @@ dependencies = [
"syn 2.0.111", "syn 2.0.111",
] ]
[[package]]
name = "windows-link"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a"
[[package]] [[package]]
name = "windows-link" name = "windows-link"
version = "0.2.1" version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
[[package]]
name = "windows-registry"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b8a9ed28765efc97bbc954883f4e6796c33a06546ebafacbabee9696967499e"
dependencies = [
"windows-link 0.1.3",
"windows-result 0.3.4",
"windows-strings 0.4.2",
]
[[package]]
name = "windows-result"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6"
dependencies = [
"windows-link 0.1.3",
]
[[package]] [[package]]
name = "windows-result" name = "windows-result"
version = "0.4.1" version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5"
dependencies = [ dependencies = [
"windows-link", "windows-link 0.2.1",
]
[[package]]
name = "windows-strings"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57"
dependencies = [
"windows-link 0.1.3",
] ]
[[package]] [[package]]
@@ -5056,7 +5117,7 @@ version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091"
dependencies = [ dependencies = [
"windows-link", "windows-link 0.2.1",
] ]
[[package]] [[package]]
@@ -5101,7 +5162,7 @@ version = "0.61.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
dependencies = [ dependencies = [
"windows-link", "windows-link 0.2.1",
] ]
[[package]] [[package]]
@@ -5141,7 +5202,7 @@ version = "0.53.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3"
dependencies = [ dependencies = [
"windows-link", "windows-link 0.2.1",
"windows_aarch64_gnullvm 0.53.1", "windows_aarch64_gnullvm 0.53.1",
"windows_aarch64_msvc 0.53.1", "windows_aarch64_msvc 0.53.1",
"windows_i686_gnu 0.53.1", "windows_i686_gnu 0.53.1",
@@ -5367,6 +5428,7 @@ checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049"
name = "yet-another-nginx-proxy-manager" name = "yet-another-nginx-proxy-manager"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"agent_client",
"argon2", "argon2",
"async-trait", "async-trait",
"axum", "axum",
@@ -5380,9 +5442,11 @@ dependencies = [
"migration", "migration",
"mime_guess", "mime_guess",
"once_cell", "once_cell",
"reqwest",
"sea-orm", "sea-orm",
"serde", "serde",
"serde_json", "serde_json",
"tempfile",
"tokio", "tokio",
"tower", "tower",
"tower-http", "tower-http",

View File

@@ -6,6 +6,7 @@ edition = "2024"
[dependencies] [dependencies]
database = { path = "../../public/database" } database = { path = "../../public/database" }
migration = { path = "../../public/migration" } migration = { path = "../../public/migration" }
agent_client = { path = "../../public/agent-client" }
axum = { version = "0.8.7", features = ["form", "http1", "http2", "json", "matched-path", "original-uri", "query", "tokio", "tower-log", "tracing", "macros"] } axum = { version = "0.8.7", features = ["form", "http1", "http2", "json", "matched-path", "original-uri", "query", "tokio", "tower-log", "tracing", "macros"] }
axum-extra = { version = "0.12.2", features = ["cookie"] } axum-extra = { version = "0.12.2", features = ["cookie"] }
@@ -28,4 +29,10 @@ argon2 = { version = "0.5.3", features = ["std"] }
jsonwebtoken = { version = "10.2.0", features = ["rust_crypto"] } jsonwebtoken = { version = "10.2.0", features = ["rust_crypto"] }
uuid = { version = "1.19.0", features = ["v4", "serde", "fast-rng"] } uuid = { version = "1.19.0", features = ["v4", "serde", "fast-rng"] }
tower-http = { version = "0.6.8", features = ["cors"] } tower-http = { version = "0.6.8", features = ["cors"] }
reqwest = { version = "^0.12", features = ["json", "multipart", "stream"] }
[dev-dependencies]
tempfile = "3"
[lints.clippy]
unwrap_used = "deny"

View File

@@ -28,7 +28,7 @@ fn action(
_matches: &clap::ArgMatches, _matches: &clap::ArgMatches,
) -> std::pin::Pin<Box<dyn std::future::Future<Output = ()> + Send>> { ) -> std::pin::Pin<Box<dyn std::future::Future<Output = ()> + Send>> {
let output_path = _matches.get_one::<String>("output_path"); let output_path = _matches.get_one::<String>("output_path");
let output_path = output_path.unwrap().to_string(); let output_path = output_path.expect("output_path is required").to_string();
Box::pin(async move { Box::pin(async move {
tracing::subscriber::with_default(log::make_temporary_subscriber(), || { tracing::subscriber::with_default(log::make_temporary_subscriber(), || {

View File

@@ -11,15 +11,8 @@ use crate::{
cmd::CliCommand, cmd::CliCommand,
configs::{ProgramSettings, get_program_settings, logging::LoggingSettings}, configs::{ProgramSettings, get_program_settings, logging::LoggingSettings},
log, log,
routes::{self, AppService, AppState}, routes::{self, AppState},
services::{ services::get_app_service,
auth::{
authentication::{AuthenticationServiceImpl, strategies::password::PasswordStrategy},
user::UserServiceImpl,
},
server_state::ServerStateService,
settings::SettingsService,
},
tasks, tasks,
}; };
@@ -148,19 +141,7 @@ fn get_app_state(
AppState { AppState {
database_connection: db_connection.clone(), database_connection: db_connection.clone(),
config: Arc::new(settings.clone()), config: Arc::new(settings.clone()),
service: Arc::new(AppService { service: Arc::new(get_app_service(db_connection, settings)),
server_state: Arc::new(ServerStateService::new(db_connection.clone())),
settings: Arc::new(SettingsService::new(db_connection.clone())),
auth_state: routes::AuthState {
strategy: routes::AuthStrategy {
password: Arc::new(PasswordStrategy::new(db_connection.clone())),
},
authentication: Arc::new(AuthenticationServiceImpl::new(
settings.auth.jwt_secret.clone(),
)),
},
user: Arc::new(UserServiceImpl::new(db_connection.clone())),
}),
} }
} }

View File

@@ -1,3 +1,4 @@
pub mod agent;
pub mod auth; pub mod auth;
pub mod database; pub mod database;
pub mod logging; pub mod logging;
@@ -21,6 +22,7 @@ pub struct ProgramSettings {
pub database: database::DatabaseSettings, pub database: database::DatabaseSettings,
pub server: server::ServerSettings, pub server: server::ServerSettings,
pub auth: auth::AuthSettings, pub auth: auth::AuthSettings,
pub agent: agent::AgentSettings,
} }
impl FromConfig for ProgramSettings { impl FromConfig for ProgramSettings {
@@ -30,6 +32,7 @@ impl FromConfig for ProgramSettings {
database: database::DatabaseSettings::from_config(_config)?, database: database::DatabaseSettings::from_config(_config)?,
server: server::ServerSettings::from_config(_config)?, server: server::ServerSettings::from_config(_config)?,
auth: auth::AuthSettings::from_config(_config)?, auth: auth::AuthSettings::from_config(_config)?,
agent: agent::AgentSettings::from_config(_config)?,
}; };
config.validate()?; config.validate()?;
Ok(config) Ok(config)
@@ -50,6 +53,7 @@ impl FromConfig for ProgramSettings {
database: database::DatabaseSettings::mock(), database: database::DatabaseSettings::mock(),
server: server::ServerSettings::mock(), server: server::ServerSettings::mock(),
auth: auth::AuthSettings::mock(), auth: auth::AuthSettings::mock(),
agent: agent::AgentSettings::mock(),
} }
} }
} }

View File

@@ -0,0 +1,58 @@
use config::Config;
use tracing::error;
use crate::configs::key::AGENT_SOCK_PATH_KEY;
use super::FromConfig;
#[derive(Debug, Clone)]
pub struct AgentSettings {
pub socket_path: String,
}
impl FromConfig for AgentSettings {
fn from_config(_config: &Config) -> Result<Self, String> {
Ok(AgentSettings {
socket_path: _config.get_string(AGENT_SOCK_PATH_KEY).map_err(|err| {
format!(
"Failed to get {} from configuration. Err: {}",
AGENT_SOCK_PATH_KEY, err
)
})?,
})
}
fn validate(&self) -> Result<(), String> {
// ensure socket_path exists and is readable and writable
if !std::path::Path::new(&self.socket_path).exists() {
let msg = format!("Agent socket path '{}' does not exist", self.socket_path);
error!("{}", msg);
return Err(msg);
}
if std::path::Path::new(&self.socket_path)
.metadata()
.map(|meta| {
let permissions = meta.permissions();
// Check read and write permissions for the owner
!permissions.readonly()
})
.unwrap_or(false)
{
Ok(())
} else {
let msg = format!(
"Agent socket path '{}' is not readable/writable",
self.socket_path
);
error!("{}", msg);
Err(msg)
}
}
#[cfg(test)]
fn mock() -> Self {
AgentSettings {
socket_path: "/tmp/agent.sock".to_string(),
}
}
}

View File

@@ -14,3 +14,5 @@ pub(crate) const DATABASE_MIGRATE_ON_STARTUP_KEY: &str = "DATABASE.MIGRATION.MIG
pub(crate) const AUTH_JWT_SECRET_KEY: &str = "AUTH.JWT_SECRET"; pub(crate) const AUTH_JWT_SECRET_KEY: &str = "AUTH.JWT_SECRET";
pub(crate) const AUTH_DEFAULT_ADMIN_USERNAME_KEY: &str = "AUTH.DEFAULT_ADMIN_USERNAME"; pub(crate) const AUTH_DEFAULT_ADMIN_USERNAME_KEY: &str = "AUTH.DEFAULT_ADMIN_USERNAME";
pub(crate) const AUTH_DEFAULT_ADMIN_PASSWORD_KEY: &str = "AUTH.DEFAULT_ADMIN_PASSWORD"; pub(crate) const AUTH_DEFAULT_ADMIN_PASSWORD_KEY: &str = "AUTH.DEFAULT_ADMIN_PASSWORD";
//
pub(crate) const AGENT_SOCK_PATH_KEY: &str = "AGENT.SOCK.PATH";

View File

@@ -121,7 +121,7 @@ impl FromConfig for ServerSettings {
#[cfg(test)] #[cfg(test)]
fn mock() -> Self { fn mock() -> Self {
ServerSettings { ServerSettings {
address: "0.0.0.0".parse().unwrap(), address: "0.0.0.0".parse().expect("Failed to parse mock IP address"),
port: 8080, port: 8080,
serve_openapi: false, serve_openapi: false,
cors: CORSSettings { cors: CORSSettings {

View File

@@ -12,12 +12,8 @@ use crate::{
configs::{ProgramSettings, server::CORSSettings}, configs::{ProgramSettings, server::CORSSettings},
middlewares, middlewares,
services::{ services::{
auth::{ AppService, ServiceState,
authentication::{AuthenticationService, strategies::password::PasswordStrategy}, auth::authentication::{AuthenticationService, strategies::password::PasswordStrategy},
user::UserService,
},
server_state::ServerStateStore,
settings::SettingsStore,
}, },
}; };
@@ -28,8 +24,6 @@ pub struct AppState {
pub config: Arc<ProgramSettings>, pub config: Arc<ProgramSettings>,
} }
pub type ServiceState<T> = Arc<T>;
pub struct AuthStrategy { pub struct AuthStrategy {
pub password: ServiceState<PasswordStrategy>, pub password: ServiceState<PasswordStrategy>,
} }
@@ -39,13 +33,6 @@ pub struct AuthState {
pub authentication: ServiceState<dyn AuthenticationService>, pub authentication: ServiceState<dyn AuthenticationService>,
} }
pub struct AppService {
pub settings: ServiceState<dyn SettingsStore>,
pub auth_state: AuthState,
pub user: ServiceState<dyn UserService>,
pub server_state: ServiceState<dyn ServerStateStore>,
}
pub fn get_root_router( pub fn get_root_router(
state: impl Into<Arc<AppState>>, state: impl Into<Arc<AppState>>,
cors_settings: Arc<CORSSettings>, cors_settings: Arc<CORSSettings>,

View File

@@ -79,6 +79,7 @@ pub async fn get_health_info(
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use crate::configs::FromConfig; use crate::configs::FromConfig;
use crate::services::agent_client::AgentService;
use crate::{ use crate::{
routes::{AppState, api::health::state::HealthState}, routes::{AppState, api::health::state::HealthState},
services::{ services::{
@@ -94,6 +95,7 @@ mod test {
}; };
use super::*; use super::*;
use agent_client::apis::configuration::Configuration;
use axum::body::to_bytes; use axum::body::to_bytes;
use axum::{ use axum::{
Router, Router,
@@ -124,6 +126,7 @@ mod test {
}, },
user: Arc::new(UserServiceImpl::new(db.clone())), user: Arc::new(UserServiceImpl::new(db.clone())),
server_state: Arc::new(ServerStateService::new(db.clone())), server_state: Arc::new(ServerStateService::new(db.clone())),
agent_client: Arc::new(AgentService::new(Configuration::default())),
}), }),
}); });
@@ -135,13 +138,21 @@ mod test {
})); }));
let response = app let response = app
.oneshot(Request::builder().uri("/info").body(Body::empty()).unwrap()) .oneshot(
Request::builder()
.uri("/info")
.body(Body::empty())
.expect("Failed to build request"),
)
.await .await
.unwrap(); .unwrap();
assert_eq!(response.status(), StatusCode::OK); assert_eq!(response.status(), StatusCode::OK);
let body = to_bytes(response.into_body(), 1024 * 1024).await.unwrap(); // Set limit to 1 MB let body = to_bytes(response.into_body(), 1024 * 1024)
let health_info: HealthInfo = serde_json::from_slice(&body).unwrap(); .await
.expect("Failed to read response body"); // Set limit to 1 MB
let health_info: HealthInfo =
serde_json::from_slice(&body).expect("Failed to deserialize response body");
assert_eq!(health_info.status, STATUS_HEALTHY); assert_eq!(health_info.status, STATUS_HEALTHY);
assert_eq!(health_info.version, env!("CARGO_PKG_VERSION")); assert_eq!(health_info.version, env!("CARGO_PKG_VERSION"));
assert!(health_info.errors.is_none()); assert!(health_info.errors.is_none());

View File

@@ -1,3 +1,54 @@
pub mod agent_client;
pub mod auth; pub mod auth;
pub mod server_state; pub mod server_state;
pub mod settings; pub mod settings;
use std::sync::Arc;
use ::agent_client::apis::configuration::Configuration;
use crate::{
configs::ProgramSettings,
routes::{self, AuthState},
services::{
auth::{
authentication::{AuthenticationServiceImpl, strategies::password::PasswordStrategy},
user::{UserService, UserServiceImpl},
},
server_state::{ServerStateService, ServerStateStore},
settings::{SettingsService, SettingsStore},
},
};
pub type ServiceState<T> = Arc<T>;
pub struct AppService {
pub settings: ServiceState<dyn SettingsStore>,
pub auth_state: AuthState,
pub user: ServiceState<dyn UserService>,
pub server_state: ServiceState<dyn ServerStateStore>,
#[allow(dead_code)]
pub agent_client: ServiceState<agent_client::AgentService>,
}
pub fn get_app_service(
db_connection: &Arc<sea_orm::DatabaseConnection>,
settings: &ProgramSettings,
) -> AppService {
AppService {
server_state: Arc::new(ServerStateService::new(db_connection.clone())),
settings: Arc::new(SettingsService::new(db_connection.clone())),
auth_state: routes::AuthState {
strategy: routes::AuthStrategy {
password: Arc::new(PasswordStrategy::new(db_connection.clone())),
},
authentication: Arc::new(AuthenticationServiceImpl::new(
settings.auth.jwt_secret.clone(),
)),
},
user: Arc::new(UserServiceImpl::new(db_connection.clone())),
agent_client: Arc::new(agent_client::AgentService::new(Configuration::from(
settings.agent.clone(),
))),
}
}

View File

@@ -0,0 +1,114 @@
use std::sync::Arc;
use agent_client::apis::{ApiClient, configuration::Configuration};
use tracing::warn;
use crate::configs::agent::AgentSettings;
pub struct AgentService {
client: Arc<ApiClient>,
}
impl From<AgentSettings> for Configuration {
fn from(settings: AgentSettings) -> Self {
let mut config = Configuration::default();
let mut builder = reqwest::Client::builder();
let url = settings.socket_path;
if url.starts_with("unix://") {
builder = builder.unix_socket(url.to_string());
config.client = builder.build().expect("Failed to build reqwest client");
} else {
warn!("AgentSettings contains a non-unix socket path: {}", url);
config.base_path = url;
}
config
}
}
impl AgentService {
pub fn new(config: impl Into<Arc<Configuration>>) -> Self {
let client = ApiClient::new(config.into());
AgentService {
client: Arc::new(client),
}
}
#[allow(dead_code)]
pub fn get_client(&self) -> Arc<ApiClient> {
Arc::clone(&self.client)
}
}
#[cfg(test)]
mod tests {
use super::*;
use agent_client::{
apis::{Api, nginx_agent_api::StatusSuccess},
models::StatusResp,
};
use axum::{http::StatusCode, response::Json};
use std::time::Duration;
use tempfile::tempdir;
use tokio::time::sleep;
#[test]
fn test_agent_service_creation() {
let config = Configuration::default();
let service = AgentService::new(config);
let client = service.get_client();
assert!(Arc::ptr_eq(&client, &service.client));
}
#[tokio::test]
async fn test_agent_socket_support() {
// create temporary socket path
let dir = tempdir().expect("Failed to create temp dir");
let socket_path = dir.path().join("agent.sock");
// create axum app with a simple /status route
let app = axum::Router::new().route(
"/status",
axum::routing::get(|| async {
let result: (StatusCode, StatusResp) = (StatusCode::OK, StatusResp { ok: true });
(result.0, Json(result.1))
}),
);
// bind tokio unix listener and serve in background
let listener =
tokio::net::UnixListener::bind(&socket_path).expect("Failed to bind to unix socket");
let server_fut = axum::serve::serve(listener, app);
let _srv = tokio::spawn(async move {
let _ = server_fut.await;
});
// give server a moment to start
sleep(Duration::from_millis(50)).await;
let client: ApiClient = ApiClient::new(Arc::new(Configuration {
base_path: "http://localhost".to_string(),
client: reqwest::Client::builder()
.unix_socket(socket_path.clone())
.build()
.expect("Failed to build reqwest client"),
..Default::default()
}));
let res = client
.nginx_agent_api()
.status()
.await
.expect("Failed to get status");
let body = res.entity.expect("Response entity is missing");
assert!(res.status.is_success());
if let StatusSuccess::Status200(body) = body {
assert!(body.ok);
} else {
panic!("Unexpected response body");
}
}
}

View File

@@ -197,14 +197,17 @@ mod tests {
let (token, _) = service let (token, _) = service
.generate_jwt(user_id, 60) .generate_jwt(user_id, 60)
.await .await
.expect("generate jwt"); .expect("Failed to generate jwt");
let valid = service let valid = service
.is_valid_jwt(&token, None) .is_valid_jwt(&token, None)
.await .await
.expect("validate jwt"); .expect("Failed to validate jwt");
assert!(valid.is_some(), "Generated token should be valid"); assert!(valid.is_some(), "Generated token should be valid");
let claims = service.parse_jwt(&token).await.expect("parse jwt"); let claims = service
.parse_jwt(&token)
.await
.expect("Failed to parse jwt");
assert_eq!(claims.sub, user_id.to_string()); assert_eq!(claims.sub, user_id.to_string());
} }
@@ -213,10 +216,16 @@ mod tests {
let service = AuthenticationServiceImpl::new(Some("secret".to_string())); let service = AuthenticationServiceImpl::new(Some("secret".to_string()));
let user_id = Uuid::new_v4(); let user_id = Uuid::new_v4();
let (token, _) = service.generate_jwt(user_id, 60).await.unwrap(); let (token, _) = service
.generate_jwt(user_id, 60)
.await
.expect("Failed to generate jwt");
let other_sub = Uuid::new_v4().to_string(); let other_sub = Uuid::new_v4().to_string();
let valid = service.is_valid_jwt(&token, Some(other_sub)).await.unwrap(); let valid = service
.is_valid_jwt(&token, Some(other_sub))
.await
.expect("jwt is not valid");
assert!( assert!(
valid.is_none(), valid.is_none(),
"Token should be invalid for a different subject" "Token should be invalid for a different subject"
@@ -236,10 +245,19 @@ mod tests {
let service = AuthenticationServiceImpl::new(Some("secret".to_string())); let service = AuthenticationServiceImpl::new(Some("secret".to_string()));
let user_id = Uuid::new_v4(); let user_id = Uuid::new_v4();
let (token, _) = service.generate_jwt(user_id, 60).await.unwrap(); let (token, _) = service
let new_token = service.refresh_jwt(&token, 120).await.unwrap(); .generate_jwt(user_id, 60)
.await
.expect("Failed to generate jwt");
let new_token = service
.refresh_jwt(&token, 120)
.await
.expect("Failed to refresh jwt");
let claims = service.parse_jwt(&new_token).await.unwrap(); let claims = service
.parse_jwt(&new_token)
.await
.expect("Failed to parse refreshed jwt");
assert_eq!(claims.sub, user_id.to_string()); assert_eq!(claims.sub, user_id.to_string());
assert_eq!(claims.exp - claims.iat, 120); assert_eq!(claims.exp - claims.iat, 120);
} }
@@ -249,10 +267,16 @@ mod tests {
let service = AuthenticationServiceImpl::new(Some("secret".to_string())); let service = AuthenticationServiceImpl::new(Some("secret".to_string()));
let user_id = Uuid::new_v4(); let user_id = Uuid::new_v4();
let (token, claims) = service.generate_jwt(user_id, 1).await.unwrap(); let (token, claims) = service
.generate_jwt(user_id, 1)
.await
.expect("Failed to generate jwt");
sleep(Duration::from_secs(2)).await; sleep(Duration::from_secs(2)).await;
let valid = service.is_valid_jwt(&token, None).await.unwrap(); let valid = service
.is_valid_jwt(&token, None)
.await
.expect("Failed to validate jwt");
assert!( assert!(
valid.is_none(), valid.is_none(),
"Token should be expired and thus invalid. Current time: {:?}. Diff: {}", "Token should be expired and thus invalid. Current time: {:?}. Diff: {}",
@@ -266,9 +290,15 @@ mod tests {
let service = AuthenticationServiceImpl::new(Some("secret".to_string())); let service = AuthenticationServiceImpl::new(Some("secret".to_string()));
let user_id = Uuid::new_v4(); let user_id = Uuid::new_v4();
let (token, _) = service.generate_jwt(user_id, 1).await.unwrap(); let (token, _) = service
.generate_jwt(user_id, 1)
.await
.expect("Failed to generate jwt");
service.invalidate_jwt(&token).await.unwrap(); service
.invalidate_jwt(&token)
.await
.expect("Failed to invalidate jwt");
// ensure entry is present // ensure entry is present
{ {

View File

@@ -236,7 +236,7 @@ mod test {
"CorrectPassword".as_bytes(), "CorrectPassword".as_bytes(),
&SaltString::generate(&mut OsRng), &SaltString::generate(&mut OsRng),
) )
.unwrap() .expect("Failed to hash password")
.to_string(); .to_string();
let db = MockDatabase::new(sea_orm::DatabaseBackend::Sqlite) let db = MockDatabase::new(sea_orm::DatabaseBackend::Sqlite)
.append_query_results(vec![vec![user::Model { .append_query_results(vec![vec![user::Model {
@@ -281,7 +281,7 @@ mod test {
"CorrectPassword".as_bytes(), "CorrectPassword".as_bytes(),
&SaltString::generate(&mut OsRng), &SaltString::generate(&mut OsRng),
) )
.unwrap() .expect("Failed to hash password")
.to_string(); .to_string();
let db = MockDatabase::new(sea_orm::DatabaseBackend::Sqlite) let db = MockDatabase::new(sea_orm::DatabaseBackend::Sqlite)
.append_query_results(vec![vec![user::Model { .append_query_results(vec![vec![user::Model {

File diff suppressed because it is too large Load Diff

View File

@@ -67,6 +67,12 @@ generate-agent-client:
--additional-properties=supportMultipleResponses=true \ --additional-properties=supportMultipleResponses=true \
--additional-properties=topLevelApiClient=true \ --additional-properties=topLevelApiClient=true \
--additional-properties=useSingleRequestParameter=true --additional-properties=useSingleRequestParameter=true
# format generated code
cd public/agent-client && \
cargo fmt
# append lint allows/forbids to the end of Cargo.toml to disable warnings in generated code and forbid unsafe code
cd public/agent-client && \
echo '\n[lints.clippy]\nall = "allow"\n[lints.rust]\nunsafe_code = "forbid"\n' >> Cargo.toml
generate-all: generate-entity generate-openapi generate-agent-client generate-all: generate-entity generate-openapi generate-agent-client

6279
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,3 +1,7 @@
packages:
- apps/frontend
onlyBuiltDependencies: onlyBuiltDependencies:
- '@nestjs/core' - '@nestjs/core'
- '@openapitools/openapi-generator-cli' - '@openapitools/openapi-generator-cli'
- esbuild

View File

@@ -19,3 +19,9 @@ default = ["native-tls"]
native-tls = ["reqwest/native-tls"] native-tls = ["reqwest/native-tls"]
rustls-tls = ["reqwest/rustls-tls"] rustls-tls = ["reqwest/rustls-tls"]
mockall = ["dep:mockall"] mockall = ["dep:mockall"]
[lints.clippy]
all = "allow"
[lints.rust]
unsafe_code = "forbid"

View File

@@ -8,8 +8,6 @@
* Generated by: https://openapi-generator.tech * Generated by: https://openapi-generator.tech
*/ */
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Configuration { pub struct Configuration {
pub base_path: String, pub base_path: String,
@@ -29,7 +27,6 @@ pub struct ApiKey {
pub key: String, pub key: String,
} }
impl Configuration { impl Configuration {
pub fn new() -> Configuration { pub fn new() -> Configuration {
Configuration::default() Configuration::default()

View File

@@ -78,8 +78,10 @@ pub fn parse_deep_object(prefix: &str, value: &serde_json::Value) -> Vec<(String
value, value,
)); ));
} }
}, }
serde_json::Value::String(s) => params.push((format!("{}[{}]", prefix, key), s.clone())), serde_json::Value::String(s) => {
params.push((format!("{}[{}]", prefix, key), s.clone()))
}
_ => params.push((format!("{}[{}]", prefix, key), value.to_string())), _ => params.push((format!("{}[{}]", prefix, key), value.to_string())),
} }
} }
@@ -96,7 +98,7 @@ pub fn parse_deep_object(prefix: &str, value: &serde_json::Value) -> Vec<(String
enum ContentType { enum ContentType {
Json, Json,
Text, Text,
Unsupported(String) Unsupported(String),
} }
impl From<&str> for ContentType { impl From<&str> for ContentType {
@@ -128,7 +130,9 @@ pub struct ApiClient {
impl ApiClient { impl ApiClient {
pub fn new(configuration: Arc<configuration::Configuration>) -> Self { pub fn new(configuration: Arc<configuration::Configuration>) -> Self {
Self { Self {
nginx_agent_api: Box::new(nginx_agent_api::NginxAgentApiClient::new(configuration.clone())), nginx_agent_api: Box::new(nginx_agent_api::NginxAgentApiClient::new(
configuration.clone(),
)),
} }
} }
} }
@@ -159,4 +163,3 @@ impl Api for MockApiClient {
&self.nginx_agent_api_mock &self.nginx_agent_api_mock
} }
} }

View File

@@ -8,44 +8,51 @@
* Generated by: https://openapi-generator.tech * Generated by: https://openapi-generator.tech
*/ */
use super::{configuration, Error};
use crate::apis::ContentType;
use crate::{apis::ResponseContent, models};
use async_trait::async_trait; use async_trait::async_trait;
#[cfg(feature = "mockall")] #[cfg(feature = "mockall")]
use mockall::automock; use mockall::automock;
use reqwest; use reqwest;
use serde::{de::Error as _, Deserialize, Serialize};
use std::sync::Arc; use std::sync::Arc;
use serde::{Deserialize, Serialize, de::Error as _};
use crate::{apis::ResponseContent, models};
use super::{Error, configuration};
use crate::apis::ContentType;
#[cfg_attr(feature = "mockall", automock)] #[cfg_attr(feature = "mockall", automock)]
#[async_trait] #[async_trait]
pub trait NginxAgentApi: Send + Sync { pub trait NginxAgentApi: Send + Sync {
/// GET /status /// GET /status
/// ///
/// ///
async fn status(&self, ) -> Result<ResponseContent<StatusSuccess>, Error<StatusError>>; async fn status(&self) -> Result<ResponseContent<StatusSuccess>, Error<StatusError>>;
/// POST /validate /// POST /validate
/// ///
/// ///
async fn validate(&self, params: ValidateParams ) -> Result<ResponseContent<ValidateSuccess>, Error<ValidateError>>; async fn validate(
&self,
params: ValidateParams,
) -> Result<ResponseContent<ValidateSuccess>, Error<ValidateError>>;
/// POST /validate_and_reload /// POST /validate_and_reload
/// ///
/// ///
async fn validate_and_reload(&self, params: ValidateAndReloadParams ) -> Result<ResponseContent<ValidateAndReloadSuccess>, Error<ValidateAndReloadError>>; async fn validate_and_reload(
&self,
params: ValidateAndReloadParams,
) -> Result<ResponseContent<ValidateAndReloadSuccess>, Error<ValidateAndReloadError>>;
/// POST /write_config /// POST /write_config
/// ///
/// ///
async fn write_config(&self, params: WriteConfigParams ) -> Result<ResponseContent<WriteConfigSuccess>, Error<WriteConfigError>>; async fn write_config(
&self,
params: WriteConfigParams,
) -> Result<ResponseContent<WriteConfigSuccess>, Error<WriteConfigError>>;
} }
pub struct NginxAgentApiClient { pub struct NginxAgentApiClient {
configuration: Arc<configuration::Configuration> configuration: Arc<configuration::Configuration>,
} }
impl NginxAgentApiClient { impl NginxAgentApiClient {
@@ -54,40 +61,38 @@ impl NginxAgentApiClient {
} }
} }
/// struct for passing parameters to the method [`NginxAgentApi::validate`] /// struct for passing parameters to the method [`NginxAgentApi::validate`]
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct ValidateParams { pub struct ValidateParams {
pub validate_body: models::ValidateBody pub validate_body: models::ValidateBody,
} }
/// struct for passing parameters to the method [`NginxAgentApi::validate_and_reload`] /// struct for passing parameters to the method [`NginxAgentApi::validate_and_reload`]
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct ValidateAndReloadParams { pub struct ValidateAndReloadParams {
pub validate_and_reload_body: models::ValidateAndReloadBody pub validate_and_reload_body: models::ValidateAndReloadBody,
} }
/// struct for passing parameters to the method [`NginxAgentApi::write_config`] /// struct for passing parameters to the method [`NginxAgentApi::write_config`]
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct WriteConfigParams { pub struct WriteConfigParams {
pub write_config_body: models::WriteConfigBody pub write_config_body: models::WriteConfigBody,
} }
#[async_trait] #[async_trait]
impl NginxAgentApi for NginxAgentApiClient { impl NginxAgentApi for NginxAgentApiClient {
async fn status(&self, ) -> Result<ResponseContent<StatusSuccess>, Error<StatusError>> { async fn status(&self) -> Result<ResponseContent<StatusSuccess>, Error<StatusError>> {
let local_var_configuration = &self.configuration; let local_var_configuration = &self.configuration;
let local_var_client = &local_var_configuration.client; let local_var_client = &local_var_configuration.client;
let local_var_uri_str = format!("{}/status", local_var_configuration.base_path); let local_var_uri_str = format!("{}/status", local_var_configuration.base_path);
let mut local_var_req_builder = local_var_client.request(reqwest::Method::GET, local_var_uri_str.as_str()); let mut local_var_req_builder =
local_var_client.request(reqwest::Method::GET, local_var_uri_str.as_str());
if let Some(ref local_var_user_agent) = local_var_configuration.user_agent { if let Some(ref local_var_user_agent) = local_var_configuration.user_agent {
local_var_req_builder = local_var_req_builder.header(reqwest::header::USER_AGENT, local_var_user_agent.clone()); local_var_req_builder = local_var_req_builder
.header(reqwest::header::USER_AGENT, local_var_user_agent.clone());
} }
let local_var_req = local_var_req_builder.build()?; let local_var_req = local_var_req_builder.build()?;
@@ -97,32 +102,43 @@ impl NginxAgentApi for NginxAgentApiClient {
let local_var_content = local_var_resp.text().await?; let local_var_content = local_var_resp.text().await?;
if !local_var_status.is_client_error() && !local_var_status.is_server_error() { if !local_var_status.is_client_error() && !local_var_status.is_server_error() {
let local_var_entity: Option<StatusSuccess> = serde_json::from_str(&local_var_content).ok(); let local_var_entity: Option<StatusSuccess> =
let local_var_result = ResponseContent { status: local_var_status, content: local_var_content, entity: local_var_entity }; serde_json::from_str(&local_var_content).ok();
let local_var_result = ResponseContent {
status: local_var_status,
content: local_var_content,
entity: local_var_entity,
};
Ok(local_var_result) Ok(local_var_result)
} else { } else {
let local_var_entity: Option<StatusError> = serde_json::from_str(&local_var_content).ok(); let local_var_entity: Option<StatusError> =
let local_var_error = ResponseContent { status: local_var_status, content: local_var_content, entity: local_var_entity }; serde_json::from_str(&local_var_content).ok();
let local_var_error = ResponseContent {
status: local_var_status,
content: local_var_content,
entity: local_var_entity,
};
Err(Error::ResponseError(local_var_error)) Err(Error::ResponseError(local_var_error))
} }
} }
async fn validate(&self, params: ValidateParams ) -> Result<ResponseContent<ValidateSuccess>, Error<ValidateError>> { async fn validate(
&self,
let ValidateParams { params: ValidateParams,
validate_body, ) -> Result<ResponseContent<ValidateSuccess>, Error<ValidateError>> {
} = params; let ValidateParams { validate_body } = params;
let local_var_configuration = &self.configuration; let local_var_configuration = &self.configuration;
let local_var_client = &local_var_configuration.client; let local_var_client = &local_var_configuration.client;
let local_var_uri_str = format!("{}/validate", local_var_configuration.base_path); let local_var_uri_str = format!("{}/validate", local_var_configuration.base_path);
let mut local_var_req_builder = local_var_client.request(reqwest::Method::POST, local_var_uri_str.as_str()); let mut local_var_req_builder =
local_var_client.request(reqwest::Method::POST, local_var_uri_str.as_str());
if let Some(ref local_var_user_agent) = local_var_configuration.user_agent { if let Some(ref local_var_user_agent) = local_var_configuration.user_agent {
local_var_req_builder = local_var_req_builder.header(reqwest::header::USER_AGENT, local_var_user_agent.clone()); local_var_req_builder = local_var_req_builder
.header(reqwest::header::USER_AGENT, local_var_user_agent.clone());
} }
local_var_req_builder = local_var_req_builder.json(&validate_body); local_var_req_builder = local_var_req_builder.json(&validate_body);
@@ -133,32 +149,46 @@ impl NginxAgentApi for NginxAgentApiClient {
let local_var_content = local_var_resp.text().await?; let local_var_content = local_var_resp.text().await?;
if !local_var_status.is_client_error() && !local_var_status.is_server_error() { if !local_var_status.is_client_error() && !local_var_status.is_server_error() {
let local_var_entity: Option<ValidateSuccess> = serde_json::from_str(&local_var_content).ok(); let local_var_entity: Option<ValidateSuccess> =
let local_var_result = ResponseContent { status: local_var_status, content: local_var_content, entity: local_var_entity }; serde_json::from_str(&local_var_content).ok();
let local_var_result = ResponseContent {
status: local_var_status,
content: local_var_content,
entity: local_var_entity,
};
Ok(local_var_result) Ok(local_var_result)
} else { } else {
let local_var_entity: Option<ValidateError> = serde_json::from_str(&local_var_content).ok(); let local_var_entity: Option<ValidateError> =
let local_var_error = ResponseContent { status: local_var_status, content: local_var_content, entity: local_var_entity }; serde_json::from_str(&local_var_content).ok();
let local_var_error = ResponseContent {
status: local_var_status,
content: local_var_content,
entity: local_var_entity,
};
Err(Error::ResponseError(local_var_error)) Err(Error::ResponseError(local_var_error))
} }
} }
async fn validate_and_reload(&self, params: ValidateAndReloadParams ) -> Result<ResponseContent<ValidateAndReloadSuccess>, Error<ValidateAndReloadError>> { async fn validate_and_reload(
&self,
params: ValidateAndReloadParams,
) -> Result<ResponseContent<ValidateAndReloadSuccess>, Error<ValidateAndReloadError>> {
let ValidateAndReloadParams { let ValidateAndReloadParams {
validate_and_reload_body, validate_and_reload_body,
} = params; } = params;
let local_var_configuration = &self.configuration; let local_var_configuration = &self.configuration;
let local_var_client = &local_var_configuration.client; let local_var_client = &local_var_configuration.client;
let local_var_uri_str = format!("{}/validate_and_reload", local_var_configuration.base_path); let local_var_uri_str =
let mut local_var_req_builder = local_var_client.request(reqwest::Method::POST, local_var_uri_str.as_str()); format!("{}/validate_and_reload", local_var_configuration.base_path);
let mut local_var_req_builder =
local_var_client.request(reqwest::Method::POST, local_var_uri_str.as_str());
if let Some(ref local_var_user_agent) = local_var_configuration.user_agent { if let Some(ref local_var_user_agent) = local_var_configuration.user_agent {
local_var_req_builder = local_var_req_builder.header(reqwest::header::USER_AGENT, local_var_user_agent.clone()); local_var_req_builder = local_var_req_builder
.header(reqwest::header::USER_AGENT, local_var_user_agent.clone());
} }
local_var_req_builder = local_var_req_builder.json(&validate_and_reload_body); local_var_req_builder = local_var_req_builder.json(&validate_and_reload_body);
@@ -169,32 +199,43 @@ impl NginxAgentApi for NginxAgentApiClient {
let local_var_content = local_var_resp.text().await?; let local_var_content = local_var_resp.text().await?;
if !local_var_status.is_client_error() && !local_var_status.is_server_error() { if !local_var_status.is_client_error() && !local_var_status.is_server_error() {
let local_var_entity: Option<ValidateAndReloadSuccess> = serde_json::from_str(&local_var_content).ok(); let local_var_entity: Option<ValidateAndReloadSuccess> =
let local_var_result = ResponseContent { status: local_var_status, content: local_var_content, entity: local_var_entity }; serde_json::from_str(&local_var_content).ok();
let local_var_result = ResponseContent {
status: local_var_status,
content: local_var_content,
entity: local_var_entity,
};
Ok(local_var_result) Ok(local_var_result)
} else { } else {
let local_var_entity: Option<ValidateAndReloadError> = serde_json::from_str(&local_var_content).ok(); let local_var_entity: Option<ValidateAndReloadError> =
let local_var_error = ResponseContent { status: local_var_status, content: local_var_content, entity: local_var_entity }; serde_json::from_str(&local_var_content).ok();
let local_var_error = ResponseContent {
status: local_var_status,
content: local_var_content,
entity: local_var_entity,
};
Err(Error::ResponseError(local_var_error)) Err(Error::ResponseError(local_var_error))
} }
} }
async fn write_config(&self, params: WriteConfigParams ) -> Result<ResponseContent<WriteConfigSuccess>, Error<WriteConfigError>> { async fn write_config(
&self,
let WriteConfigParams { params: WriteConfigParams,
write_config_body, ) -> Result<ResponseContent<WriteConfigSuccess>, Error<WriteConfigError>> {
} = params; let WriteConfigParams { write_config_body } = params;
let local_var_configuration = &self.configuration; let local_var_configuration = &self.configuration;
let local_var_client = &local_var_configuration.client; let local_var_client = &local_var_configuration.client;
let local_var_uri_str = format!("{}/write_config", local_var_configuration.base_path); let local_var_uri_str = format!("{}/write_config", local_var_configuration.base_path);
let mut local_var_req_builder = local_var_client.request(reqwest::Method::POST, local_var_uri_str.as_str()); let mut local_var_req_builder =
local_var_client.request(reqwest::Method::POST, local_var_uri_str.as_str());
if let Some(ref local_var_user_agent) = local_var_configuration.user_agent { if let Some(ref local_var_user_agent) = local_var_configuration.user_agent {
local_var_req_builder = local_var_req_builder.header(reqwest::header::USER_AGENT, local_var_user_agent.clone()); local_var_req_builder = local_var_req_builder
.header(reqwest::header::USER_AGENT, local_var_user_agent.clone());
} }
local_var_req_builder = local_var_req_builder.json(&write_config_body); local_var_req_builder = local_var_req_builder.json(&write_config_body);
@@ -205,16 +246,25 @@ impl NginxAgentApi for NginxAgentApiClient {
let local_var_content = local_var_resp.text().await?; let local_var_content = local_var_resp.text().await?;
if !local_var_status.is_client_error() && !local_var_status.is_server_error() { if !local_var_status.is_client_error() && !local_var_status.is_server_error() {
let local_var_entity: Option<WriteConfigSuccess> = serde_json::from_str(&local_var_content).ok(); let local_var_entity: Option<WriteConfigSuccess> =
let local_var_result = ResponseContent { status: local_var_status, content: local_var_content, entity: local_var_entity }; serde_json::from_str(&local_var_content).ok();
let local_var_result = ResponseContent {
status: local_var_status,
content: local_var_content,
entity: local_var_entity,
};
Ok(local_var_result) Ok(local_var_result)
} else { } else {
let local_var_entity: Option<WriteConfigError> = serde_json::from_str(&local_var_content).ok(); let local_var_entity: Option<WriteConfigError> =
let local_var_error = ResponseContent { status: local_var_status, content: local_var_content, entity: local_var_entity }; serde_json::from_str(&local_var_content).ok();
let local_var_error = ResponseContent {
status: local_var_status,
content: local_var_content,
entity: local_var_entity,
};
Err(Error::ResponseError(local_var_error)) Err(Error::ResponseError(local_var_error))
} }
} }
} }
/// struct for typed successes of method [`NginxAgentApi::status`] /// struct for typed successes of method [`NginxAgentApi::status`]
@@ -277,4 +327,3 @@ pub enum WriteConfigError {
Status500(serde_json::Value), Status500(serde_json::Value),
UnknownValue(serde_json::Value), UnknownValue(serde_json::Value),
} }

View File

@@ -1,9 +1,9 @@
#![allow(unused_imports)] #![allow(unused_imports)]
#![allow(clippy::too_many_arguments)] #![allow(clippy::too_many_arguments)]
extern crate serde_repr;
extern crate serde; extern crate serde;
extern crate serde_json; extern crate serde_json;
extern crate serde_repr;
extern crate url; extern crate url;
pub mod apis; pub mod apis;

View File

@@ -19,9 +19,6 @@ pub struct StatusResp {
impl StatusResp { impl StatusResp {
pub fn new(ok: bool) -> StatusResp { pub fn new(ok: bool) -> StatusResp {
StatusResp { StatusResp { ok }
ok,
} }
} }
}

View File

@@ -27,4 +27,3 @@ impl ValidateAndReloadBody {
} }
} }
} }

View File

@@ -21,10 +21,6 @@ pub struct ValidateAndReloadResp {
impl ValidateAndReloadResp { impl ValidateAndReloadResp {
pub fn new(rc: i32, ro: String) -> ValidateAndReloadResp { pub fn new(rc: i32, ro: String) -> ValidateAndReloadResp {
ValidateAndReloadResp { ValidateAndReloadResp { rc, ro }
rc,
ro,
} }
} }
}

View File

@@ -27,4 +27,3 @@ impl ValidateBody {
} }
} }
} }

View File

@@ -30,4 +30,3 @@ impl WriteConfigBody {
} }
} }
} }