Skip to content

Commit

Permalink
apply formatter and fix creating object proxy
Browse files Browse the repository at this point in the history
  • Loading branch information
jreidinger committed Mar 21, 2024
1 parent eebbbd4 commit 22a936c
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 46 deletions.
131 changes: 86 additions & 45 deletions rust/agama-server/src/questions/web.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,30 @@
//! * `questions_service` which returns the Axum service.
//! * `questions_stream` which offers an stream that emits questions related signals.

use std::{collections::HashMap,pin::Pin};
use crate::{error::Error, web::Event};
use agama_lib::{
error::ServiceError, proxies::{GenericQuestionProxy, QuestionWithPasswordProxy},
error::ServiceError,
proxies::{GenericQuestionProxy, QuestionWithPasswordProxy},
};
use anyhow::Context;
use axum::{
extract::{State, Path},
extract::{Path, State},
http::StatusCode,
response::{IntoResponse, Response},
routing::{get, put},
Json, Router,
};
use tokio_stream::{Stream, StreamExt};
use zbus::{fdo::ObjectManagerProxy, names::{InterfaceName, OwnedInterfaceName}};
use zbus::zvariant::OwnedObjectPath;
use zbus::zvariant::ObjectPath;
use thiserror::Error;
use serde::{Deserialize, Serialize};
use serde_json::json;
use std::{collections::HashMap, pin::Pin};
use thiserror::Error;
use tokio_stream::{Stream, StreamExt};
use zbus::zvariant::ObjectPath;
use zbus::zvariant::OwnedObjectPath;
use zbus::{
fdo::ObjectManagerProxy,
names::{InterfaceName, OwnedInterfaceName},
};

// TODO: move to lib
#[derive(Clone)]
Expand All @@ -35,19 +39,27 @@ struct QuestionsClient<'a> {

