@@ -19,7 +19,7 @@ import { CallCredentials } from "./call-credentials";
19
19
import { Call , CallStreamOptions , InterceptingListener , MessageContext , StatusObject } from "./call-interface" ;
20
20
import { LogVerbosity , Propagate , Status } from "./constants" ;
21
21
import { Deadline , getDeadlineTimeoutString , getRelativeTimeout , minDeadline } from "./deadline" ;
22
- import { FilterStackFactory } from "./filter-stack" ;
22
+ import { FilterStack , FilterStackFactory } from "./filter-stack" ;
23
23
import { InternalChannel } from "./internal-channel" ;
24
24
import { Metadata } from "./metadata" ;
25
25
import * as logging from './logging' ;
@@ -33,12 +33,16 @@ export class ResolvingCall implements Call {
33
33
private pendingMessage : { context : MessageContext , message : Buffer } | null = null ;
34
34
private pendingHalfClose = false ;
35
35
private ended = false ;
36
+ private readFilterPending = false ;
37
+ private writeFilterPending = false ;
38
+ private pendingChildStatus : StatusObject | null = null ;
36
39
private metadata : Metadata | null = null ;
37
40
private listener : InterceptingListener | null = null ;
38
41
private deadline : Deadline ;
39
42
private host : string ;
40
43
private statusWatchers : ( ( status : StatusObject ) => void ) [ ] = [ ] ;
41
44
private deadlineTimer : NodeJS . Timer = setTimeout ( ( ) => { } , 0 ) ;
45
+ private filterStack : FilterStack | null = null ;
42
46
43
47
constructor (
44
48
private readonly channel : InternalChannel ,
@@ -96,14 +100,35 @@ export class ResolvingCall implements Call {
96
100
private outputStatus ( status : StatusObject ) {
97
101
if ( ! this . ended ) {
98
102
this . ended = true ;
99
- this . trace ( 'ended with status: code=' + status . code + ' details="' + status . details + '"' ) ;
100
- this . statusWatchers . forEach ( watcher => watcher ( status ) ) ;
103
+ if ( ! this . filterStack ) {
104
+ this . filterStack = this . filterStackFactory . createFilter ( ) ;
105
+ }
106
+ const filteredStatus = this . filterStack . receiveTrailers ( status ) ;
107
+ this . trace ( 'ended with status: code=' + filteredStatus . code + ' details="' + filteredStatus . details + '"' ) ;
108
+ this . statusWatchers . forEach ( watcher => watcher ( filteredStatus ) ) ;
101
109
process . nextTick ( ( ) => {
102
- this . listener ?. onReceiveStatus ( status ) ;
110
+ this . listener ?. onReceiveStatus ( filteredStatus ) ;
103
111
} ) ;
104
112
}
105
113
}
106
114
115
+ private sendMessageOnChild ( context : MessageContext , message : Buffer ) : void {
116
+ if ( ! this . child ) {
117
+ throw new Error ( 'sendMessageonChild called with child not populated' ) ;
118
+ }
119
+ const child = this . child ;
120
+ this . writeFilterPending = true ;
121
+ this . filterStack ! . sendMessage ( Promise . resolve ( { message : message , flags : context . flags } ) ) . then ( ( filteredMessage ) => {
122
+ this . writeFilterPending = false ;
123
+ child . sendMessageWithContext ( context , filteredMessage . message ) ;
124
+ if ( this . pendingHalfClose ) {
125
+ child . halfClose ( ) ;
126
+ }
127
+ } , ( status : StatusObject ) => {
128
+ this . cancelWithStatus ( status . code , status . details ) ;
129
+ } ) ;
130
+ }
131
+
107
132
getConfig ( ) : void {
108
133
if ( this . ended ) {
109
134
return ;
@@ -148,29 +173,46 @@ export class ResolvingCall implements Call {
148
173
}
149
174
150
175
this . filterStackFactory . push ( config . dynamicFilterFactories ) ;
151
-
152
- this . child = this . channel . createInnerCall ( config , this . method , this . host , this . credentials , this . deadline ) ;
153
- this . child . start ( this . metadata , {
154
- onReceiveMetadata : metadata => {
155
- this . listener ! . onReceiveMetadata ( metadata ) ;
156
- } ,
157
- onReceiveMessage : message => {
158
- this . listener ! . onReceiveMessage ( message ) ;
159
- } ,
160
- onReceiveStatus : status => {
161
- this . outputStatus ( status ) ;
176
+ this . filterStack = this . filterStackFactory . createFilter ( ) ;
177
+ this . filterStack . sendMetadata ( Promise . resolve ( this . metadata ) ) . then ( filteredMetadata => {
178
+ this . child = this . channel . createInnerCall ( config , this . method , this . host , this . credentials , this . deadline ) ;
179
+ this . child . start ( filteredMetadata , {
180
+ onReceiveMetadata : metadata => {
181
+ this . listener ! . onReceiveMetadata ( this . filterStack ! . receiveMetadata ( metadata ) ) ;
182
+ } ,
183
+ onReceiveMessage : message => {
184
+ this . readFilterPending = true ;
185
+ this . filterStack ! . receiveMessage ( message ) . then ( filteredMesssage => {
186
+ this . readFilterPending = false ;
187
+ this . listener ! . onReceiveMessage ( filteredMesssage ) ;
188
+ if ( this . pendingChildStatus ) {
189
+ this . outputStatus ( this . pendingChildStatus ) ;
190
+ }
191
+ } , ( status : StatusObject ) => {
192
+ this . cancelWithStatus ( status . code , status . details ) ;
193
+ } ) ;
194
+ } ,
195
+ onReceiveStatus : status => {
196
+ if ( this . readFilterPending ) {
197
+ this . pendingChildStatus = status ;
198
+ } else {
199
+ this . outputStatus ( status ) ;
200
+ }
201
+ }
202
+ } ) ;
203
+ if ( this . readPending ) {
204
+ this . child . startRead ( ) ;
162
205
}
163
- } ) ;
164
- if ( this . readPending ) {
165
- this . child . startRead ( ) ;
166
- }
167
- if ( this . pendingMessage ) {
168
- this . child . sendMessageWithContext ( this . pendingMessage . context , this . pendingMessage . message ) ;
169
- }
170
- if ( this . pendingHalfClose ) {
171
- this . child . halfClose ( ) ;
172
- }
206
+ if ( this . pendingMessage ) {
207
+ this . sendMessageOnChild ( this . pendingMessage . context , this . pendingMessage . message ) ;
208
+ } else if ( this . pendingHalfClose ) {
209
+ this . child . halfClose ( ) ;
210
+ }
211
+ } , ( status : StatusObject ) => {
212
+ this . outputStatus ( status ) ;
213
+ } )
173
214
}
215
+
174
216
reportResolverError ( status : StatusObject ) {
175
217
if ( this . metadata ?. getOptions ( ) . waitForReady ) {
176
218
this . channel . queueCallForConfig ( this ) ;
@@ -195,7 +237,7 @@ export class ResolvingCall implements Call {
195
237
sendMessageWithContext ( context : MessageContext , message : Buffer ) : void {
196
238
this . trace ( 'write() called with message of length ' + message . length ) ;
197
239
if ( this . child ) {
198
- this . child . sendMessageWithContext ( context , message ) ;
240
+ this . sendMessageOnChild ( context , message ) ;
199
241
} else {
200
242
this . pendingMessage = { context, message} ;
201
243
}
@@ -210,7 +252,7 @@ export class ResolvingCall implements Call {
210
252
}
211
253
halfClose ( ) : void {
212
254
this . trace ( 'halfClose called' ) ;
213
- if ( this . child ) {
255
+ if ( this . child && ! this . writeFilterPending ) {
214
256
this . child . halfClose ( ) ;
215
257
} else {
216
258
this . pendingHalfClose = true ;
0 commit comments