use std::collections::HashMap;
use std::fmt::{Display, Formatter};
use std::sync::Arc;
use prost::encoding::{WireType, decode_key, decode_varint};
use prost::{DecodeError, Message};
use prost_types::{
DescriptorProto, EnumDescriptorProto, FieldDescriptorProto, FileDescriptorProto,
FileDescriptorSet,
};
use tonic::Status;
pub mod v1;
pub mod v1alpha;
#[derive(Debug)]
pub struct Builder<'b> {
file_descriptor_sets: Vec<FileDescriptorSet>,
encoded_file_descriptor_sets: Vec<&'b [u8]>,
include_reflection_service: bool,
service_names: Vec<String>,
use_all_service_names: bool,
}
impl<'b> Builder<'b> {
pub fn configure() -> Self {
Builder {
file_descriptor_sets: Vec::new(),
encoded_file_descriptor_sets: Vec::new(),
include_reflection_service: true,
service_names: Vec::new(),
use_all_service_names: true,
}
}
pub fn register_file_descriptor_set(mut self, file_descriptor_set: FileDescriptorSet) -> Self {
self.file_descriptor_sets.push(file_descriptor_set);
self
}
pub fn register_encoded_file_descriptor_set(
mut self,
encoded_file_descriptor_set: &'b [u8],
) -> Self {
self.encoded_file_descriptor_sets
.push(encoded_file_descriptor_set);
self
}
pub fn include_reflection_service(mut self, include: bool) -> Self {
self.include_reflection_service = include;
self
}
pub fn with_service_name(mut self, name: impl Into<String>) -> Self {
self.use_all_service_names = false;
self.service_names.push(name.into());
self
}
pub fn build_v1(
mut self,
) -> Result<v1::ServerReflectionServer<impl v1::ServerReflection>, Error> {
if self.include_reflection_service {
self = self.register_encoded_file_descriptor_set(crate::pb::v1::FILE_DESCRIPTOR_SET);
}
Ok(v1::ServerReflectionServer::new(
v1::ReflectionService::from(ReflectionServiceState::new(
self.service_names,
self.encoded_file_descriptor_sets,
self.file_descriptor_sets,
self.use_all_service_names,
)?),
))
}
pub fn build_v1alpha(
mut self,
) -> Result<v1alpha::ServerReflectionServer<impl v1alpha::ServerReflection>, Error> {
if self.include_reflection_service {
self =
self.register_encoded_file_descriptor_set(crate::pb::v1alpha::FILE_DESCRIPTOR_SET);
}
Ok(v1alpha::ServerReflectionServer::new(
v1alpha::ReflectionService::from(ReflectionServiceState::new(
self.service_names,
self.encoded_file_descriptor_sets,
self.file_descriptor_sets,
self.use_all_service_names,
)?),
))
}
}
#[derive(Debug)]
struct ReflectionServiceState {
service_names: Vec<String>,
files: HashMap<String, Arc<[u8]>>,
symbols: HashMap<String, Arc<[u8]>>,
}
impl ReflectionServiceState {
fn new(
service_names: Vec<String>,
encoded_file_descriptor_sets: Vec<&[u8]>,
file_descriptor_sets: Vec<FileDescriptorSet>,
use_all_service_names: bool,
) -> Result<Self, Error> {
let mut state = ReflectionServiceState {
service_names,
files: HashMap::new(),
symbols: HashMap::new(),
};
for encoded in encoded_file_descriptor_sets {
for raw in split_file_descriptor_set(encoded)? {
let fd = FileDescriptorProto::decode(raw.as_slice())?;
state.register_file(&fd, Arc::from(raw), use_all_service_names)?;
}
}
for fds in file_descriptor_sets {
for fd in fds.file {
let raw = fd.encode_to_vec();
state.register_file(&fd, Arc::from(raw), use_all_service_names)?;
}
}
Ok(state)
}
fn register_file(
&mut self,
fd: &FileDescriptorProto,
raw: Arc<[u8]>,
use_all_service_names: bool,
) -> Result<(), Error> {
let name = match fd.name.clone() {
None => {
return Err(Error::InvalidFileDescriptorSet("missing name".to_string()));
}
Some(n) => n,
};
if self.files.contains_key(&name) {
return Ok(());
}
self.files.insert(name, raw.clone());
self.process_file(fd, &raw, use_all_service_names)
}
fn process_file(
&mut self,
fd: &FileDescriptorProto,
raw: &Arc<[u8]>,
use_all_service_names: bool,
) -> Result<(), Error> {
let prefix = &fd.package.clone().unwrap_or_default();
for msg in &fd.message_type {
self.process_message(raw, prefix, msg)?;
}
for en in &fd.enum_type {
self.process_enum(raw, prefix, en)?;
}
for service in &fd.service {
let service_name = extract_name(prefix, "service", service.name.as_ref())?;
if use_all_service_names {
self.service_names.push(service_name.clone());
}
self.symbols.insert(service_name.clone(), raw.clone());
for method in &service.method {
let method_name = extract_name(&service_name, "method", method.name.as_ref())?;
self.symbols.insert(method_name, raw.clone());
}
}
Ok(())
}
fn process_message(
&mut self,
raw: &Arc<[u8]>,
prefix: &str,
msg: &DescriptorProto,
) -> Result<(), Error> {
let message_name = extract_name(prefix, "message", msg.name.as_ref())?;
self.symbols.insert(message_name.clone(), raw.clone());
for nested in &msg.nested_type {
self.process_message(raw, &message_name, nested)?;
}
for en in &msg.enum_type {
self.process_enum(raw, &message_name, en)?;
}
for field in &msg.field {
self.process_field(raw, &message_name, field)?;
}
for oneof in &msg.oneof_decl {
let oneof_name = extract_name(&message_name, "oneof", oneof.name.as_ref())?;
self.symbols.insert(oneof_name, raw.clone());
}
Ok(())
}
fn process_enum(
&mut self,
raw: &Arc<[u8]>,
prefix: &str,
en: &EnumDescriptorProto,
) -> Result<(), Error> {
let enum_name = extract_name(prefix, "enum", en.name.as_ref())?;
self.symbols.insert(enum_name.clone(), raw.clone());
for value in &en.value {
let value_name = extract_name(&enum_name, "enum value", value.name.as_ref())?;
self.symbols.insert(value_name, raw.clone());
}
Ok(())
}
fn process_field(
&mut self,
raw: &Arc<[u8]>,
prefix: &str,
field: &FieldDescriptorProto,
) -> Result<(), Error> {
let field_name = extract_name(prefix, "field", field.name.as_ref())?;
self.symbols.insert(field_name, raw.clone());
Ok(())
}
fn list_services(&self) -> &[String] {
&self.service_names
}
fn symbol_by_name(&self, symbol: &str) -> Result<Vec<u8>, Status> {
match self.symbols.get(symbol) {
None => Err(Status::not_found(format!("symbol '{symbol}' not found"))),
Some(raw) => Ok(raw.to_vec()),
}
}
fn file_by_filename(&self, filename: &str) -> Result<Vec<u8>, Status> {
match self.files.get(filename) {
None => Err(Status::not_found(format!("file '{filename}' not found"))),
Some(raw) => Ok(raw.to_vec()),
}
}
}
fn split_file_descriptor_set(mut buf: &[u8]) -> Result<Vec<Vec<u8>>, Error> {
const FILE_FIELD_TAG: u32 = 1;
let truncated = || {
Error::InvalidFileDescriptorSet("unexpected end of FileDescriptorSet buffer".to_string())
};
let mut files = Vec::new();
while !buf.is_empty() {
let (tag, wire_type) = decode_key(&mut buf)?;
match wire_type {
WireType::LengthDelimited => {
let len = decode_varint(&mut buf)? as usize;
if len > buf.len() {
return Err(truncated());
}
let (field, rest) = buf.split_at(len);
if tag == FILE_FIELD_TAG {
files.push(field.to_vec());
}
buf = rest;
}
WireType::Varint => {
decode_varint(&mut buf)?;
}
WireType::ThirtyTwoBit => {
if buf.len() < 4 {
return Err(truncated());
}
buf = &buf[4..];
}
WireType::SixtyFourBit => {
if buf.len() < 8 {
return Err(truncated());
}
buf = &buf[8..];
}
WireType::StartGroup | WireType::EndGroup => {
return Err(Error::InvalidFileDescriptorSet(
"unexpected group wire type in FileDescriptorSet".to_string(),
));
}
}
}
Ok(files)
}
fn extract_name(
prefix: &str,
name_type: &str,
maybe_name: Option<&String>,
) -> Result<String, Error> {
match maybe_name {
None => Err(Error::InvalidFileDescriptorSet(format!(
"missing {name_type} name"
))),
Some(name) => {
if prefix.is_empty() {
Ok(name.to_string())
} else {
Ok(format!("{prefix}.{name}"))
}
}
}
}
#[derive(Debug)]
pub enum Error {
DecodeError(prost::DecodeError),
InvalidFileDescriptorSet(String),
}
impl From<DecodeError> for Error {
fn from(e: DecodeError) -> Self {
Error::DecodeError(e)
}
}
impl std::error::Error for Error {}
impl Display for Error {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Error::DecodeError(_) => f.write_str("error decoding FileDescriptorSet from buffer"),
Error::InvalidFileDescriptorSet(s) => {
write!(f, "invalid FileDescriptorSet - {s}")
}
}
}
}