Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create a ClientTrait for RustSDK #142

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
255 changes: 101 additions & 154 deletions databroker-cli/src/kuksa_cli.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/********************************************************************************
* Copyright (c) 2023 Contributors to the Eclipse Foundation
* Copyright (c) 2025 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
Expand All @@ -13,6 +13,7 @@

use databroker_proto::kuksa::val as proto;
use kuksa::*;
use kuksa_common::ClientTrait;

use prost_types::Timestamp;
use tokio_stream::StreamExt;
Expand Down Expand Up @@ -40,7 +41,7 @@ const CLI_COMMANDS: &[(&str, &str, &str)] = &[
("actuate", "<PATH> <VALUE>", "Set actuator signal"),
(
"subscribe",
"<QUERY>",
"<PATH> [[PATH] ...]",
"Subscribe to signals with QUERY, if you use kuksa feature comma separated list",
),
("publish", "<PATH> <VALUE>", "Publish signal value"),
Expand All @@ -67,6 +68,35 @@ fn print_usage(command: impl AsRef<str>) {
}
}

async fn handle_get_metadata(
paths: Vec<&str>,
client: &mut KuksaClient,
) -> Result<Option<Vec<DataEntry>>, Box<dyn std::error::Error>> {
match client
.get_metadata(
paths
.iter()
.map(|&s| s.to_string()) // Convert each &str to String
.collect(),
)
.await
{
Ok(data_entries) => Ok(Some(data_entries)),
Err(kuksa_common::ClientError::Status(status)) => {
cli::print_resp_err("get metadata", &status)?;
Ok(None)
}
Err(kuksa_common::ClientError::Connection(msg)) => {
cli::print_error("get metadata", msg)?;
Ok(None)
}
Err(kuksa_common::ClientError::Function(msg)) => {
cli::print_resp_err_fmt("get metadata", format_args!("Error {msg:?}"))?;
Ok(None)
}
}
}

async fn handle_actuate_command(
path: &str,
value: &str,
Expand All @@ -77,21 +107,7 @@ async fn handle_actuate_command(
return Ok(());
}

let datapoint_entries = match client.get_metadata(vec![path]).await {
Ok(data_entries) => Some(data_entries),
Err(ClientError::Status(status)) => {
cli::print_resp_err("metadata", &status)?;
None
}
Err(ClientError::Connection(msg)) => {
cli::print_error("metadata", msg)?;
None
}
Err(ClientError::Function(msg)) => {
cli::print_resp_err_fmt("actuate", format_args!("Error {msg:?}"))?;
None
}
};
let datapoint_entries = handle_get_metadata(vec![path], client).await.unwrap();

if let Some(entries) = datapoint_entries {
for entry in entries {
Expand Down Expand Up @@ -142,21 +158,7 @@ async fn handle_publish_command(
value: &str,
client: &mut KuksaClient,
) -> Result<(), Box<dyn std::error::Error>> {
let datapoint_entries = match client.get_metadata(vec![path]).await {
Ok(data_entries) => Some(data_entries),
Err(kuksa_common::ClientError::Status(status)) => {
cli::print_resp_err("metadata", &status)?;
None
}
Err(kuksa_common::ClientError::Connection(msg)) => {
cli::print_error("metadata", msg)?;
None
}
Err(kuksa_common::ClientError::Function(msg)) => {
cli::print_resp_err_fmt("publish", format_args!("Error {msg:?}"))?;
None
}
};
let datapoint_entries = handle_get_metadata(vec![path], client).await.unwrap();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't simply unwrapping the result here crash the application in case of an err? might be a rare case though as this only happens when cli::print_error(...) or prin_resp_err_fm fails - might be neglectable.


if let Some(entries) = datapoint_entries {
for entry in entries {
Expand Down Expand Up @@ -329,20 +331,9 @@ pub async fn kuksa_main(_cli: Cli) -> Result<(), Box<dyn std::error::Error>> {

let pattern = vec!["**"];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

optional: could be inlined


match client.get_metadata(pattern).await {
Ok(metadata) => {
interface
.set_completer(Arc::new(CliCompleter::from_metadata(&metadata)));
}
Err(kuksa_common::ClientError::Status(status)) => {
cli::print_resp_err("metadata", &status)?;
}
Err(kuksa_common::ClientError::Connection(msg)) => {
cli::print_error("metadata", msg)?;
}
Err(kuksa_common::ClientError::Function(msg)) => {
cli::print_resp_err_fmt("metadata", format_args!("Error {msg:?}"))?;
}
let data_entries = handle_get_metadata(pattern, &mut client).await?;
if let Some(entries) = data_entries {
interface.set_completer(Arc::new(CliCompleter::from_metadata(&entries)));
}
}
Err(err) => {
Expand Down Expand Up @@ -432,24 +423,12 @@ pub async fn kuksa_main(_cli: Cli) -> Result<(), Box<dyn std::error::Error>> {
match client.basic_client.set_access_token(args) {
Ok(()) => {
cli::print_info("Access token set.")?;
match client.get_metadata(vec![]).await {
Ok(metadata) => {
interface.set_completer(Arc::new(
CliCompleter::from_metadata(&metadata),
));
}
Err(kuksa_common::ClientError::Status(status)) => {
cli::print_resp_err("metadata", &status)?;
}
Err(kuksa_common::ClientError::Connection(msg)) => {
cli::print_error("metadata", msg)?;
}
Err(kuksa_common::ClientError::Function(msg)) => {
cli::print_resp_err_fmt(
"metadata",
format_args!("Error {msg:?}"),
)?;
}
if let Some(entries) =
handle_get_metadata(vec![], &mut client).await.unwrap()
{
interface.set_completer(Arc::new(
CliCompleter::from_metadata(&entries),
));
}
}
Err(err) => {
Expand All @@ -470,24 +449,12 @@ pub async fn kuksa_main(_cli: Cli) -> Result<(), Box<dyn std::error::Error>> {
Ok(token) => match client.basic_client.set_access_token(token) {
Ok(()) => {
cli::print_info("Access token set.")?;
match client.get_metadata(vec![]).await {
Ok(metadata) => {
interface.set_completer(Arc::new(
CliCompleter::from_metadata(&metadata),
));
}
Err(kuksa_common::ClientError::Status(status)) => {
cli::print_resp_err("metadata", &status)?;
}
Err(kuksa_common::ClientError::Connection(msg)) => {
cli::print_error("metadata", msg)?;
}
Err(kuksa_common::ClientError::Function(msg)) => {
cli::print_resp_err_fmt(
cmd,
format_args!("Error {msg:?}"),
)?;
}
if let Some(entries) =
handle_get_metadata(vec![], &mut client).await.unwrap()
{
interface.set_completer(Arc::new(
CliCompleter::from_metadata(&entries),
));
}
}
Err(err) => {
Expand Down Expand Up @@ -536,7 +503,15 @@ pub async fn kuksa_main(_cli: Cli) -> Result<(), Box<dyn std::error::Error>> {

let input = args.split_whitespace().collect::<Vec<_>>();

match client.subscribe(input).await {
match client
.subscribe(
input
.iter()
.map(|&s| s.to_string()) // Convert each &str to String
.collect(),
)
.await
{
Ok(mut subscription) => {
let iface = interface.clone();
tokio::spawn(async move {
Expand Down Expand Up @@ -684,24 +659,12 @@ pub async fn kuksa_main(_cli: Cli) -> Result<(), Box<dyn std::error::Error>> {
}
};
if client.basic_client.is_connected() {
match client.get_metadata(vec!["**"]).await {
Ok(metadata) => {
interface.set_completer(Arc::new(
CliCompleter::from_metadata(&metadata),
));
}
Err(kuksa_common::ClientError::Status(status)) => {
cli::print_resp_err("metadata", &status)?;
}
Err(kuksa_common::ClientError::Connection(msg)) => {
cli::print_error("metadata", msg)?;
}
Err(kuksa_common::ClientError::Function(msg)) => {
cli::print_resp_err_fmt(
cmd,
format_args!("Error {msg:?}"),
)?;
}
if let Some(entries) =
handle_get_metadata(vec!["**"], &mut client).await.unwrap()
{
interface.set_completer(Arc::new(
CliCompleter::from_metadata(&entries),
));
}
}
};
Expand All @@ -713,63 +676,47 @@ pub async fn kuksa_main(_cli: Cli) -> Result<(), Box<dyn std::error::Error>> {

if paths.is_empty() {
cli::print_info("If you want to list metadata of signals, use `metadata PATTERN`")?;
} else {
match client.get_metadata(paths).await {
Ok(metadata) => {
cli::print_resp_ok(cmd)?;
if !metadata.is_empty() {
let max_len_path =
metadata.iter().fold(0, |mut max_len, item| {
if item.path.len() > max_len {
max_len = item.path.len();
}
max_len
});
} else if let Some(entries) =
handle_get_metadata(paths, &mut client).await.unwrap()
{
cli::print_resp_ok(cmd)?;
if !entries.is_empty() {
let max_len_path =
entries.iter().fold(0, |mut max_len, item| {
if item.path.len() > max_len {
max_len = item.path.len();
}
max_len
});

cli::print_info(format!(
"{:<max_len_path$} {:<10} {:<9}",
"Path", "Entry type", "Data type"
))?;
cli::print_info(format!(
"{:<max_len_path$} {:<10} {:<9}",
"Path", "Entry type", "Data type"
))?;

for entry in &metadata {
if let Some(entry_metadata) = &entry.metadata {
println!(
"{:<max_len_path$} {:<10} {:<9}",
entry.path,
DisplayEntryType::from(
proto::v1::EntryType::try_from(
entry_metadata.entry_type
)
.ok()
),
DisplayDataType::from(
proto::v1::DataType::try_from(
entry_metadata.data_type
)
.ok()
),
);
} else {
let name = entry.path.clone();
println!("No entry metadata for {name}");
}
}
for entry in &entries {
if let Some(entry_metadata) = &entry.metadata {
println!(
"{:<max_len_path$} {:<10} {:<9}",
entry.path,
DisplayEntryType::from(
proto::v1::EntryType::try_from(
entry_metadata.entry_type
)
.ok()
),
DisplayDataType::from(
proto::v1::DataType::try_from(
entry_metadata.data_type
)
.ok()
),
);
} else {
let name = entry.path.clone();
println!("No entry metadata for {name}");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
println!("No entry metadata for {name}");
println!("No metadata entry for {name}");

}
}
Err(kuksa_common::ClientError::Status(status)) => {
cli::print_resp_err(cmd, &status)?;
continue;
}
Err(kuksa_common::ClientError::Connection(msg)) => {
cli::print_error(cmd, msg)?;
continue;
}
Err(kuksa_common::ClientError::Function(msg)) => {
cli::print_resp_err_fmt(
cmd,
format_args!("Error {msg:?}"),
)?;
}
}
}
}
Expand Down
5 changes: 3 additions & 2 deletions databroker-cli/src/sdv_cli.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/********************************************************************************
* Copyright (c) 2023 Contributors to the Eclipse Foundation
* Copyright (c) 2025 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
Expand All @@ -12,6 +12,7 @@
********************************************************************************/

use databroker_proto::sdv::databroker as proto;
use kuksa_common::ClientTrait;
use kuksa_sdv::*;

use prost_types::Timestamp;
Expand Down Expand Up @@ -451,7 +452,7 @@ pub async fn sdv_main(_cli: Cli) -> Result<(), Box<dyn std::error::Error>> {
}
let ts = Timestamp::from(SystemTime::now());
let datapoints = HashMap::from([(
metadata.id,
metadata.name.clone(),
proto::v1::Datapoint {
timestamp: Some(ts),
value: Some(data_value.unwrap()),
Expand Down
3 changes: 2 additions & 1 deletion databroker/tests/read_write_values.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/********************************************************************************
* Copyright (c) 2023 Contributors to the Eclipse Foundation
* Copyright (c) 2025 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
Expand All @@ -17,6 +17,7 @@ use std::{collections::HashMap, future, time::SystemTime, vec};
use cucumber::{cli, gherkin::Step, given, then, when, writer, World as _};
use databroker::broker;
use databroker_proto::kuksa::val::v1::{datapoint::Value, DataType, Datapoint};
use kuksa_common::ClientTrait;
use tracing::debug;
use world::{DataBrokerWorld, ValueType};

Expand Down
Loading
Loading