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

[RSDK-9887] get agent config from app #417

Merged
merged 12 commits into from
Feb 20, 2025
52 changes: 49 additions & 3 deletions micro-rdk/src/common/app_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,15 @@
use crate::proto::app::v1::CertificateRequest;
use crate::proto::app::v1::CertificateResponse;
use crate::proto::{
app::v1::{
AgentInfo, ConfigRequest, ConfigResponse, LogRequest, NeedsRestartRequest,
NeedsRestartResponse,
app::{
agent::v1::{
DeviceAgentConfigRequest, DeviceAgentConfigResponse, DeviceSubsystemConfig, HostInfo,
VersionInfo,
},
v1::{
AgentInfo, ConfigRequest, ConfigResponse, LogRequest, NeedsRestartRequest,
NeedsRestartResponse,
},
},
common::v1::LogEntry,
rpc::{
Expand Down Expand Up @@ -323,6 +329,46 @@ impl AppClient {
Ok((Box::new(cfg_response), datetime))
}

pub async fn get_agent_config(&self) -> Result<Box<DeviceAgentConfigResponse>, AppClientError> {
let host_info = Some(HostInfo {
platform: "micro-rdk/esp32".to_string(),
distro: "esp32".to_string(),
tags: Default::default(),
});

let version_info = Some(VersionInfo {
agent_running: "none".to_string(),
Copy link
Member

Choose a reason for hiding this comment

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

What happens if we just don't set agent_running?

..Default::default()
});

let req = DeviceAgentConfigRequest {
id: self.robot_credentials.robot_id.clone(),
host_info,
version_info,
..Default::default()
};
let body = encode_request(req)?;

let r = self
.grpc_client
.build_request(
"/viam.app.agent.v1.AgentDeviceService/DeviceAgentConfig",
Some(&self.jwt),
"",
BodyExt::boxed(Full::new(body).map_err(|never| match never {})),
)
.map_err(AppClientError::AppGrpcClientError)?;

let (mut r, headers) = self.grpc_client.send_request(r).await?;

if r.is_empty() {
return Err(AppClientError::AppClientEmptyBody);
}
let cfg_response = DeviceAgentConfigResponse::decode(r.split_off(5))?;

Ok(Box::new(cfg_response))
}

pub async fn push_logs(&self, logs: Vec<LogEntry>) -> Result<(), AppClientError> {
let req = LogRequest {
id: self.robot_credentials.robot_id.clone(),
Expand Down
71 changes: 70 additions & 1 deletion micro-rdk/src/common/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
#[cfg(feature = "data")]
use crate::common::data_collector::DataCollectorConfig;
use crate::google;
use crate::proto::{app::v1::ComponentConfig, common::v1::ResourceName};
use crate::proto::{
app::{agent::v1::DeviceAgentConfigResponse, v1::ComponentConfig},
common::v1::ResourceName,
};

use std::collections::HashMap;
use std::num::{ParseFloatError, ParseIntError};
Expand Down Expand Up @@ -404,6 +407,72 @@ impl Component for DynamicComponentConfig {
}
}

#[derive(Debug)]
pub struct AgentConfig {
pub network_settings: Vec<NetworkSetting>,
}

impl TryFrom<&DeviceAgentConfigResponse> for AgentConfig {
type Error = AttributeError;
fn try_from(value: &DeviceAgentConfigResponse) -> Result<Self, Self::Error> {
if let Some(additional_networks) = &value.additional_networks {
let network_settings = additional_networks
.fields
.iter()
.filter_map(|(_k, v)| {
let local_kind: Option<Kind> =
v.kind.clone().and_then(|v| Kind::try_from(v).ok());
local_kind
.as_ref()
.and_then(|v| NetworkSetting::try_from(v).ok())
})
.collect::<Vec<NetworkSetting>>();
Ok(Self { network_settings })
} else {
Err(AttributeError::ConversionImpossibleError)
}
}
}

pub struct NetworkSetting {
ssid: String,
password: String,
priority: i32,
}

impl TryFrom<&Kind> for NetworkSetting {
type Error = AttributeError;
fn try_from(value: &Kind) -> Result<Self, Self::Error> {
let ssid: String = value
.get("ssid")?
.ok_or(AttributeError::ConversionImpossibleError)?
.try_into()?;
let password: String = value
.get("psk")?
.ok_or(AttributeError::ConversionImpossibleError)?
.try_into()?;
let priority: i32 = value
.get("priority")?
.ok_or(AttributeError::ConversionImpossibleError)?
.try_into()?;
Ok(Self {
ssid,
password,
priority,
})
}
}

impl std::fmt::Debug for NetworkSetting {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"NetworkSetting {{ ssid: {}, password: ***, priority: {} }}",
self.ssid, self.priority
)
}
}

#[cfg(test)]
mod tests {
use std::collections::HashMap;
Expand Down
15 changes: 15 additions & 0 deletions micro-rdk/src/common/conn/viam.rs
Original file line number Diff line number Diff line change
Expand Up @@ -558,6 +558,21 @@ where
None => None,
};

// TODO(RSDK-9887): remove after implementing agent NVS storage
if let Some(app) = app_client.as_ref() {
use crate::common::config::AgentConfig;
if let Ok(device_agent_config) = app.get_agent_config().await {
let agent_config: AgentConfig =
device_agent_config
.as_ref()
.try_into()
.unwrap_or(AgentConfig {
network_settings: Vec::new(),
});
log::debug!("agent config: {:?}", agent_config);
}
}

let (config, build_time) = config.map_or_else(
|| {
(
Expand Down
5 changes: 5 additions & 0 deletions micro-rdk/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,11 @@ pub mod proto {
pub mod v1 {
include!("gen/viam.app.v1.rs");
}
pub mod agent {
pub mod v1 {
include!("gen/viam.app.agent.v1.rs");
}
}
pub mod packages {
pub mod v1 {
include!("gen/viam.app.packages.v1.rs");
Expand Down