Proto selection UI/models

This commit is contained in:
Gregory Schier
2024-02-06 12:29:23 -08:00
parent c85a11edf1
commit 562a36d616
28 changed files with 382 additions and 154 deletions

View File

@@ -1,8 +1,5 @@
use prost_reflect::SerializeOptions;
use serde::{Deserialize, Serialize};
use tonic::transport::Uri;
use crate::proto::fill_pool;
mod codec;
mod json_schema;
@@ -28,31 +25,3 @@ pub struct MethodDefinition {
pub client_streaming: bool,
pub server_streaming: bool,
}
pub async fn reflect(uri: &Uri) -> Result<Vec<ServiceDefinition>, String> {
let (pool, _) = fill_pool(uri).await?;
Ok(pool
.services()
.map(|s| {
let mut def = ServiceDefinition {
name: s.full_name().to_string(),
methods: vec![],
};
for method in s.methods() {
let input_message = method.input();
def.methods.push(MethodDefinition {
name: method.name().to_string(),
server_streaming: method.is_server_streaming(),
client_streaming: method.is_client_streaming(),
schema: serde_json::to_string_pretty(&json_schema::message_to_json_schema(
&pool,
input_message,
))
.unwrap(),
})
}
def
})
.collect::<Vec<_>>())
}

View File

@@ -6,7 +6,6 @@ use hyper_rustls::HttpsConnector;
use prost_reflect::DescriptorPool;
pub use prost_reflect::DynamicMessage;
use serde_json::Deserializer;
use tokio::sync::mpsc;
use tokio_stream::wrappers::ReceiverStream;
use tokio_stream::StreamExt;
use tonic::body::BoxBody;
@@ -15,6 +14,7 @@ use tonic::{IntoRequest, IntoStreamingRequest, Streaming};
use crate::codec::DynamicCodec;
use crate::proto::{fill_pool, method_desc_to_path};
use crate::{json_schema, MethodDefinition, ServiceDefinition};
type Result<T> = std::result::Result<T, String>;
@@ -145,25 +145,61 @@ impl GrpcConnection {
}
}
pub struct GrpcManager {
pub struct GrpcHandle {
connections: HashMap<String, GrpcConnection>,
pub send: mpsc::Sender<String>,
pub recv: mpsc::Receiver<String>,
pools: HashMap<String, DescriptorPool>,
}
impl Default for GrpcManager {
impl Default for GrpcHandle {
fn default() -> Self {
let (send, recv) = mpsc::channel(100);
let connections = HashMap::new();
Self {
connections,
send,
recv,
}
let pools = HashMap::new();
Self { connections, pools }
}
}
impl GrpcManager {
impl GrpcHandle {
pub async fn clean_reflect(&mut self, uri: &Uri) -> Result<Vec<ServiceDefinition>> {
self.pools.remove(&uri.to_string());
self.reflect(uri).await
}
pub async fn reflect(&mut self, uri: &Uri) -> Result<Vec<ServiceDefinition>> {
let pool = match self.pools.get(&uri.to_string()) {
Some(p) => p.clone(),
None => {
let (pool, _) = fill_pool(uri).await?;
self.pools.insert(uri.to_string(), pool.clone());
pool
}
};
let result =
pool.services()
.map(|s| {
let mut def = ServiceDefinition {
name: s.full_name().to_string(),
methods: vec![],
};
for method in s.methods() {
let input_message = method.input();
def.methods.push(MethodDefinition {
name: method.name().to_string(),
server_streaming: method.is_server_streaming(),
client_streaming: method.is_client_streaming(),
schema: serde_json::to_string_pretty(
&json_schema::message_to_json_schema(&pool, input_message),
)
.unwrap(),
})
}
def
})
.collect::<Vec<_>>();
Ok(result)
}
pub async fn server_streaming(
&mut self,
id: &str,

View File

@@ -1,4 +1,5 @@
use std::ops::Deref;
use std::path::PathBuf;
use std::str::FromStr;
use anyhow::anyhow;
@@ -9,17 +10,27 @@ use log::warn;
use prost::Message;
use prost_reflect::{DescriptorPool, MethodDescriptor};
use prost_types::FileDescriptorProto;
use tokio::fs;
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;
use tonic_reflection::pb::server_reflection_response::MessageResponse;
use tonic_reflection::pb::ServerReflectionRequest;
pub async fn fill_pool_from_files(paths: Vec<PathBuf>) -> Result<DescriptorPool, String> {
let mut pool = DescriptorPool::new();
for p in paths {
let bytes = fs::read(p).await.unwrap();
let fdp = FileDescriptorProto::decode(bytes.deref()).unwrap();
pool.add_file_descriptor_proto(fdp)
.map_err(|e| e.to_string())?;
}
Ok(pool)
}
pub async fn fill_pool(
uri: &Uri,
) -> Result<
@@ -155,7 +166,9 @@ async fn send_reflection_request(
.server_reflection_info(request)
.await
.map_err(|e| match e.code() {
Unimplemented => "Reflection not implemented for server".to_string(),
tonic::Code::Unavailable => "Failed to connect to endpoint".to_string(),
tonic::Code::Unauthenticated => "Authentication failed".to_string(),
tonic::Code::DeadlineExceeded => "Deadline exceeded".to_string(),
_ => e.to_string(),
})?
.into_inner()