1#[cfg(feature = "reflection")]
18use tonic_reflection::server::{ServerReflection, ServerReflectionServer};
19
20#[derive(Debug, Clone)]
22pub struct ReflectionConfig {
23 pub enabled: bool,
25 pub file_descriptor_sets: Vec<&'static [u8]>,
27}
28
29impl Default for ReflectionConfig {
30 fn default() -> Self {
31 Self {
32 enabled: true,
33 file_descriptor_sets: Vec::new(),
34 }
35 }
36}
37
38impl ReflectionConfig {
39 pub fn new() -> Self {
41 Self::default()
42 }
43
44 pub fn enabled(mut self, enabled: bool) -> Self {
46 self.enabled = enabled;
47 self
48 }
49
50 pub fn add_file_descriptor_set(mut self, fds: &'static [u8]) -> Self {
52 self.file_descriptor_sets.push(fds);
53 self
54 }
55}
56
57#[cfg(feature = "reflection")]
61pub struct ReflectionService {
62 config: ReflectionConfig,
63}
64
65#[cfg(feature = "reflection")]
66impl ReflectionService {
67 pub fn new(file_descriptor_sets: &[&'static [u8]]) -> Self {
69 Self {
70 config: ReflectionConfig {
71 enabled: true,
72 file_descriptor_sets: file_descriptor_sets.to_vec(),
73 },
74 }
75 }
76
77 pub fn with_config(config: ReflectionConfig) -> Self {
79 Self { config }
80 }
81
82 pub fn build_server(
86 &self,
87 ) -> Option<ServerReflectionServer<impl ServerReflection>> {
88 if !self.config.enabled || self.config.file_descriptor_sets.is_empty() {
89 return None;
90 }
91
92 let mut builder = tonic_reflection::server::Builder::configure();
93
94 for fds in &self.config.file_descriptor_sets {
95 builder = builder.register_encoded_file_descriptor_set(fds);
96 }
97
98 builder.build_v1().ok()
99 }
100
101 pub fn build_server_v1alpha(
105 &self,
106 ) -> Option<tonic_reflection::server::v1alpha::ServerReflectionServer<impl tonic_reflection::server::v1alpha::ServerReflection>> {
107 if !self.config.enabled || self.config.file_descriptor_sets.is_empty() {
108 return None;
109 }
110
111 let mut builder = tonic_reflection::server::Builder::configure();
112
113 for fds in &self.config.file_descriptor_sets {
114 builder = builder.register_encoded_file_descriptor_set(fds);
115 }
116
117 builder.build_v1alpha().ok()
118 }
119}
120
121#[cfg(feature = "reflection")]
122impl std::fmt::Debug for ReflectionService {
123 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
124 f.debug_struct("ReflectionService")
125 .field("enabled", &self.config.enabled)
126 .field(
127 "file_descriptor_count",
128 &self.config.file_descriptor_sets.len(),
129 )
130 .finish()
131 }
132}
133
134#[cfg(not(feature = "reflection"))]
136pub struct ReflectionService {
137 _private: (),
138}
139
140#[cfg(not(feature = "reflection"))]
141impl ReflectionService {
142 pub fn new(_file_descriptor_sets: &[&'static [u8]]) -> Self {
144 Self { _private: () }
145 }
146}
147
148#[cfg(test)]
149mod tests {
150 use super::*;
151
152 #[test]
153 fn reflection_config_defaults() {
154 let config = ReflectionConfig::default();
155 assert!(config.enabled);
156 assert!(config.file_descriptor_sets.is_empty());
157 }
158
159 #[test]
160 fn reflection_config_builder() {
161 let config = ReflectionConfig::new()
162 .enabled(false);
163 assert!(!config.enabled);
164 }
165
166 #[cfg(feature = "reflection")]
167 #[test]
168 fn reflection_service_disabled_returns_none() {
169 let service = ReflectionService::with_config(
170 ReflectionConfig::new().enabled(false),
171 );
172 assert!(service.build_server().is_none());
173 }
174
175 #[cfg(feature = "reflection")]
176 #[test]
177 fn reflection_service_empty_fds_returns_none() {
178 let service = ReflectionService::new(&[]);
179 assert!(service.build_server().is_none());
180 }
181}