Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
a8e12a1
feat(rust): add a client ID to the JWT
imobachgs Jul 30, 2025
0a50b38
feat(rust): add the client ID to each request
imobachgs Jul 30, 2025
018478c
chore: log the client ID
imobachgs Jul 30, 2025
9598598
feat(rust): emit a Connected event
imobachgs Jul 30, 2025
eb0ff35
feat(web): add infrastructure for displaying out-of-sync alert
dgdavid Jul 30, 2025
10c69bc
feat(rust): add the client ID to events
imobachgs Jul 30, 2025
199cef9
fix(rust): add clientId to the L10nConfigChanged event
imobachgs Jul 30, 2025
bf2faa2
fix(web): simplify out of sync alert text
dgdavid Jul 31, 2025
847ad24
feat(web): make client aware of its ID
dgdavid Jul 31, 2025
e147a34
refactor(rust): move event! macro tests to doctests
imobachgs Jul 31, 2025
eec9d8a
feat(web): enable use of `replace` prop in core/Link
dgdavid Jul 31, 2025
0626869
doc(web): add entry to changes file
dgdavid Jul 31, 2025
88839db
fix(web): add missing mock
dgdavid Jul 31, 2025
cd32708
feat: add a client ID to be used in signals (#2627)
imobachgs Jul 31, 2025
84743d8
fix(web): force a reload via JavaScript
dgdavid Jul 31, 2025
d68bb86
Merge branch 'ui-sync' into out-of-sync-toast
dgdavid Jul 31, 2025
9e72bb5
fix(web): minor adjustments in test file
dgdavid Jul 31, 2025
e2b949c
feat(web): add infrastructure for displaying out-of-sync alert (#2630)
dgdavid Jul 31, 2025
9fb0828
fix(storage): do not generate json for default size
joseivanlopez Jul 30, 2025
36846c5
storage: avoid unnecessary signals/events
joseivanlopez Jul 30, 2025
423a6ba
storage: send event when storage is configured
joseivanlopez Jul 30, 2025
2bbc686
web: fix alert
joseivanlopez Jul 31, 2025
f362fb5
web: use alert in storage
joseivanlopez Jul 31, 2025
355e69a
feat(web): safeguard partition page/form from missing or wrong param
dgdavid Aug 3, 2025
ffac6fe
feat(web): subscribe PartitionPage to storage changes
dgdavid Aug 3, 2025
ecea98c
Revert "web: fix alert"
joseivanlopez Aug 4, 2025
bb85d06
storage: properly send client id on storage changed
joseivanlopez Aug 4, 2025
6506747
feat(web): re-render result section only when proceed
dgdavid Aug 4, 2025
eddad29
feat(web) PoC of hook for using last valid values
dgdavid Aug 4, 2025
6e5f930
feat(web): move useLastValid hook to its own file
dgdavid Aug 4, 2025
cb0f760
storage: include client id while probing through manager
joseivanlopez Aug 4, 2025
ced6db4
Revert "feat(web): move useLastValid hook to its own file"
joseivanlopez Aug 5, 2025
76ded0a
Revert "feat(web) PoC of hook for using last valid values"
joseivanlopez Aug 5, 2025
214c4f9
Revert "feat(web): re-render result section only when proceed"
joseivanlopez Aug 5, 2025
efbf66e
web: use blocking popup for out of sync alert
joseivanlopez Aug 5, 2025
b5f77f6
web: move alert to app
joseivanlopez Aug 5, 2025
de5b6a6
web: improvements in alert
joseivanlopez Aug 6, 2025
4c33466
fix(ui): detect out of sync storage (#2622)
joseivanlopez Aug 6, 2025
3c4870d
Merge branch 'master' into ui-sync
joseivanlopez Aug 6, 2025
12947af
rust: changelog
joseivanlopez Aug 6, 2025
38489a7
service: changelog
joseivanlopez Aug 6, 2025
9b587f1
web: changelog
joseivanlopez Aug 6, 2025
8cc6ebc
storage: fix tests
joseivanlopez Aug 6, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions rust/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions rust/agama-lib/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ fluent-uri = { version = "0.3.2", features = ["serde"] }
tokio-tungstenite = { version = "0.26.2", features = ["native-tls"] }
tokio-native-tls = "0.3.1"
percent-encoding = "2.3.1"
uuid = { version = "1.17.0", features = ["serde", "v4"] }

[dev-dependencies]
httpmock = "0.7.0"
Expand Down
30 changes: 27 additions & 3 deletions rust/agama-lib/src/auth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ const USER_TOKEN_PATH: &str = ".local/agama/token";
const AGAMA_TOKEN_FILE: &str = "/run/agama/token";

use std::{
fmt::Display,
fmt,
fs::{self, File},
io::{self, BufRead, BufReader, Write},
os::unix::fs::OpenOptionsExt,
Expand All @@ -56,6 +56,7 @@ use chrono::{Duration, Utc};
use jsonwebtoken::{DecodingKey, EncodingKey, Header, Validation};
use serde::{Deserialize, Serialize};
use thiserror::Error;
use uuid::Uuid;

#[derive(Error, Debug)]
#[error("Invalid authentication token: {0}")]
Expand Down Expand Up @@ -183,8 +184,8 @@ impl AuthToken {
}
}

impl Display for AuthToken {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
impl fmt::Display for AuthToken {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
Expand All @@ -195,8 +196,10 @@ impl Display for AuthToken {
#[derive(Debug, Serialize, Deserialize)]
pub struct TokenClaims {
pub exp: i64,
pub client_id: ClientId,
}

// FIXME: replace with TokenClaims::new, as it does not exist a "default" token.
impl Default for TokenClaims {
fn default() -> Self {
let mut exp = Utc::now();
Expand All @@ -207,10 +210,31 @@ impl Default for TokenClaims {

Self {
exp: exp.timestamp(),
client_id: ClientId::new(),
}
}
}

/// Identifies a client.
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub struct ClientId(Uuid);

impl ClientId {
pub fn new() -> Self {
ClientId(Uuid::new_v4())
}

pub fn new_from_uuid(uuid: Uuid) -> Self {
ClientId(uuid)
}
}

impl fmt::Display for ClientId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}

#[cfg(test)]
mod tests {
use tempfile::tempdir;
Expand Down
2 changes: 1 addition & 1 deletion rust/agama-lib/src/http.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ mod base_http_client;
pub use base_http_client::{BaseHTTPClient, BaseHTTPClientError};

mod event;
pub use event::Event;
pub use event::{Event, EventPayload};

mod websocket;
pub use websocket::{WebSocketClient, WebSocketError};
108 changes: 107 additions & 1 deletion rust/agama-lib/src/http/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
// find current contact information at www.suse.com.

use crate::{
auth::ClientId,
jobs::Job,
localization::model::LocaleConfig,
manager::InstallationPhase,
Expand All @@ -39,9 +40,47 @@ use std::collections::HashMap;

use crate::issue::Issue;

/// Agama event.
///
/// It represents an event that occurs in Agama.
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Event {
/// The identifier of the client which caused the event.
#[serde(skip_serializing_if = "Option::is_none")]
pub client_id: Option<ClientId>,
/// Event payload.
#[serde(flatten)]
pub payload: EventPayload,
}

impl Event {
/// Creates a new event.
///
/// * `payload`: event payload.
pub fn new(payload: EventPayload) -> Self {
Event {
client_id: None,
payload,
}
}

/// Creates a new event with a client ID.
///
/// * `payload`: event payload.
/// * `client_id`: client ID.
pub fn new_with_client_id(payload: EventPayload, client_id: &ClientId) -> Self {
Event {
client_id: Some(client_id.clone()),
payload,
}
}
}

#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(tag = "type")]
pub enum Event {
pub enum EventPayload {
ClientConnected,
L10nConfigChanged(LocaleConfig),
LocaleChanged {
locale: String,
Expand All @@ -64,6 +103,7 @@ pub enum Event {
#[serde(flatten)]
change: NetworkChange,
},
StorageChanged,
// TODO: it should include the full software proposal or, at least,
// all the relevant changes.
SoftwareProposalChanged {
Expand Down Expand Up @@ -144,3 +184,69 @@ pub enum Event {
device: ZFCPController,
},
}

/// Makes it easier to create an event, reducing the boilerplate.
///
/// # Event without additional data
///
/// ```
/// # use agama_lib::{event, http::EventPayload};
/// let my_event = event!(ClientConnected);
/// assert!(matches!(my_event.payload, EventPayload::ClientConnected));
/// assert!(my_event.client_id.is_none());
/// ```
///
/// # Event with some additional data
///
/// ```
/// # use agama_lib::{event, http::EventPayload};
/// let my_event = event!(LocaleChanged { locale: "es_ES".to_string() });
/// assert!(matches!(
/// my_event.payload,
/// EventPayload::LocaleChanged { locale: _ }
/// ));
/// ```
///
/// # Adding the client ID
///
/// ```
/// # use agama_lib::{auth::ClientId, event, http::EventPayload};
/// let client_id = ClientId::new();
/// let my_event = event!(ClientConnected, &client_id);
/// assert!(matches!(my_event.payload, EventPayload::ClientConnected));
/// assert!(my_event.client_id.is_some());
/// ```
///
/// # Add the client ID to a complex event
///
/// ```
/// # use agama_lib::{auth::ClientId, event, http::EventPayload};
/// let client_id = ClientId::new();
/// let my_event = event!(LocaleChanged { locale: "es_ES".to_string() }, &client_id);
/// assert!(matches!(
/// my_event.payload,
/// EventPayload::LocaleChanged { locale: _ }
/// ));
/// assert!(my_event.client_id.is_some());
/// ```
#[macro_export]
macro_rules! event {
($variant:ident) => {
agama_lib::http::Event::new(agama_lib::http::EventPayload::$variant)
};
($variant:ident, $client:expr) => {
agama_lib::http::Event::new_with_client_id(
agama_lib::http::EventPayload::$variant,
$client,
)
};
($variant:ident $inner:tt, $client:expr) => {
agama_lib::http::Event::new_with_client_id(
agama_lib::http::EventPayload::$variant $inner,
$client
)
};
($variant:ident $inner:tt) => {
agama_lib::http::Event::new(agama_lib::http::EventPayload::$variant $inner)
};
}
15 changes: 11 additions & 4 deletions rust/agama-lib/src/manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
pub mod http_client;
pub use http_client::ManagerHTTPClient;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;

use crate::error::ServiceError;
use crate::proxies::ServiceStatusProxy;
Expand Down Expand Up @@ -141,15 +142,21 @@ impl<'a> ManagerClient<'a> {
}

/// Starts the probing process.
pub async fn probe(&self) -> Result<(), ServiceError> {
pub async fn probe(&self, client_id: String) -> Result<(), ServiceError> {
self.wait().await?;
Ok(self.manager_proxy.probe().await?)
Ok(self
.manager_proxy
.probe(HashMap::from([("client_id", &client_id.into())]))
.await?)
}

/// Starts the reprobing process.
pub async fn reprobe(&self) -> Result<(), ServiceError> {
pub async fn reprobe(&self, client_id: String) -> Result<(), ServiceError> {
self.wait().await?;
Ok(self.manager_proxy.reprobe().await?)
Ok(self
.manager_proxy
.reprobe(HashMap::from([("client_id", &client_id.into())]))
.await?)
}

/// Starts the installation.
Expand Down
12 changes: 7 additions & 5 deletions rust/agama-lib/src/monitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,9 @@ use std::collections::HashMap;
use tokio::sync::{broadcast, mpsc, oneshot};

use crate::{
http::{BaseHTTPClient, BaseHTTPClientError, Event, WebSocketClient, WebSocketError},
http::{
BaseHTTPClient, BaseHTTPClientError, Event, EventPayload, WebSocketClient, WebSocketError,
},
manager::{InstallationPhase, InstallerStatus},
progress::Progress,
};
Expand Down Expand Up @@ -223,16 +225,16 @@ impl Monitor {
///
/// * `event`: Agama event.
fn handle_event(&mut self, event: Event) {
match event {
Event::ProgressChanged { path, progress } => {
match event.payload {
EventPayload::ProgressChanged { path, progress } => {
self.status.update_progress(path, progress);
}
Event::ServiceStatusChanged { service, status } => {
EventPayload::ServiceStatusChanged { service, status } => {
if service.as_str() == MANAGER_PROGRESS_OBJECT_PATH {
self.status.set_is_busy(status == 1);
}
}
Event::InstallationPhaseChanged { phase } => {
EventPayload::InstallationPhaseChanged { phase } => {
self.status.set_phase(phase);
}
_ => {}
Expand Down
10 changes: 8 additions & 2 deletions rust/agama-lib/src/proxies/manager1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,16 @@ pub trait Manager1 {
fn finish(&self, method: &str) -> zbus::Result<bool>;

/// Probe method
fn probe(&self) -> zbus::Result<()>;
fn probe(
&self,
data: std::collections::HashMap<&str, &zbus::zvariant::Value<'_>>,
) -> zbus::Result<()>;

/// Reprobe method
fn reprobe(&self) -> zbus::Result<()>;
fn reprobe(
&self,
data: std::collections::HashMap<&str, &zbus::zvariant::Value<'_>>,
) -> zbus::Result<()>;

/// BusyServices property
#[zbus(property)]
Expand Down
Loading