impl<'a> QuestionsClient<'a> {
pub async fn new(dbus: zbus::Connection) -> Result<Self, zbus::Error> {
let question_path =
OwnedObjectPath::from(ObjectPath::try_from("/org/opensuse/Agama1/Questions")?);
Ok(Self {
connection: dbus.clone(),
objects_proxy: ObjectManagerProxy::new(&dbus).await?
objects_proxy: ObjectManagerProxy::builder(&dbus)
.path(question_path)?
.build()
.await?,
})
}

pub async fn questions(&self) -> Result<Vec<Question>, ServiceError> {
let objects = self.objects_proxy.get_managed_objects().await
let objects = self
.objects_proxy
.get_managed_objects()
.await
.context("failed to get managed object with Object Manager")?;
let mut result: Vec<Question> = Vec::with_capacity(objects.len());
let password_interface = OwnedInterfaceName::from(
InterfaceName::from_static_str("org.opensuse.Agama1.Questions.WithPassword")
.context("Failed to create interface name for question with password")?
.context("Failed to create interface name for question with password")?,
);
for (path, interfaces_hash) in objects.iter() {
if interfaces_hash.contains_key(&password_interface) {
Expand All @@ -59,30 +71,42 @@ impl<'a> QuestionsClient<'a> {
Ok(result)
}

async fn create_generic_question(&self, path: &OwnedObjectPath) -> Result<Question, ServiceError> {
async fn create_generic_question(
&self,
path: &OwnedObjectPath,
) -> Result<Question, ServiceError> {
let dbus_question = GenericQuestionProxy::builder(&self.connection)
.path(path)?.cache_properties(zbus::CacheProperties::No).build().await?;
.path(path)?
.cache_properties(zbus::CacheProperties::No)
.build()
.await?;
let result = Question {
generic: GenericQuestion {
id: dbus_question.id().await?,
class: dbus_question.class().await?,
text: dbus_question.text().await?,
options: dbus_question.options().await?,
default_option: dbus_question.default_option().await?,
data: dbus_question.data().await?
data: dbus_question.data().await?,
},
with_password: None
with_password: None,
};

Ok(result)
}

async fn create_question_with_password(&self, path: &OwnedObjectPath) -> Result<Question, ServiceError> {
async fn create_question_with_password(
&self,
path: &OwnedObjectPath,
) -> Result<Question, ServiceError> {
let dbus_question = QuestionWithPasswordProxy::builder(&self.connection)
.path(path)?.cache_properties(zbus::CacheProperties::No).build().await?;
.path(path)?
.cache_properties(zbus::CacheProperties::No)
.build()
.await?;
let mut result = self.create_generic_question(path).await?;
result.with_password = Some(QuestionWithPassword{
password: dbus_question.password().await?
result.with_password = Some(QuestionWithPassword {
password: dbus_question.password().await?,
});

Ok(result)
Expand All @@ -91,16 +115,26 @@ impl<'a> QuestionsClient<'a> {
pub async fn answer(&self, id: u32, answer: Answer) -> Result<(), ServiceError> {
let question_path = OwnedObjectPath::from(
ObjectPath::try_from(format!("/org/opensuse/Agama1/Questions/{}", id))
.context("Failed to create dbus path")?
);
.context("Failed to create dbus path")?,
);
if let Some(password) = answer.with_password {
let dbus_password = QuestionWithPasswordProxy::builder(&self.connection)
.path(&question_path)?.cache_properties(zbus::CacheProperties::No).build().await?;
dbus_password.set_password(password.password.as_str()).await?
.path(&question_path)?
.cache_properties(zbus::CacheProperties::No)
.build()
.await?;
dbus_password
.set_password(password.password.as_str())
.await?
}
let dbus_generic = GenericQuestionProxy::builder(&self.connection)
.path(&question_path)?.cache_properties(zbus::CacheProperties::No).build().await?;
dbus_generic.set_answer(answer.generic.answer.as_str()).await?;
.path(&question_path)?
.cache_properties(zbus::CacheProperties::No)
.build()
.await?;
dbus_generic
.set_answer(answer.generic.answer.as_str())
.await?;
Ok(())
}
}
Expand Down Expand Up @@ -140,14 +174,14 @@ pub struct GenericQuestion {
text: String,
options: Vec<String>,
default_option: String,
data: HashMap<String, String>
data: HashMap<String, String>,
}

/// Facade of agama_lib::questions::WithPassword
/// For fields details see it.
#[derive(Clone, Serialize, Deserialize, utoipa::ToSchema)]
pub struct QuestionWithPassword {
password: String
password: String,
}

#[derive(Clone, Serialize, Deserialize, utoipa::ToSchema)]
Expand All @@ -159,13 +193,13 @@ pub struct Answer {
/// Answer needed for GenericQuestion
#[derive(Clone, Serialize, Deserialize, utoipa::ToSchema)]
pub struct GenericAnswer {
answer: String
answer: String,
}

/// Answer needed for Password specific questions.
#[derive(Clone, Serialize, Deserialize, utoipa::ToSchema)]
pub struct PasswordAnswer {
password: String
password: String,
}
/// Sets up and returns the axum service for the questions module.
pub async fn questions_service(dbus: zbus::Connection) -> Result<Router, ServiceError> {
Expand All @@ -178,35 +212,42 @@ pub async fn questions_service(dbus: zbus::Connection) -> Result<Router, Service
Ok(router)
}

pub async fn questions_stream(dbus: zbus::Connection) ->
Result<Pin<Box<dyn Stream<Item = Event> + Send>>, Error> {
let proxy = ObjectManagerProxy::new(&dbus).await?;
pub async fn questions_stream(
dbus: zbus::Connection,
) -> Result<Pin<Box<dyn Stream<Item = Event> + Send>>, Error> {
let question_path = OwnedObjectPath::from(
ObjectPath::try_from("/org/opensuse/Agama1/Questions")
.context("failed to create object path")?,
);
let proxy = ObjectManagerProxy::builder(&dbus)
.path(question_path)
.context("Failed to create object manager path")?
.build()
.await
.context("Failed to create Object MAnager proxy")?;
let add_stream = proxy
.receive_interfaces_added()
.await?
.then(|_| async move {
Event::QuestionsChanged
});
.then(|_| async move { Event::QuestionsChanged });
let remove_stream = proxy
.receive_interfaces_removed()
.await?
.then(|_| async move {
Event::QuestionsChanged
});
.then(|_| async move { Event::QuestionsChanged });
let stream = StreamExt::merge(add_stream, remove_stream);
Ok(Box::pin(stream))
}

async fn list_questions(State(state): State<QuestionsState<'_>>
) -> Result<Json<Vec<Question>>, QuestionsError> {
Ok(Json(state.questions.questions().await?))
async fn list_questions(
State(state): State<QuestionsState<'_>>,
) -> Result<Json<Vec<Question>>, QuestionsError> {
Ok(Json(state.questions.questions().await?))
}

async fn answer(
State(state): State<QuestionsState<'_>>,
Path(question_id): Path<u32>,
Json(answer): Json<Answer>
State(state): State<QuestionsState<'_>>,
Path(question_id): Path<u32>,
Json(answer): Json<Answer>,
) -> Result<(), QuestionsError> {
state.questions.answer(question_id, answer).await?;
Ok(())
}
}
2 changes: 1 addition & 1 deletion rust/agama-server/src/web.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ use crate::{
error::Error,
l10n::web::l10n_service,
manager::web::{manager_service, manager_stream},
software::web::{software_service, software_stream},
questions::web::{questions_service, questions_stream},
software::web::{software_service, software_stream},
web::common::{progress_stream, service_status_stream},
};
use axum::Router;
Expand Down

0 comments on commit 22a936c

Please sign in to comment.