@@ -74,6 +74,7 @@ import { ServerInterceptingCallInterface, ServerInterceptor, getServerIntercepti
74
74
import { PartialStatusObject } from './call-interface' ;
75
75
import { CallEventTracker } from './transport' ;
76
76
import { Socket } from 'net' ;
77
+ import { Duplex } from 'stream' ;
77
78
78
79
const UNLIMITED_CONNECTION_AGE_MS = ~ ( 1 << 31 ) ;
79
80
const KEEPALIVE_MAX_TIME_MS = ~ ( 1 << 31 ) ;
@@ -225,6 +226,12 @@ export interface ServerOptions extends ChannelOptions {
225
226
interceptors ?: ServerInterceptor [ ]
226
227
}
227
228
229
+ export interface ConnectionInjector {
230
+ injectConnection ( connection : Duplex ) : void ;
231
+ drain ( graceTimeMs : number ) : void ;
232
+ destroy ( ) : void ;
233
+ }
234
+
228
235
export class Server {
229
236
private boundPorts : Map < string , BoundPort > = new Map ( ) ;
230
237
private http2Servers : Map < AnyHttp2Server , Http2ServerInfo > = new Map ( ) ;
@@ -808,6 +815,70 @@ export class Server {
808
815
}
809
816
}
810
817
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
+
811
882
private closeServer ( server : AnyHttp2Server , callback ?: ( ) => void ) {
812
883
this . trace ( 'Closing server with address ' + JSON . stringify ( server . address ( ) ) ) ;
813
884
const serverInfo = this . http2Servers . get ( server ) ;
0 commit comments