use std::collections::HashMap;
use tonic::{Request, Response, Status};
use crate::proto::service as proto;
pub use proto::mav_inspect_service_server::MavInspectServiceServer;
use proto::mav_inspect_service_server::MavInspectService;
use proto::{
GetDialectRequest, GetDialectResponse, GetProtocolRequest, GetProtocolResponse,
ListDialectsRequest, ListDialectsResponse,
};
use crate::proto::mavlink_messages_v1::{Dialect, Protocol};
use crate::proto::service::{
EnumSummary, GetDialectSummaryRequest, GetDialectSummaryResponse, GetEnumRequest,
GetEnumResponse, GetMessageRequest, GetMessageResponse, ListDialectEnumsRequest,
ListDialectEnumsResponse, ListDialectMessagesRequest, ListDialectMessagesResponse,
MessageSummary,
};
#[derive(Default)]
pub struct MavInspectServerImplementation {
protocol: Protocol,
}
impl MavInspectServerImplementation {
pub fn new(protocol: Protocol) -> Self {
Self { protocol }
}
fn dialect_names(&self) -> Vec<String> {
self.protocol
.dialects
.keys()
.cloned()
.collect::<Vec<String>>()
}
fn dialect_message_summaries(dialect: &Dialect) -> HashMap<u32, MessageSummary> {
dialect
.messages
.iter()
.map(|(&id, msg)| {
(
id,
MessageSummary {
id: msg.id,
name: msg.name.clone(),
description: msg.description.clone(),
wip: msg.wip,
defined_in: msg.defined_in.clone(),
},
)
})
.collect()
}
fn dialect_enum_summaries(dialect: &Dialect) -> HashMap<String, EnumSummary> {
dialect
.enums
.iter()
.map(|(name, enm)| {
(
name.clone(),
EnumSummary {
name: enm.name.clone(),
description: enm.description.clone(),
bitmask: enm.bitmask,
defined_in: enm.defined_in.clone(),
},
)
})
.collect()
}
}
#[tonic::async_trait]
impl MavInspectService for MavInspectServerImplementation {
async fn get_protocol(
&self,
request: Request<GetProtocolRequest>,
) -> Result<Response<GetProtocolResponse>, Status> {
println!("Got GetProtocolRequest from {:?}", request.remote_addr());
let reply = GetProtocolResponse {
protocol: Some(self.protocol.clone()),
};
Ok(Response::new(reply))
}
async fn list_dialects(
&self,
request: Request<ListDialectsRequest>,
) -> Result<Response<ListDialectsResponse>, Status> {
println!("Got ListDialectsRequest from {:?}", request.remote_addr());
let reply = ListDialectsResponse {
dialects: self.dialect_names(),
};
Ok(Response::new(reply))
}
async fn get_dialect(
&self,
request: Request<GetDialectRequest>,
) -> Result<Response<GetDialectResponse>, Status> {
println!("Got GetDialectRequest from {:?}", request.remote_addr());
let name = request.into_inner().name;
match self.protocol.dialects.get(&name) {
None => Err(Status::not_found(
format!(
"Dialect \"{name}\" is not present in protocol. Available options: {:?}",
self.dialect_names()
)
.as_str()
.to_string(),
)),
Some(dialect) => Ok(Response::new(GetDialectResponse {
dialect: Some(dialect.clone()),
})),
}
}
async fn get_dialect_summary(
&self,
request: Request<GetDialectSummaryRequest>,
) -> Result<Response<GetDialectSummaryResponse>, Status> {
println!(
"Got GetDialectSummaryRequest from {:?}",
request.remote_addr()
);
let name = request.into_inner().name;
match self.protocol.dialects.get(&name) {
None => Err(Status::not_found(
format!(
"Dialect \"{name}\" is not present in protocol. Available options: {:?}",
self.dialect_names()
)
.as_str()
.to_string(),
)),
Some(dialect) => Ok(Response::new(GetDialectSummaryResponse {
name,
version: dialect.version,
dialect: dialect.dialect,
messages: MavInspectServerImplementation::dialect_message_summaries(dialect),
enums: MavInspectServerImplementation::dialect_enum_summaries(dialect),
})),
}
}
async fn list_dialect_messages(
&self,
request: Request<ListDialectMessagesRequest>,
) -> Result<Response<ListDialectMessagesResponse>, Status> {
println!(
"Got ListDialectMessagesRequest from {:?}",
request.remote_addr()
);
let name = request.into_inner().dialect_name;
match self.protocol.dialects.get(&name) {
None => Err(Status::not_found(
format!(
"Dialect \"{name}\" is not present in protocol. Available options: {:?}",
self.dialect_names()
)
.as_str()
.to_string(),
)),
Some(dialect) => Ok(Response::new(ListDialectMessagesResponse {
messages: MavInspectServerImplementation::dialect_message_summaries(dialect),
})),
}
}
async fn get_message(
&self,
request: Request<GetMessageRequest>,
) -> Result<Response<GetMessageResponse>, Status> {
println!("Got GetMessageRequest from {:?}", request.remote_addr());
let req = request.into_inner();
let dialect_name = req.dialect_name;
let message_id = req.message_id;
match self.protocol.dialects.get(&dialect_name) {
None => Err(Status::not_found(
format!(
"Dialect \"{dialect_name}\" is not present in protocol. Available options: {:?}",
self.dialect_names()
)
.as_str()
.to_string(),
)),
Some(dialect) => match dialect.messages.get(&message_id) {
None => Err(Status::not_found(
format!(
"Dialect \"{dialect_name}\" does not have message with ID={message_id}."
)
.as_str()
.to_string(),
)),
Some(message) => Ok(Response::new(GetMessageResponse {
message: Some(message.clone()),
})),
},
}
}
async fn list_dialect_enums(
&self,
request: Request<ListDialectEnumsRequest>,
) -> Result<Response<ListDialectEnumsResponse>, Status> {
println!(
"Got ListDialectEnumsRequest from {:?}",
request.remote_addr()
);
let name = request.into_inner().dialect_name;
match self.protocol.dialects.get(&name) {
None => Err(Status::not_found(
format!(
"Dialect \"{name}\" is not present in protocol. Available options: {:?}",
self.dialect_names()
)
.as_str()
.to_string(),
)),
Some(dialect) => Ok(Response::new(ListDialectEnumsResponse {
enums: MavInspectServerImplementation::dialect_enum_summaries(dialect),
})),
}
}
async fn get_enum(
&self,
request: Request<GetEnumRequest>,
) -> Result<Response<GetEnumResponse>, Status> {
println!("Got GetMessageRequest from {:?}", request.remote_addr());
let req = request.into_inner();
let dialect_name = req.dialect_name;
let enum_name = req.enum_name;
match self.protocol.dialects.get(&dialect_name) {
None => Err(Status::not_found(
format!(
"Dialect \"{dialect_name}\" is not present in protocol. Available options: {:?}",
self.dialect_names()
)
.as_str()
.to_string(),
)),
Some(dialect) => match dialect.enums.get(&enum_name) {
None => Err(Status::not_found(
format!(
"Dialect \"{dialect_name}\" does not have enum named \"{enum_name}\"."
)
.as_str()
.to_string(),
)),
Some(enm) => Ok(Response::new(GetEnumResponse {
r#enum: Some(enm.clone()),
})),
},
}
}
}