List of usage examples for io.netty.channel ChannelPromise addListener
@Override ChannelPromise addListener(GenericFutureListener<? extends Future<? super Void>> listener);
From source file:com.relayrides.pushy.apns.ApnsClientHandler.java
License:Open Source License
@Override public void write(final ChannelHandlerContext context, final Object message, final ChannelPromise writePromise) throws Http2Exception { if (message instanceof PushNotificationAndResponsePromise) { final PushNotificationAndResponsePromise pushNotificationAndResponsePromise = (PushNotificationAndResponsePromise) message; final ApnsPushNotification pushNotification = pushNotificationAndResponsePromise.getPushNotification(); if (this.responsePromises.containsKey(pushNotification)) { writePromise.tryFailure(new PushNotificationStillPendingException()); } else {// www. ja v a 2 s .c o m this.responsePromises.put(pushNotification, pushNotificationAndResponsePromise.getResponsePromise()); pushNotificationAndResponsePromise.getResponsePromise().addListener( new GenericFutureListener<Future<PushNotificationResponse<ApnsPushNotification>>>() { @Override public void operationComplete( final Future<PushNotificationResponse<ApnsPushNotification>> future) { // Regardless of the outcome, when the response promise is finished, we want to remove it from // the map of pending promises. ApnsClientHandler.this.responsePromises.remove(pushNotification); } }); this.write(context, pushNotification, writePromise); } } else if (message instanceof ApnsPushNotification) { final ApnsPushNotification pushNotification = (ApnsPushNotification) message; try { final int streamId = (int) this.nextStreamId; final Http2Headers headers = new DefaultHttp2Headers().method(HttpMethod.POST.asciiName()) .authority(this.authority).path(APNS_PATH_PREFIX + pushNotification.getToken()) .addInt(APNS_EXPIRATION_HEADER, pushNotification.getExpiration() == null ? 0 : (int) (pushNotification.getExpiration().getTime() / 1000)); final String authenticationToken = this.apnsClient .getAuthenticationTokenSupplierForTopic(pushNotification.getTopic()).getToken(); headers.add(APNS_AUTHORIZATION_HEADER, "bearer " + authenticationToken); if (pushNotification.getCollapseId() != null) { headers.add(APNS_COLLAPSE_ID_HEADER, pushNotification.getCollapseId()); } if (pushNotification.getPriority() != null) { headers.addInt(APNS_PRIORITY_HEADER, pushNotification.getPriority().getCode()); } if (pushNotification.getTopic() != null) { headers.add(APNS_TOPIC_HEADER, pushNotification.getTopic()); } final ChannelPromise headersPromise = context.newPromise(); this.encoder().writeHeaders(context, streamId, headers, 0, false, headersPromise); log.trace("Wrote headers on stream {}: {}", streamId, headers); final ByteBuf payloadBuffer = context.alloc().ioBuffer(INITIAL_PAYLOAD_BUFFER_CAPACITY); payloadBuffer.writeBytes(pushNotification.getPayload().getBytes(StandardCharsets.UTF_8)); final ChannelPromise dataPromise = context.newPromise(); this.encoder().writeData(context, streamId, payloadBuffer, 0, true, dataPromise); log.trace("Wrote payload on stream {}: {}", streamId, pushNotification.getPayload()); final PromiseCombiner promiseCombiner = new PromiseCombiner(); promiseCombiner.addAll(headersPromise, dataPromise); promiseCombiner.finish(writePromise); writePromise.addListener(new GenericFutureListener<ChannelPromise>() { @Override public void operationComplete(final ChannelPromise future) throws Exception { if (future.isSuccess()) { ApnsClientHandler.this.pushNotificationsByStreamId.put(streamId, pushNotification); ApnsClientHandler.this.authenticationTokensByStreamId.put(streamId, authenticationToken); } else { log.trace("Failed to write push notification on stream {}.", streamId, future.cause()); final Promise<PushNotificationResponse<ApnsPushNotification>> responsePromise = ApnsClientHandler.this.responsePromises .get(pushNotification); if (responsePromise != null) { responsePromise.tryFailure(future.cause()); } else { log.error("Notification write failed, but no response promise found."); } } } }); this.nextStreamId += 2; if (this.nextStreamId >= STREAM_ID_RESET_THRESHOLD) { // This is very unlikely, but in the event that we run out of stream IDs (the maximum allowed is // 2^31, per https://httpwg.github.io/specs/rfc7540.html#StreamIdentifiers), we need to open a new // connection. Just closing the context should be enough; automatic reconnection should take things // from there. context.close(); } } catch (NoKeyForTopicException | SignatureException e) { writePromise.tryFailure(e); } } else { // This should never happen, but in case some foreign debris winds up in the pipeline, just pass it through. log.error("Unexpected object in pipeline: {}", message); context.write(message, writePromise); } }
From source file:com.turo.pushy.apns.ApnsClientHandler.java
License:Open Source License
private void writePushNotification(final ChannelHandlerContext context, final PushNotificationPromise responsePromise, final ChannelPromise writePromise) { if (context.channel().isActive()) { final int streamId = this.connection().local().incrementAndGetNextStreamId(); if (streamId > 0) { // We'll attach the push notification and response promise to the stream as soon as the stream is created. // Because we're using a StreamBufferingEncoder under the hood, there's no guarantee as to when the stream // will actually be created, and so we attach these in the onStreamAdded listener to make sure everything // is happening in a predictable order. this.unattachedResponsePromisesByStreamId.put(streamId, responsePromise); final ApnsPushNotification pushNotification = responsePromise.getPushNotification(); final Http2Headers headers = getHeadersForPushNotification(pushNotification, streamId); final ChannelPromise headersPromise = context.newPromise(); this.encoder().writeHeaders(context, streamId, headers, 0, false, headersPromise); log.trace("Wrote headers on stream {}: {}", streamId, headers); final ByteBuf payloadBuffer = context.alloc().ioBuffer(INITIAL_PAYLOAD_BUFFER_CAPACITY); payloadBuffer.writeBytes(pushNotification.getPayload().getBytes(StandardCharsets.UTF_8)); final ChannelPromise dataPromise = context.newPromise(); this.encoder().writeData(context, streamId, payloadBuffer, 0, true, dataPromise); log.trace("Wrote payload on stream {}: {}", streamId, pushNotification.getPayload()); final PromiseCombiner promiseCombiner = new PromiseCombiner(); promiseCombiner.addAll((ChannelFuture) headersPromise, dataPromise); promiseCombiner.finish(writePromise); writePromise.addListener(new GenericFutureListener<ChannelPromise>() { @Override/*from w w w .j a v a 2 s. c o m*/ public void operationComplete(final ChannelPromise future) { if (!future.isSuccess()) { log.trace("Failed to write push notification on stream {}.", streamId, future.cause()); responsePromise.tryFailure(future.cause()); } } }); } else { // This is very unlikely, but in the event that we run out of stream IDs, we need to open a new // connection. Just closing the context should be enough; automatic reconnection should take things // from there. writePromise.tryFailure(STREAMS_EXHAUSTED_EXCEPTION); context.channel().close(); } } else { writePromise.tryFailure(STREAM_CLOSED_BEFORE_REPLY_EXCEPTION); } }
From source file:com.twitter.http2.HttpConnectionHandler.java
License:Apache License
@Override public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception { if (msg instanceof HttpDataFrame) { HttpDataFrame httpDataFrame = (HttpDataFrame) msg; int streamId = httpDataFrame.getStreamId(); // Frames must not be sent on half-closed streams if (httpConnection.isLocalSideClosed(streamId)) { promise.setFailure(PROTOCOL_EXCEPTION); return; }//from w w w . java2 s. c om // HTTP/2 DATA frame flow control processing requirements: // // Sender must not send a data frame with data length greater // than the transfer window size. // // After sending each data frame, the sender decrements its // transfer window size by the amount of data transmitted. // // When the window size becomes less than or equal to 0, the // sender must pause transmitting data frames. int dataLength = httpDataFrame.content().readableBytes(); int sendWindowSize = httpConnection.getSendWindowSize(streamId); int connectionSendWindowSize = httpConnection.getSendWindowSize(HTTP_CONNECTION_STREAM_ID); sendWindowSize = Math.min(sendWindowSize, connectionSendWindowSize); if (sendWindowSize <= 0) { // Stream is stalled -- enqueue Data frame and return httpConnection.putPendingWrite(streamId, new HttpConnection.PendingWrite(httpDataFrame, promise)); return; } else if (sendWindowSize < dataLength) { // Stream is not stalled but we cannot send the entire frame httpConnection.updateSendWindowSize(streamId, -1 * sendWindowSize); httpConnection.updateSendWindowSize(HTTP_CONNECTION_STREAM_ID, -1 * sendWindowSize); // Create a partial data frame whose length is the current window size ByteBuf data = httpDataFrame.content().readSlice(sendWindowSize); ByteBuf partialDataFrame = httpFrameEncoder.encodeDataFrame(streamId, false, data); // Enqueue the remaining data (will be the first frame queued) httpConnection.putPendingWrite(streamId, new HttpConnection.PendingWrite(httpDataFrame, promise)); ChannelPromise writeFuture = ctx.channel().newPromise(); // The transfer window size is pre-decremented when sending a data frame downstream. // Close the connection on write failures that leaves the transfer window in a corrupt state. writeFuture.addListener(connectionErrorListener); ctx.write(partialDataFrame, writeFuture); return; } else { // Window size is large enough to send entire data frame httpConnection.updateSendWindowSize(streamId, -1 * dataLength); httpConnection.updateSendWindowSize(HTTP_CONNECTION_STREAM_ID, -1 * dataLength); // The transfer window size is pre-decremented when sending a data frame downstream. // Close the connection on write failures that leaves the transfer window in a corrupt state. promise.addListener(connectionErrorListener); } // Close the local side of the stream if this is the last frame if (httpDataFrame.isLast()) { halfCloseStream(streamId, false, promise); } ByteBuf frame = httpFrameEncoder.encodeDataFrame(streamId, httpDataFrame.isLast(), httpDataFrame.content()); ctx.write(frame, promise); } else if (msg instanceof HttpHeadersFrame) { HttpHeadersFrame httpHeadersFrame = (HttpHeadersFrame) msg; int streamId = httpHeadersFrame.getStreamId(); if (streamId <= lastStreamId) { // Frames must not be sent on half-closed (local) or closed streams if (httpConnection.isLocalSideClosed(streamId)) { promise.setFailure(PROTOCOL_EXCEPTION); return; } } else { if (isRemoteInitiatedId(streamId)) { promise.setFailure(PROTOCOL_EXCEPTION); return; } // Try to accept the stream boolean exclusive = httpHeadersFrame.isExclusive(); int dependency = httpHeadersFrame.getDependency(); int weight = httpHeadersFrame.getWeight(); if (!acceptStream(streamId, exclusive, dependency, weight)) { promise.setFailure(PROTOCOL_EXCEPTION); return; } } // Close the local side of the stream if this is the last frame if (httpHeadersFrame.isLast()) { halfCloseStream(streamId, false, promise); } synchronized (httpHeaderBlockEncoder) { ByteBuf frame = httpFrameEncoder.encodeHeadersFrame(httpHeadersFrame.getStreamId(), httpHeadersFrame.isLast(), httpHeadersFrame.isExclusive(), httpHeadersFrame.getDependency(), httpHeadersFrame.getWeight(), httpHeaderBlockEncoder.encode(ctx, httpHeadersFrame)); // Writes of compressed data must occur in order ctx.write(frame, promise); } } else if (msg instanceof HttpPriorityFrame) { HttpPriorityFrame httpPriorityFrame = (HttpPriorityFrame) msg; int streamId = httpPriorityFrame.getStreamId(); boolean exclusive = httpPriorityFrame.isExclusive(); int dependency = httpPriorityFrame.getDependency(); int weight = httpPriorityFrame.getWeight(); setPriority(streamId, exclusive, dependency, weight); ByteBuf frame = httpFrameEncoder.encodePriorityFrame(streamId, exclusive, dependency, weight); ctx.write(frame, promise); } else if (msg instanceof HttpRstStreamFrame) { HttpRstStreamFrame httpRstStreamFrame = (HttpRstStreamFrame) msg; removeStream(httpRstStreamFrame.getStreamId(), promise); ByteBuf frame = httpFrameEncoder.encodeRstStreamFrame(httpRstStreamFrame.getStreamId(), httpRstStreamFrame.getErrorCode().getCode()); ctx.write(frame, promise); } else if (msg instanceof HttpSettingsFrame) { // TODO(jpinner) currently cannot have more than one settings frame outstanding at a time HttpSettingsFrame httpSettingsFrame = (HttpSettingsFrame) msg; if (httpSettingsFrame.isAck()) { // Cannot send an acknowledgement frame promise.setFailure(PROTOCOL_EXCEPTION); return; } int newHeaderTableSize = httpSettingsFrame.getValue(HttpSettingsFrame.SETTINGS_HEADER_TABLE_SIZE); if (newHeaderTableSize >= 0) { headerTableSize = newHeaderTableSize; changeDecoderHeaderTableSize = true; } int newConcurrentStreams = httpSettingsFrame .getValue(HttpSettingsFrame.SETTINGS_MAX_CONCURRENT_STREAMS); if (newConcurrentStreams >= 0) { localConcurrentStreams = newConcurrentStreams; } int newInitialWindowSize = httpSettingsFrame.getValue(HttpSettingsFrame.SETTINGS_INITIAL_WINDOW_SIZE); if (newInitialWindowSize >= 0) { updateInitialReceiveWindowSize(newInitialWindowSize); } ByteBuf frame = httpFrameEncoder.encodeSettingsFrame(httpSettingsFrame); ctx.write(frame, promise); } else if (msg instanceof HttpPushPromiseFrame) { if (!pushEnabled) { promise.setFailure(PROTOCOL_EXCEPTION); return; } // TODO(jpinner) handle push promise frames promise.setFailure(PROTOCOL_EXCEPTION); // synchronized (httpHeaderBlockEncoder) { // HttpPushPromiseFrame httpPushPromiseFrame = (HttpPushPromiseFrame) msg; // ChannelBuffer frame = httpFrameEncoder.encodePushPromiseFrame( // httpPushPromiseFrame.getStreamId(), // httpPushPromiseFrame.getPromisedStreamId(), // httpHeaderBlockEncoder.encode(ctx, httpPushPromiseFrame) // ); // // Writes of compressed data must occur in order // Channels.write(ctx, e.getFuture(), frame, e.getRemoteAddress()); // } } else if (msg instanceof HttpPingFrame) { HttpPingFrame httpPingFrame = (HttpPingFrame) msg; if (httpPingFrame.isPong()) { // Cannot send a PONG frame promise.setFailure(PROTOCOL_EXCEPTION); } else { ByteBuf frame = httpFrameEncoder.encodePingFrame(httpPingFrame.getData(), false); ctx.write(frame, promise); } } else if (msg instanceof HttpGoAwayFrame) { // Why is this being sent? Intercept it and fail the write. // Should have sent a CLOSE ChannelStateEvent promise.setFailure(PROTOCOL_EXCEPTION); } else if (msg instanceof HttpWindowUpdateFrame) { HttpWindowUpdateFrame httpWindowUpdateFrame = (HttpWindowUpdateFrame) msg; int streamId = httpWindowUpdateFrame.getStreamId(); if (handleStreamWindowUpdates || streamId == HTTP_CONNECTION_STREAM_ID) { // Why is this being sent? Intercept it and fail the write. promise.setFailure(PROTOCOL_EXCEPTION); } else { int windowSizeIncrement = httpWindowUpdateFrame.getWindowSizeIncrement(); httpConnection.updateReceiveWindowSize(streamId, windowSizeIncrement); ByteBuf frame = httpFrameEncoder.encodeWindowUpdateFrame(streamId, windowSizeIncrement); ctx.write(frame, promise); } } else { ctx.write(msg, promise); } }
From source file:com.twitter.http2.HttpConnectionHandler.java
License:Apache License
private void updateSendWindowSize(ChannelHandlerContext ctx, int streamId, int windowSizeIncrement) { httpConnection.updateSendWindowSize(streamId, windowSizeIncrement); while (true) { // Check if we have unblocked a stalled stream HttpConnection.PendingWrite e = httpConnection.getPendingWrite(streamId); if (e == null) { break; }//from w w w . j a v a 2s .c om HttpDataFrame httpDataFrame = e.httpDataFrame; int dataFrameSize = httpDataFrame.content().readableBytes(); int writeStreamId = httpDataFrame.getStreamId(); int sendWindowSize = httpConnection.getSendWindowSize(writeStreamId); int connectionSendWindowSize = httpConnection.getSendWindowSize(HTTP_CONNECTION_STREAM_ID); sendWindowSize = Math.min(sendWindowSize, connectionSendWindowSize); if (sendWindowSize <= 0) { return; } else if (sendWindowSize < dataFrameSize) { // We can send a partial frame httpConnection.updateSendWindowSize(writeStreamId, -1 * sendWindowSize); httpConnection.updateSendWindowSize(HTTP_CONNECTION_STREAM_ID, -1 * sendWindowSize); // Create a partial data frame whose length is the current window size ByteBuf data = httpDataFrame.content().readSlice(sendWindowSize); ByteBuf partialDataFrame = httpFrameEncoder.encodeDataFrame(writeStreamId, false, data); ChannelPromise writeFuture = ctx.channel().newPromise(); // The transfer window size is pre-decremented when sending a data frame downstream. // Close the connection on write failures that leaves the transfer window in a corrupt state. writeFuture.addListener(connectionErrorListener); ctx.writeAndFlush(partialDataFrame, writeFuture); } else { // Window size is large enough to send entire data frame httpConnection.removePendingWrite(writeStreamId); httpConnection.updateSendWindowSize(writeStreamId, -1 * dataFrameSize); httpConnection.updateSendWindowSize(HTTP_CONNECTION_STREAM_ID, -1 * dataFrameSize); // The transfer window size is pre-decremented when sending a data frame downstream. // Close the connection on write failures that leaves the transfer window in a corrupt state. e.promise.addListener(connectionErrorListener); // Close the local side of the stream if this is the last frame if (httpDataFrame.isLast()) { halfCloseStream(writeStreamId, false, e.promise); } ByteBuf frame = httpFrameEncoder.encodeDataFrame(writeStreamId, httpDataFrame.isLast(), httpDataFrame.content()); ctx.writeAndFlush(frame, e.promise); } } }
From source file:com.twitter.http2.HttpStreamEncoder.java
License:Apache License
private ChannelPromise getMessageFuture(final ChannelHandlerContext ctx, final ChannelPromise promise, final int streamId, HttpMessage message) { if (message instanceof StreamedHttpMessage && !((StreamedHttpMessage) message).getContent().isClosed()) { final Pipe<HttpContent> pipe = ((StreamedHttpMessage) message).getContent(); ChannelPromise writeFuture = ctx.channel().newPromise(); writeFuture.addListener(new ChannelFutureListener() { @Override//from w w w . jav a 2s .c om public void operationComplete(ChannelFuture future) throws Exception { // Channel's thread // First frame has been written if (future.isSuccess()) { pipe.receive().addListener(new ChunkListener(ctx, streamId, pipe, promise)); } else if (future.isCancelled()) { pipe.close(); promise.cancel(true); } else { pipe.close(); promise.setFailure(future.cause()); } } }); return writeFuture; } else { return promise; } }
From source file:com.twitter.http2.HttpStreamEncoder.java
License:Apache License
private static ChannelPromise getFrameFuture(ChannelHandlerContext ctx, ChannelPromise future, HttpFrame[] httpFrames) {/*from w ww . j a va2s .c o m*/ ChannelPromise frameFuture = future; for (int i = httpFrames.length; --i >= 0;) { future = ctx.channel().newPromise(); future.addListener(new HttpFrameWriter(ctx, frameFuture, httpFrames[i])); frameFuture = future; } return frameFuture; }
From source file:com.vmware.dcp.common.http.netty.NettyWebSocketRequestHandler.java
License:Open Source License
private void performWebsocketHandshake(final ChannelHandlerContext ctx, FullHttpRequest nettyRequest) { WebSocketServerHandshakerFactory factory = new WebSocketServerHandshakerFactory(this.handshakePath, null, false);/*from www . j a va 2s. c om*/ this.handshaker = factory.newHandshaker(nettyRequest); if (this.handshaker == null) { WebSocketServerHandshakerFactory.sendUnsupportedVersionResponse(ctx.channel()); } else { ChannelPromise promise = new DefaultChannelPromise(ctx.channel()); promise.addListener(new ChannelFutureListener() { @Override public void operationComplete(ChannelFuture future) throws Exception { if (!future.isSuccess()) { ctx.channel().close(); } ctx.channel().closeFuture().addListener(f -> { for (java.util.Map.Entry<URI, Set<String>> e : NettyWebSocketRequestHandler.this.serviceSubscriptions .entrySet()) { WebSocketService svc = NettyWebSocketRequestHandler.this.webSocketServices .get(e.getKey()); if (svc != null) { deleteServiceSubscriptions(svc); } NettyWebSocketRequestHandler.this.host.stopService(svc); } }); } }); DefaultHttpHeaders responseHeaders = new DefaultHttpHeaders(); this.handshaker.handshake(ctx.channel(), nettyRequest, responseHeaders, promise); } }
From source file:com.vmware.xenon.common.http.netty.NettyChannelPool.java
License:Open Source License
/** * When using HTTP/2, we have to wait for the settings to be negotiated before we can send * data. We wait for a promise that comes from the HTTP client channel pipeline *//* w ww . ja va2 s . c o m*/ private void waitForSettings(Channel ch, NettyChannelContext contextFinal, Operation request, NettyChannelGroup group) { ChannelPromise settingsPromise = ch.attr(NettyChannelContext.SETTINGS_PROMISE_KEY).get(); settingsPromise.addListener(new ChannelFutureListener() { @Override public void operationComplete(ChannelFuture future) throws Exception { if (future.isSuccess()) { // retrieve pending operations List<Operation> pendingOps = new ArrayList<>(); synchronized (group) { contextFinal.setOpenInProgress(false); contextFinal.setChannel(future.channel()).setOperation(request); pendingOps.addAll(group.pendingRequests); group.pendingRequests.clear(); } sendAfterConnect(future.channel(), contextFinal, request, group); // trigger pending operations for (Operation pendingOp : pendingOps) { pendingOp.setSocketContext(contextFinal); pendingOp.complete(); } } else { returnOrClose(contextFinal, true); fail(request, future.cause()); } } }); }
From source file:com.vmware.xenon.common.http.netty.NettyWebSocketRequestHandler.java
License:Open Source License
private void performWebsocketHandshake(final ChannelHandlerContext ctx, FullHttpRequest nettyRequest) { WebSocketServerHandshakerFactory factory = new WebSocketServerHandshakerFactory(this.handshakePath, null, false);/*from w w w .j a v a2 s . c o m*/ this.handshaker = factory.newHandshaker(nettyRequest); if (this.handshaker == null) { WebSocketServerHandshakerFactory.sendUnsupportedVersionResponse(ctx.channel()); } else { ChannelPromise promise = new DefaultChannelPromise(ctx.channel()); promise.addListener(new ChannelFutureListener() { @Override public void operationComplete(ChannelFuture future) throws Exception { if (!future.isSuccess()) { ctx.channel().close(); } ctx.channel().closeFuture().addListener(f -> { for (java.util.Map.Entry<URI, Set<String>> e : NettyWebSocketRequestHandler.this.serviceSubscriptions .entrySet()) { WebSocketService svc = NettyWebSocketRequestHandler.this.webSocketServices .get(e.getKey()); if (svc != null) { deleteServiceSubscriptions(svc); } NettyWebSocketRequestHandler.this.host.stopService(svc); } }); } }); DefaultHttpHeaders responseHeaders = new DefaultHttpHeaders(); CharSequence token = nettyRequest.headers().get(Operation.REQUEST_AUTH_TOKEN_HEADER, null); if (token == null) { String cookie = nettyRequest.headers().get(HttpHeaderNames.COOKIE); if (cookie != null) { token = CookieJar.decodeCookies(cookie).get(AuthenticationConstants.REQUEST_AUTH_TOKEN_COOKIE); } } this.authToken = token == null ? null : token.toString(); this.handshaker.handshake(ctx.channel(), nettyRequest, responseHeaders, promise); } }
From source file:de.saxsys.synchronizefx.netty.base.client.NetworkEventHandlerClient.java
License:Open Source License
@Override public void write(final ChannelHandlerContext ctx, final Object msg, final ChannelPromise promise) throws Exception { promise.addListener(new GenericFutureListener<Future<? super Void>>() { @Override// ww w. ja v a 2 s . co m public void operationComplete(final Future<? super Void> future) throws Exception { Throwable cause = future.cause(); if (cause != null) { exceptionCaught(ctx, cause); } } }); ctx.write(msg, promise); }