Skip to content

Commit

Permalink
fix(rust): handle registration errors properly
Browse files Browse the repository at this point in the history
  • Loading branch information
imobachgs committed Jan 8, 2025
1 parent 7e4e6db commit 9a98871
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 27 deletions.
21 changes: 19 additions & 2 deletions rust/agama-lib/src/product/http_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
// To contact SUSE LLC about this file by physical or electronic mail, you may
// find current contact information at www.suse.com.

use crate::software::model::RegistrationError;
use crate::software::model::RegistrationInfo;
use crate::software::model::RegistrationParams;
use crate::software::model::SoftwareConfig;
Expand Down Expand Up @@ -64,13 +65,29 @@ impl ProductHTTPClient {
}

/// register product
pub async fn register(&self, key: &str, email: &str) -> Result<(u32, String), ServiceError> {
pub async fn register(&self, key: &str, email: &str) -> Result<(), ServiceError> {
// note RegistrationParams != RegistrationInfo, fun!
let params = RegistrationParams {
key: key.to_owned(),
email: email.to_owned(),
};
let result = self
.client
.post_void("/software/registration", &params)
.await;

self.client.post("/software/registration", &params).await
let Err(error) = result else {
return Ok(());
};

let message = match error {
ServiceError::BackendError(_, details) => {
let details: RegistrationError = serde_json::from_str(&details).unwrap();
format!("{} (error code: {})", details.message, details.id)
}
_ => format!("Could not register the product: #{error:?}"),
};

Err(ServiceError::FailedRegistration(message))
}
}
13 changes: 2 additions & 11 deletions rust/agama-lib/src/product/store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,17 +68,8 @@ impl ProductStore {
}
}
if let Some(reg_code) = &settings.registration_code {
let (result, message);
if let Some(email) = &settings.registration_email {
(result, message) = self.product_client.register(reg_code, email).await?;
} else {
(result, message) = self.product_client.register(reg_code, "").await?;
}
// FIXME: name the magic numbers. 3 is Registration not required
// FIXME: well don't register when not required (no regcode in profile)
if result != 0 && result != 3 {
return Err(ServiceError::FailedRegistration(message));
}
let email = settings.registration_email.as_deref().unwrap_or("");
self.product_client.register(reg_code, email).await?;
probe = true;
}

Expand Down
8 changes: 8 additions & 0 deletions rust/agama-lib/src/software/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,14 @@ pub enum RegistrationRequirement {
Mandatory = 2,
}

#[derive(Clone, Serialize, Deserialize, utoipa::ToSchema)]
pub struct RegistrationError {
/// ID of error. See dbus API for possible values
pub id: u32,
/// human readable error string intended to be displayed to user
pub message: String,
}

/// Software resolvable type (package or pattern).
#[derive(Deserialize, Serialize, strum::Display, utoipa::ToSchema)]
#[strum(serialize_all = "camelCase")]
Expand Down
23 changes: 9 additions & 14 deletions rust/agama-server/src/software/web.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,10 @@ use agama_lib::{
error::ServiceError,
product::{proxies::RegistrationProxy, Product, ProductClient},
software::{
model::{RegistrationInfo, RegistrationParams, ResolvableParams, SoftwareConfig},
model::{
RegistrationError, RegistrationInfo, RegistrationParams, ResolvableParams,
SoftwareConfig,
},
proxies::{Software1Proxy, SoftwareProductProxy},
Pattern, SelectedBy, SoftwareClient, UnknownSelectedBy,
},
Expand All @@ -49,7 +52,7 @@ use axum::{
routing::{get, post, put},
Json, Router,
};
use serde::{Deserialize, Serialize};
use serde::Serialize;
use std::collections::HashMap;
use tokio_stream::{Stream, StreamExt};

Expand Down Expand Up @@ -248,14 +251,6 @@ async fn get_registration(
Ok(Json(result))
}

#[derive(Clone, Serialize, Deserialize, utoipa::ToSchema)]
pub struct FailureDetails {
/// ID of error. See dbus API for possible values
id: u32,
/// human readable error string intended to be displayed to user
message: String,
}

/// Register product
///
/// * `state`: service state.
Expand All @@ -265,7 +260,7 @@ pub struct FailureDetails {
context_path = "/api/software",
responses(
(status = 204, description = "registration successfull"),
(status = 422, description = "Registration failed. Details are in body", body = FailureDetails),
(status = 422, description = "Registration failed. Details are in body", body = RegistrationError),
(status = 400, description = "The D-Bus service could not perform the action")
)
)]
Expand All @@ -274,10 +269,10 @@ async fn register(
Json(config): Json<RegistrationParams>,
) -> Result<impl IntoResponse, Error> {
let (id, message) = state.product.register(&config.key, &config.email).await?;
let details = FailureDetails { id, message };
if id == 0 {
Ok((StatusCode::NO_CONTENT, ().into_response()))
} else {
let details = RegistrationError { id, message };
Ok((
StatusCode::UNPROCESSABLE_ENTITY,
Json(details).into_response(),
Expand All @@ -294,13 +289,13 @@ async fn register(
context_path = "/api/software",
responses(
(status = 200, description = "deregistration successfull"),
(status = 422, description = "De-registration failed. Details are in body", body = FailureDetails),
(status = 422, description = "De-registration failed. Details are in body", body = RegistrationError),
(status = 400, description = "The D-Bus service could not perform the action")
)
)]
async fn deregister(State(state): State<SoftwareState<'_>>) -> Result<impl IntoResponse, Error> {
let (id, message) = state.product.deregister().await?;
let details = FailureDetails { id, message };
let details = RegistrationError { id, message };
if id == 0 {
Ok((StatusCode::NO_CONTENT, ().into_response()))
} else {
Expand Down

0 comments on commit 9a98871

Please sign in to comment.