@@ -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 ;
@@ -149,29 +174,46 @@ export class ResolvingCall implements Call {
149
174
}
150
175
151
176
this . filterStackFactory . push ( config . dynamicFilterFactories ) ;
152
-
153
- this . child = this . channel . createInnerCall ( config , this . method , this . host , this . credentials , this . deadline ) ;
154
- this . child . start ( this . metadata , {
155
- onReceiveMetadata : metadata => {
156
- this . listener ! . onReceiveMetadata ( metadata ) ;
157
- } ,
158
- onReceiveMessage : message => {
159
- this . listener ! . onReceiveMessage ( message ) ;
160
- } ,
161
- onReceiveStatus : status => {
162
- this . outputStatus ( status ) ;
177
+ this . filterStack = this . filterStackFactory . createFilter ( ) ;
178
+ this . filterStack . sendMetadata ( Promise . resolve ( this . metadata ) ) . then ( filteredMetadata => {
179
+ this . child = this . channel . createInnerCall ( config , this . method , this . host , this . credentials , this . deadline ) ;
180
+ this . child . start ( filteredMetadata , {
181
+ onReceiveMetadata : metadata => {
182
+ this . listener ! . onReceiveMetadata ( this . filterStack ! . receiveMetadata ( metadata ) ) ;
183
+ } ,
184
+ onReceiveMessage : message => {
185
+ this . readFilterPending = true ;
186
+ this . filterStack ! . receiveMessage ( message ) . then ( filteredMesssage => {
187
+ this . readFilterPending = false ;
188
+ this . listener ! . onReceiveMessage ( filteredMesssage ) ;
189
+ if ( this . pendingChildStatus ) {
190
+ this . outputStatus ( this . pendingChildStatus ) ;
191
+ }
192
+ } , ( status : StatusObject ) => {
193
+ this . cancelWithStatus ( status . code , status . details ) ;
194
+ } ) ;
195
+ } ,
196
+ onReceiveStatus : status => {
197
+ if ( this . readFilterPending ) {
198
+ this . pendingChildStatus = status ;
199
+ } else {
200
+ this . outputStatus ( status ) ;
201
+ }
202
+ }
203
+ } ) ;
204
+ if ( this . readPending ) {
205
+ this . child . startRead ( ) ;
163
206
}
164
- } ) ;
165
- if ( this . readPending ) {
166
- this . child . startRead ( ) ;
167
- }
168
- if ( this . pendingMessage ) {
169
- this . child . sendMessageWithContext ( this . pendingMessage . context , this . pendingMessage . message ) ;
170
- }
171
- if ( this . pendingHalfClose ) {
172
- this . child . halfClose ( ) ;
173
- }
207
+ if ( this . pendingMessage ) {
208
+ this . sendMessageOnChild ( this . pendingMessage . context , this . pendingMessage . message ) ;
209
+ } else if ( this . pendingHalfClose ) {
210
+ this . child . halfClose ( ) ;
211
+ }
212
+ } , ( status : StatusObject ) => {
213
+ this . outputStatus ( status ) ;
214
+ } )
174
215
}
216
+
175
217
reportResolverError ( status : StatusObject ) {
176
218
if ( this . metadata ?. getOptions ( ) . waitForReady ) {
177
219
this . channel . queueCallForConfig ( this ) ;
@@ -196,7 +238,7 @@ export class ResolvingCall implements Call {
196
238
sendMessageWithContext ( context : MessageContext , message : Buffer ) : void {
197
239
this . trace ( 'write() called with message of length ' + message . length ) ;
198
240
if ( this . child ) {
199
- this . child . sendMessageWithContext ( context , message ) ;
241
+ this . sendMessageOnChild ( context , message ) ;
200
242
} else {
201
243
this . pendingMessage = { context, message} ;
202
244
}
@@ -211,7 +253,7 @@ export class ResolvingCall implements Call {
211
253
}
212
254
halfClose ( ) : void {
213
255
this . trace ( 'halfClose called' ) ;
214
- if ( this . child ) {
256
+ if ( this . child && ! this . writeFilterPending ) {
215
257
this . child . halfClose ( ) ;
216
258
} else {
217
259
this . pendingHalfClose = true ;
0 commit comments