• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #region Copyright notice and license
2 // Copyright 2015 gRPC authors.
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //     http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 #endregion
16 
17 using System;
18 using System.Collections.Generic;
19 using System.Linq;
20 using System.Text;
21 using System.Threading.Tasks;
22 
23 using Grpc.Core;
24 using Grpc.Core.Utils;
25 using Grpc.Reflection.V1Alpha;
26 using Google.Protobuf.Reflection;
27 
28 namespace Grpc.Reflection
29 {
30     /// <summary>
31     /// Implementation of server reflection service.
32     /// </summary>
33     public class ReflectionServiceImpl : Grpc.Reflection.V1Alpha.ServerReflection.ServerReflectionBase
34     {
35         readonly List<string> services;
36         readonly SymbolRegistry symbolRegistry;
37 
38         /// <summary>
39         /// Creates a new instance of <c>ReflectionServiceIml</c>.
40         /// </summary>
ReflectionServiceImpl(IEnumerable<string> services, SymbolRegistry symbolRegistry)41         public ReflectionServiceImpl(IEnumerable<string> services, SymbolRegistry symbolRegistry)
42         {
43             this.services = new List<string>(services);
44             this.symbolRegistry = symbolRegistry;
45         }
46 
47         /// <summary>
48         /// Creates a new instance of <c>ReflectionServiceIml</c>.
49         /// </summary>
ReflectionServiceImpl(IEnumerable<ServiceDescriptor> serviceDescriptors)50         public ReflectionServiceImpl(IEnumerable<ServiceDescriptor> serviceDescriptors)
51         {
52             this.services = new List<string>(serviceDescriptors.Select((serviceDescriptor) => serviceDescriptor.FullName));
53             this.symbolRegistry = SymbolRegistry.FromFiles(serviceDescriptors.Select((serviceDescriptor) => serviceDescriptor.File));
54         }
55 
56         /// <summary>
57         /// Creates a new instance of <c>ReflectionServiceIml</c>.
58         /// </summary>
ReflectionServiceImpl(params ServiceDescriptor[] serviceDescriptors)59         public ReflectionServiceImpl(params ServiceDescriptor[] serviceDescriptors) : this((IEnumerable<ServiceDescriptor>) serviceDescriptors)
60         {
61         }
62 
63         /// <summary>
64         /// Processes a stream of server reflection requests.
65         /// </summary>
ServerReflectionInfo(IAsyncStreamReader<ServerReflectionRequest> requestStream, IServerStreamWriter<ServerReflectionResponse> responseStream, ServerCallContext context)66         public override async Task ServerReflectionInfo(IAsyncStreamReader<ServerReflectionRequest> requestStream, IServerStreamWriter<ServerReflectionResponse> responseStream, ServerCallContext context)
67         {
68             while (await requestStream.MoveNext())
69             {
70                 var response = ProcessRequest(requestStream.Current);
71                 await responseStream.WriteAsync(response);
72             }
73         }
74 
ProcessRequest(ServerReflectionRequest request)75         ServerReflectionResponse ProcessRequest(ServerReflectionRequest request)
76         {
77             switch (request.MessageRequestCase)
78             {
79                 case ServerReflectionRequest.MessageRequestOneofCase.FileByFilename:
80                     return FileByFilename(request.FileByFilename);
81                 case ServerReflectionRequest.MessageRequestOneofCase.FileContainingSymbol:
82                     return FileContainingSymbol(request.FileContainingSymbol);
83                 case ServerReflectionRequest.MessageRequestOneofCase.ListServices:
84                     return ListServices();
85                 case ServerReflectionRequest.MessageRequestOneofCase.AllExtensionNumbersOfType:
86                 case ServerReflectionRequest.MessageRequestOneofCase.FileContainingExtension:
87                 default:
88                     return CreateErrorResponse(StatusCode.Unimplemented, "Request type not supported by C# reflection service.");
89             }
90         }
91 
FileByFilename(string filename)92         ServerReflectionResponse FileByFilename(string filename)
93         {
94             FileDescriptor file = symbolRegistry.FileByName(filename);
95             if (file == null)
96             {
97                 return CreateErrorResponse(StatusCode.NotFound, "File not found.");
98             }
99 
100             var transitiveDependencies = new HashSet<FileDescriptor>();
101             CollectTransitiveDependencies(file, transitiveDependencies);
102 
103             return new ServerReflectionResponse
104             {
105                 FileDescriptorResponse = new FileDescriptorResponse { FileDescriptorProto = { transitiveDependencies.Select((d) => d.SerializedData) } }
106             };
107         }
108 
FileContainingSymbol(string symbol)109         ServerReflectionResponse FileContainingSymbol(string symbol)
110         {
111             FileDescriptor file = symbolRegistry.FileContainingSymbol(symbol);
112             if (file == null)
113             {
114                 return CreateErrorResponse(StatusCode.NotFound, "Symbol not found.");
115             }
116 
117             var transitiveDependencies = new HashSet<FileDescriptor>();
118             CollectTransitiveDependencies(file, transitiveDependencies);
119 
120             return new ServerReflectionResponse
121             {
122                 FileDescriptorResponse = new FileDescriptorResponse { FileDescriptorProto = { transitiveDependencies.Select((d) => d.SerializedData) } }
123             };
124         }
125 
ListServices()126         ServerReflectionResponse ListServices()
127         {
128             var serviceResponses = new ListServiceResponse();
129             foreach (string serviceName in services)
130             {
131                 serviceResponses.Service.Add(new ServiceResponse { Name = serviceName });
132             }
133 
134             return new ServerReflectionResponse
135             {
136                 ListServicesResponse = serviceResponses
137             };
138         }
139 
CreateErrorResponse(StatusCode status, string message)140         ServerReflectionResponse CreateErrorResponse(StatusCode status, string message)
141         {
142             return new ServerReflectionResponse
143             {
144                 ErrorResponse = new ErrorResponse { ErrorCode = (int) status, ErrorMessage = message }
145             };
146         }
147 
CollectTransitiveDependencies(FileDescriptor descriptor, HashSet<FileDescriptor> pool)148         void CollectTransitiveDependencies(FileDescriptor descriptor, HashSet<FileDescriptor> pool)
149         {
150             pool.Add(descriptor);
151             foreach (var dependency in descriptor.Dependencies)
152             {
153                 if (pool.Add(dependency))
154                 {
155                     // descriptors cannot have circular dependencies
156                     CollectTransitiveDependencies(dependency, pool);
157                 }
158             }
159         }
160     }
161 }
162