Skip to content

Commit

Permalink
Add support to expose the Issues API
Browse files Browse the repository at this point in the history
  • Loading branch information
imobachgs committed Mar 19, 2024
1 parent 3f13f6f commit 806fedc
Show file tree
Hide file tree
Showing 3 changed files with 134 additions and 3 deletions.
7 changes: 7 additions & 0 deletions rust/agama-lib/src/proxies.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,3 +121,10 @@ trait Questions1 {
#[dbus_proxy(property)]
fn set_interactive(&self, value: bool) -> zbus::Result<()>;
}

#[dbus_proxy(interface = "org.opensuse.Agama1.Issues", assume_defaults = true)]
trait Issues {
/// All property
#[dbus_proxy(property)]
fn all(&self) -> zbus::Result<Vec<(String, String, u32, u32)>>;
}
125 changes: 122 additions & 3 deletions rust/agama-server/src/web/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use std::{pin::Pin, task::Poll};
use agama_lib::{
error::ServiceError,
progress::Progress,
proxies::{ProgressProxy, ServiceStatusProxy},
proxies::{IssuesProxy, ProgressProxy, ServiceStatusProxy},
};
use axum::{extract::State, routing::get, Json, Router};
use pin_project::pin_project;
Expand All @@ -17,8 +17,8 @@ use crate::error::Error;

use super::Event;

/// Builds a router to the `org.opensuse.Agama1.ServiceStatus`
/// interface of the given D-Bus object.
/// Builds a router to the `org.opensuse.Agama1.ServiceStatus` interface of the
/// given D-Bus object.
///
/// ```no_run
/// # use axum::{extract::State, routing::get, Json, Router};
Expand Down Expand Up @@ -231,3 +231,122 @@ async fn build_progress_proxy<'a>(
.await?;
Ok(proxy)
}

/// Builds a router to the `org.opensuse.Agama1.Issues` interface of a given
/// D-Bus object.
///
/// ```no_run
/// # use axum::{extract::State, routing::get, Json, Router};
/// # use agama_lib::connection;
/// # use agama_server::web::common::service_status_router;
/// # use tokio_test;
///
/// # tokio_test::block_on(async {
/// async fn hello(state: State<HelloWorldState>) {};
///
/// #[derive(Clone)]
/// struct HelloWorldState {};
///
/// let dbus = connection().await.unwrap();
/// let issues_router = issues_router(
/// &dbus, "org.opensuse.HelloWorld", "/org/opensuse/hello"
/// ).await.unwrap();
/// let router: Router<HelloWorldState> = Router::new()
/// .route("/hello", get(hello))
/// .merge(issues_router)
/// .with_state(HelloWorldState {});
/// });
/// ```
///
/// * `dbus`: D-Bus connection.
/// * `destination`: D-Bus service name.
/// * `path`: D-Bus object path.
pub async fn issues_router<T>(
dbus: &zbus::Connection,
destination: &str,
path: &str,
) -> Result<Router<T>, ServiceError> {
let proxy = build_issues_proxy(dbus, destination, path).await?;
let state = IssuesState { proxy };
Ok(Router::new()
.route("/issues", get(issues))
.with_state(state))
}

async fn issues(State(state): State<IssuesState<'_>>) -> Result<Json<Vec<Issue>>, Error> {
let issues = state.proxy.all().await?;
let issues: Vec<Issue> = issues.into_iter().map(Issue::from_tuple).collect();
Ok(Json(issues))
}

#[derive(Clone)]
struct IssuesState<'a> {
proxy: IssuesProxy<'a>,
}

#[derive(Clone, Debug, Serialize)]
pub struct Issue {
description: String,
details: Option<String>,
source: u32,
severity: u32,
}

impl Issue {
pub fn from_tuple(
(description, details, source, severity): (String, String, u32, u32),
) -> Self {
let details = if details.is_empty() {
None
} else {
Some(details)
};

Self {
description,
details,
source,
severity,
}
}
}

/// Builds a stream of the changes in the the `org.opensuse.Agama1.Issues`
/// interface of the given D-Bus object.
///
/// * `dbus`: D-Bus connection.
/// * `destination`: D-Bus service name.
/// * `path`: D-Bus object path.
pub async fn issues_stream(
dbus: zbus::Connection,
destination: &'static str,
path: &'static str,
) -> Result<Pin<Box<dyn Stream<Item = Event> + Send>>, Error> {
let proxy = build_issues_proxy(&dbus, destination, path).await?;
let stream = proxy
.receive_all_changed()
.await
.then(move |change| async move {
if let Ok(issues) = change.get().await {
let issues = issues.into_iter().map(Issue::from_tuple).collect();
Some(Event::IssuesChanged { issues })
} else {
None
}
})
.filter_map(|e| e);
Ok(Box::pin(stream))
}

async fn build_issues_proxy<'a>(
dbus: &zbus::Connection,
destination: &str,
path: &str,
) -> Result<IssuesProxy<'a>, zbus::Error> {
let proxy = IssuesProxy::builder(&dbus)
.destination(destination.to_string())?
.path(path.to_string())?
.build()
.await?;
Ok(proxy)
}
5 changes: 5 additions & 0 deletions rust/agama-server/src/web/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ use serde::Serialize;
use std::collections::HashMap;
use tokio::sync::broadcast::{Receiver, Sender};

use super::common::Issue;

#[derive(Clone, Debug, Serialize)]
#[serde(tag = "type")]
pub enum Event {
Expand All @@ -30,6 +32,9 @@ pub enum Event {
service: String,
status: u32,
},
IssuesChanged {
issues: Vec<Issue>,
},
}

pub type EventsSender = Sender<Event>;
Expand Down

0 comments on commit 806fedc

Please sign in to comment.