@@ -74,6 +74,7 @@ import { ServerInterceptingCallInterface, ServerInterceptor, getServerIntercepti
7474import { PartialStatusObject } from './call-interface' ;
7575import { CallEventTracker } from './transport' ;
7676import { Socket } from 'net' ;
77+ import { Duplex } from 'stream' ;
7778
7879const UNLIMITED_CONNECTION_AGE_MS = ~ ( 1 << 31 ) ;
7980const KEEPALIVE_MAX_TIME_MS = ~ ( 1 << 31 ) ;
@@ -225,6 +226,12 @@ export interface ServerOptions extends ChannelOptions {
225226 interceptors ?: ServerInterceptor [ ]
226227}
227228
229+ export interface ConnectionInjector {
230+ injectConnection ( connection : Duplex ) : void ;
231+ drain ( graceTimeMs : number ) : void ;
232+ destroy ( ) : void ;
233+ }
234+
228235export class Server {
229236 private boundPorts : Map < string , BoundPort > = new Map ( ) ;
230237 private http2Servers : Map < AnyHttp2Server , Http2ServerInfo > = new Map ( ) ;
@@ -808,6 +815,70 @@ export class Server {
808815 }
809816 }
810817
818+ private registerInjectorToChannelz ( ) {
819+ return registerChannelzSocket (
820+ 'injector' ,
821+ ( ) => {
822+ return {
823+ localAddress : null ,
824+ remoteAddress : null ,
825+ security : null ,
826+ remoteName : null ,
827+ streamsStarted : 0 ,
828+ streamsSucceeded : 0 ,
829+ streamsFailed : 0 ,
830+ messagesSent : 0 ,
831+ messagesReceived : 0 ,
832+ keepAlivesSent : 0 ,
833+ lastLocalStreamCreatedTimestamp : null ,
834+ lastRemoteStreamCreatedTimestamp : null ,
835+ lastMessageSentTimestamp : null ,
836+ lastMessageReceivedTimestamp : null ,
837+ localFlowControlWindow : null ,
838+ remoteFlowControlWindow : null ,
839+ } ;
840+ } ,
841+ this . channelzEnabled
842+ ) ;
843+ }
844+
845+ createConnectionInjector ( credentials : ServerCredentials ) : ConnectionInjector {
846+ if ( credentials === null || ! ( credentials instanceof ServerCredentials ) ) {
847+ throw new TypeError ( 'creds must be a ServerCredentials object' ) ;
848+ }
849+ const server = this . createHttp2Server ( credentials ) ;
850+ const channelzRef = this . registerInjectorToChannelz ( ) ;
851+ if ( this . channelzEnabled ) {
852+ this . listenerChildrenTracker . refChild ( channelzRef ) ;
853+ }
854+ const sessionsSet : Set < http2 . ServerHttp2Session > = new Set ( ) ;
855+ this . http2Servers . set ( server , {
856+ channelzRef : channelzRef ,
857+ sessions : sessionsSet
858+ } ) ;
859+ return {
860+ injectConnection : ( connection : Duplex ) => {
861+ server . emit ( 'connection' , connection ) ;
862+ } ,
863+ drain : ( graceTimeMs : number ) => {
864+ for ( const session of sessionsSet ) {
865+ this . closeSession ( session ) ;
866+ }
867+ setTimeout ( ( ) => {
868+ for ( const session of sessionsSet ) {
869+ session . destroy ( http2 . constants . NGHTTP2_CANCEL as any ) ;
870+ }
871+ } , graceTimeMs ) . unref ?.( ) ;
872+ } ,
873+ destroy : ( ) => {
874+ this . closeServer ( server )
875+ for ( const session of sessionsSet ) {
876+ this . closeSession ( session ) ;
877+ }
878+ }
879+ } ;
880+ }
881+
811882 private closeServer ( server : AnyHttp2Server , callback ?: ( ) => void ) {
812883 this . trace ( 'Closing server with address ' + JSON . stringify ( server . address ( ) ) ) ;
813884 const serverInfo = this . http2Servers . get ( server ) ;
0 commit comments