@@ -55,16 +55,33 @@ export class ServerGrpc extends Server implements CustomTransportStrategy {
5555 this . logger . error ( invalidPackageError . message , invalidPackageError . stack ) ;
5656 throw invalidPackageError ;
5757 }
58- for ( const name of this . getServiceNames ( grpcPkg ) ) {
58+ // Take all of the services defined in grpcPkg and assign them to
59+ // method handlers defined in Controllers
60+ for ( const definition of this . getServiceNames ( grpcPkg ) ) {
5961 this . grpcClient . addService (
60- grpcPkg [ name ] . service ,
61- await this . createService ( grpcPkg [ name ] , name ) ,
62+ // First parameter requires exact service definition from proto
63+ definition . service . service ,
64+ // Here full proto definition required along with namespaced pattern name
65+ await this . createService ( definition . service , definition . name )
6266 ) ;
6367 }
6468 }
6569
66- public getServiceNames ( grpcPkg : any ) {
67- return Object . keys ( grpcPkg ) . filter ( name => grpcPkg [ name ] . service ) ;
70+ /**
71+ * Will return all of the services along with their fully namespaced
72+ * names as an array of objects.
73+ *
74+ * This method initiates recursive scan of grpcPkg object
75+ *
76+ * @param grpcPkg
77+ */
78+ public getServiceNames ( grpcPkg : any ) : { name : string , service : any } [ ] {
79+ const keys = Object . keys ( grpcPkg ) ;
80+ // Define accumulator to collect all of the services available to load
81+ const services : { name : string , service : any } [ ] = [ ] ;
82+ // Initiate recursive services collector starting with empty name
83+ this . _getServiceNamesCollector ( '' , grpcPkg , services ) ;
84+ return services ;
6885 }
6986
7087 public async createService ( grpcService : any , name : string ) {
@@ -177,4 +194,54 @@ export class ServerGrpc extends Server implements CustomTransportStrategy {
177194 throw invalidProtoError ;
178195 }
179196 }
197+
198+ /**
199+ * Recursively fetch all of the service methods available on loaded
200+ * protobuf descriptor object, and collect those as an objects with
201+ * dot-syntax full-path names.
202+ *
203+ * Example:
204+ * for proto package Bundle.FirstService with service Events { rpc...
205+ * will be resolved to object of (while loaded for Bundle package):
206+ * {
207+ * name: "FirstService.Events",
208+ * service: {Object}
209+ * }
210+ *
211+ * @param name
212+ * @param grpcDefinition
213+ * @param accumulator
214+ * @private
215+ */
216+ private _getServiceNamesCollector ( name , grpcDefinition , accumulator ) {
217+ // Confirm that next definition to unwrap is an object
218+ if ( typeof grpcDefinition !== 'object' )
219+ // Exit for non objects
220+ return ;
221+ // Collect keys for traverse
222+ const keys = Object . keys ( grpcDefinition ) ;
223+ // Traverse definitions or namespace extensions
224+ for ( const key of keys ) {
225+ // Define name extension variable
226+ let nameExtended = '' ;
227+ // If depth is zero then just add key
228+ if ( name . length === 0 )
229+ nameExtended = key ;
230+ // If depth non-zero then add next through dot syntax
231+ else
232+ nameExtended = name + '.' + key ;
233+ // Take nested object
234+ const nested = grpcDefinition [ key ] ;
235+ // Check if it's in depth with service definition
236+ if ( nested . hasOwnProperty ( 'service' ) ) {
237+ // Add new service object to accumulator
238+ accumulator . push ( {
239+ name : nameExtended ,
240+ service : nested
241+ } ) ;
242+ } else
243+ // Continue recursion until objects end or service definition found
244+ this . _getServiceNamesCollector ( nameExtended , nested , accumulator ) ;
245+ }
246+ }
180247}
0 commit comments