Better reflect failure UI

This commit is contained in:
Gregory Schier
2024-02-05 14:50:47 -08:00
parent 63a381c55a
commit 8309c19167
13 changed files with 584 additions and 395 deletions

View File

@@ -29,10 +29,11 @@ pub struct MethodDefinition {
pub server_streaming: bool,
}
pub async fn reflect(uri: &Uri) -> Vec<ServiceDefinition> {
let (pool, _) = fill_pool(uri).await;
pub async fn reflect(uri: &Uri) -> Result<Vec<ServiceDefinition>, String> {
let (pool, _) = fill_pool(uri).await?;
pool.services()
Ok(pool
.services()
.map(|s| {
let mut def = ServiceDefinition {
name: s.full_name().to_string(),
@@ -53,5 +54,5 @@ pub async fn reflect(uri: &Uri) -> Vec<ServiceDefinition> {
}
def
})
.collect::<Vec<_>>()
.collect::<Vec<_>>())
}

View File

@@ -173,7 +173,7 @@ impl GrpcManager {
message: &str,
) -> Result<Streaming<DynamicMessage>> {
self.connect(id, uri)
.await
.await?
.server_streaming(service, method, message)
.await
}
@@ -187,7 +187,7 @@ impl GrpcManager {
stream: ReceiverStream<String>,
) -> Result<DynamicMessage> {
self.connect(id, uri)
.await
.await?
.client_streaming(service, method, stream)
.await
}
@@ -201,15 +201,15 @@ impl GrpcManager {
stream: ReceiverStream<String>,
) -> Result<Streaming<DynamicMessage>> {
self.connect(id, uri)
.await
.await?
.streaming(service, method, stream)
.await
}
pub async fn connect(&mut self, id: &str, uri: Uri) -> GrpcConnection {
let (pool, conn) = fill_pool(&uri).await;
pub async fn connect(&mut self, id: &str, uri: Uri) -> Result<GrpcConnection> {
let (pool, conn) = fill_pool(&uri).await?;
let connection = GrpcConnection { pool, conn, uri };
self.connections.insert(id.to_string(), connection.clone());
connection
Ok(connection)
}
}

View File

@@ -5,6 +5,7 @@ use anyhow::anyhow;
use hyper::client::HttpConnector;
use hyper::Client;
use hyper_rustls::{HttpsConnector, HttpsConnectorBuilder};
use log::warn;
use prost::Message;
use prost_reflect::{DescriptorPool, MethodDescriptor};
use prost_types::FileDescriptorProto;
@@ -12,6 +13,7 @@ use tokio_stream::StreamExt;
use tonic::body::BoxBody;
use tonic::codegen::http::uri::PathAndQuery;
use tonic::transport::Uri;
use tonic::Code::Unimplemented;
use tonic::Request;
use tonic_reflection::pb::server_reflection_client::ServerReflectionClient;
use tonic_reflection::pb::server_reflection_request::MessageRequest;
@@ -20,10 +22,13 @@ use tonic_reflection::pb::ServerReflectionRequest;
pub async fn fill_pool(
uri: &Uri,
) -> (
DescriptorPool,
Client<HttpsConnector<HttpConnector>, BoxBody>,
) {
) -> Result<
(
DescriptorPool,
Client<HttpsConnector<HttpConnector>, BoxBody>,
),
String,
> {
let mut pool = DescriptorPool::new();
let connector = HttpsConnectorBuilder::new().with_native_roots();
let connector = connector.https_or_http().enable_http2().wrap_connector({
@@ -37,34 +42,33 @@ pub async fn fill_pool(
.build(connector);
let mut client = ServerReflectionClient::with_origin(transport.clone(), uri.clone());
let services = list_services(&mut client).await;
for service in services {
for service in list_services(&mut client).await? {
if service == "grpc.reflection.v1alpha.ServerReflection" {
continue;
}
file_descriptor_set_from_service_name(&service, &mut pool, &mut client).await;
}
(pool, transport)
Ok((pool, transport))
}
async fn list_services(
reflect_client: &mut ServerReflectionClient<Client<HttpsConnector<HttpConnector>, BoxBody>>,
) -> Vec<String> {
) -> Result<Vec<String>, String> {
let response =
send_reflection_request(reflect_client, MessageRequest::ListServices("".into())).await;
send_reflection_request(reflect_client, MessageRequest::ListServices("".into())).await?;
let list_services_response = match response {
MessageResponse::ListServicesResponse(resp) => resp,
_ => panic!("Expected a ListServicesResponse variant"),
};
list_services_response
Ok(list_services_response
.service
.iter()
.map(|s| s.name.clone())
.collect::<Vec<_>>()
.collect::<Vec<_>>())
}
async fn file_descriptor_set_from_service_name(
@@ -72,11 +76,21 @@ async fn file_descriptor_set_from_service_name(
pool: &mut DescriptorPool,
client: &mut ServerReflectionClient<Client<HttpsConnector<HttpConnector>, BoxBody>>,
) {
let response = send_reflection_request(
let response = match send_reflection_request(
client,
MessageRequest::FileContainingSymbol(service_name.into()),
)
.await;
.await
{
Ok(resp) => resp,
Err(e) => {
warn!(
"Error fetching file descriptor for service {}: {}",
service_name, e
);
return;
}
};
let file_descriptor_response = match response {
MessageResponse::FileDescriptorResponse(resp) => resp,
@@ -109,8 +123,14 @@ async fn file_descriptor_set_by_filename(
let response =
send_reflection_request(client, MessageRequest::FileByFilename(filename.into())).await;
let file_descriptor_response = match response {
MessageResponse::FileDescriptorResponse(resp) => resp,
_ => panic!("Expected a FileDescriptorResponse variant"),
Ok(MessageResponse::FileDescriptorResponse(resp)) => resp,
Ok(_) => {
panic!("Expected a FileDescriptorResponse variant")
}
Err(e) => {
warn!("Error fetching file descriptor for {}: {}", filename, e);
return;
}
};
for fd in file_descriptor_response.file_descriptor_proto {
@@ -123,7 +143,7 @@ async fn file_descriptor_set_by_filename(
async fn send_reflection_request(
client: &mut ServerReflectionClient<Client<HttpsConnector<HttpConnector>, BoxBody>>,
message: MessageRequest,
) -> MessageResponse {
) -> Result<MessageResponse, String> {
let reflection_request = ServerReflectionRequest {
host: "".into(), // Doesn't matter
message_request: Some(message),
@@ -134,14 +154,17 @@ async fn send_reflection_request(
client
.server_reflection_info(request)
.await
.expect("server reflection failed")
.map_err(|e| match e.code() {
Unimplemented => "Reflection not implemented for server".to_string(),
_ => e.to_string(),
})?
.into_inner()
.next()
.await
.expect("steamed response")
.expect("successful response")
.map_err(|e| e.to_string())?
.message_response
.expect("some MessageResponse")
.ok_or("No reflection response".to_string())
}
pub fn method_desc_to_path(md: &MethodDescriptor) -> PathAndQuery {

View File

@@ -100,7 +100,7 @@ async fn cmd_grpc_reflect(
.await
.map_err(|e| e.to_string())?;
let uri = safe_uri(&req.url).map_err(|e| e.to_string())?;
Ok(grpc::reflect(&uri).await)
grpc::reflect(&uri).await
}
#[tauri::command]
@@ -150,7 +150,7 @@ async fn cmd_grpc_call_unary(
.lock()
.await
.connect(&conn.clone().id, uri)
.await
.await?
.unary(
&req.service.unwrap_or_default(),
&req.method.unwrap_or_default(),