2424
2525import org .apache .servicecomb .common .rest .RestConst ;
2626import org .apache .servicecomb .common .rest .codec .RestCodec ;
27+ import org .apache .servicecomb .common .rest .codec .produce .ProduceEventStreamProcessor ;
2728import org .apache .servicecomb .common .rest .codec .produce .ProduceProcessor ;
2829import org .apache .servicecomb .common .rest .definition .RestOperationMeta ;
2930import org .apache .servicecomb .common .rest .filter .HttpServerFilter ;
3637import org .apache .servicecomb .swagger .invocation .Response ;
3738import org .apache .servicecomb .swagger .invocation .exception .ExceptionFactory ;
3839import org .apache .servicecomb .swagger .invocation .exception .InvocationException ;
40+ import org .reactivestreams .Publisher ;
41+ import org .reactivestreams .Subscriber ;
42+ import org .reactivestreams .Subscription ;
43+ import org .slf4j .Logger ;
44+ import org .slf4j .LoggerFactory ;
3945
4046import com .netflix .config .DynamicPropertyFactory ;
4147
42- import io .netty . buffer .Unpooled ;
48+ import io .vertx . core . buffer .Buffer ;
4349
4450public class ServerRestArgsFilter implements HttpServerFilter {
4551 private static final boolean enabled = DynamicPropertyFactory .getInstance ().getBooleanProperty
4652 ("servicecomb.http.filter.server.serverRestArgs.enabled" , true ).get ();
4753
54+ private static final Logger LOGGER = LoggerFactory .getLogger (ServerRestArgsFilter .class );
55+
4856 @ Override
4957 public int getOrder () {
5058 return -100 ;
@@ -74,10 +82,15 @@ public CompletableFuture<Void> beforeSendResponseAsync(Invocation invocation, Ht
7482 return responseEx .sendPart (PartUtils .getSinglePart (null , response .getResult ()));
7583 }
7684
77- responseEx .setContentType (produceProcessor .getName () + "; charset=utf-8" );
85+ if (isServerSendEvent (response )) {
86+ produceProcessor = new ProduceEventStreamProcessor ();
87+ responseEx .setContentType (produceProcessor .getName () + "; charset=utf-8" );
88+ return writeServerSendEvent (response , produceProcessor , responseEx );
89+ }
7890
91+ responseEx .setContentType (produceProcessor .getName () + "; charset=utf-8" );
7992 CompletableFuture <Void > future = new CompletableFuture <>();
80- try (BufferOutputStream output = new BufferOutputStream (Unpooled . compositeBuffer ())) {
93+ try (BufferOutputStream output = new BufferOutputStream (Buffer . buffer ())) {
8194 if (failed ) {
8295 produceProcessor .encodeResponse (output , ((InvocationException ) response .getResult ()).getErrorData ());
8396 } else {
@@ -91,4 +104,66 @@ public CompletableFuture<Void> beforeSendResponseAsync(Invocation invocation, Ht
91104 }
92105 return future ;
93106 }
107+
108+ public static boolean isServerSendEvent (Response response ) {
109+ return response .getResult () instanceof Publisher <?>;
110+ }
111+
112+ private static CompletableFuture <Void > writeServerSendEvent (Response response , ProduceProcessor produceProcessor ,
113+ HttpServletResponseEx responseEx ) {
114+ responseEx .setChunked (true );
115+ CompletableFuture <Void > result = new CompletableFuture <>();
116+ Publisher <?> publisher = response .getResult ();
117+ publisher .subscribe (new Subscriber <Object >() {
118+ Subscription subscription ;
119+
120+ @ Override
121+ public void onSubscribe (Subscription s ) {
122+ s .request (1 );
123+ subscription = s ;
124+ }
125+
126+ @ Override
127+ public void onNext (Object o ) {
128+ writeResponse (responseEx , produceProcessor , o , response ).whenComplete ((r , e ) -> {
129+ if (e != null ) {
130+ subscription .cancel ();
131+ result .completeExceptionally (e );
132+ return ;
133+ }
134+ subscription .request (1 );
135+ });
136+ }
137+
138+ @ Override
139+ public void onError (Throwable t ) {
140+ result .completeExceptionally (t );
141+ }
142+
143+ @ Override
144+ public void onComplete () {
145+ result .complete (null );
146+ }
147+ });
148+ return result ;
149+ }
150+
151+ private static CompletableFuture <Response > writeResponse (
152+ HttpServletResponseEx responseEx , ProduceProcessor produceProcessor , Object data , Response response ) {
153+ try (BufferOutputStream output = new BufferOutputStream (Buffer .buffer ())) {
154+ produceProcessor .encodeResponse (output , data );
155+ CompletableFuture <Response > result = new CompletableFuture <>();
156+ responseEx .sendBuffer (output .getBuffer ()).whenComplete ((v , e ) -> {
157+ if (e != null ) {
158+ result .completeExceptionally (e );
159+ }
160+ });
161+ result .complete (response );
162+ return result ;
163+ } catch (Throwable e ) {
164+ LOGGER .error ("internal service error must be fixed." , e );
165+ responseEx .setStatus (500 );
166+ return CompletableFuture .failedFuture (e );
167+ }
168+ }
94169}
0 commit comments