/** * Creates a new protobuf handler. * * @param handler The callback listener * @param prototype The default instance of the message type used in both directions of this channel. * This should be the return value from {@link MessageLite#getDefaultInstanceForType()} * @param maxMessageSize The maximum message size (not including the 4-byte length prefix). * Note that this has an upper bound of {@link Integer#MAX_VALUE} - 4 * @param timeoutMillis The timeout between messages before the connection is automatically closed. Only enabled * after the connection is established. */ public ProtobufConnection(Listener<MessageType> handler, MessageType prototype, int maxMessageSize, int timeoutMillis) { this.handler = handler; this.prototype = prototype; this.maxMessageSize = Math.min(maxMessageSize, Integer.MAX_VALUE - 4); setTimeoutEnabled(false); setSocketTimeout(timeoutMillis); }
@Override public void sendToServer(Protos.TwoWayChannelMessage msg) { wireParser.write(msg); }
@Override public void destroyConnection(PaymentChannelCloseException.CloseReason reason) { if (closeReason != null) closeReason = reason; socketProtobufHandler.closeConnection(); }
/** * <p>Closes the channel with the client (will generate a * {@link ServerConnectionEventHandler#channelClosed(PaymentChannelCloseException.CloseReason)} event)</p> * * <p>Note that this does <i>NOT</i> actually broadcast the most recent payment transaction, which will be triggered * automatically when the channel times out by the {@link StoredPaymentChannelServerStates}, or manually by calling * {@link StoredPaymentChannelServerStates#closeChannel(StoredServerChannel)} with the channel returned by * {@link StoredPaymentChannelServerStates#getChannel(org.bitcoinj.core.Sha256Hash)} with the id provided in * {@link ServerConnectionEventHandler#channelOpen(org.bitcoinj.core.Sha256Hash)}</p> */ @SuppressWarnings("unchecked") // The warning 'unchecked call to write(MessageType)' being suppressed here comes from the build() // formally returning MessageLite-derived class that cannot be statically guaranteed to be the same MessageType // that is used in connectionChannel. protected final synchronized void closeChannel() { if (connectionChannel == null) throw new IllegalStateException("Channel is not fully initialized/has already been closed"); connectionChannel.write(Protos.TwoWayChannelMessage.newBuilder() .setType(Protos.TwoWayChannelMessage.MessageType.CLOSE) .build()); connectionChannel.closeConnection(); }
serverConnection1Open.get(); ProtobufConnection<TwoWayChannelMessage> client2Handler = new ProtobufConnection<>( new ProtobufConnection.Listener<Protos.TwoWayChannelMessage>() { @Override serverConnection2Open.get(); ProtobufConnection<TwoWayChannelMessage> client3Handler = new ProtobufConnection<>( new ProtobufConnection.Listener<Protos.TwoWayChannelMessage>() { @Override client1Handler.write(msg); assertEquals(msg, client1MessageReceived.get()); client2Handler.write(msg2); assertEquals(msg2, client2MessageReceived.get()); client3Handler.write(msg3); assertEquals(msg3, client3MessageReceived.get());
if (messageBytesOffset == messageBytes.length) { deserializeMessage(ByteBuffer.wrap(messageBytes)); messageBytes = null; if (buff.hasRemaining()) return bytesToGet + receiveBytes(buff); deserializeMessage(buff); checkState(buff.remaining() == 0); return len + 4 + receiveBytes(buff); else return len + 4;
@Override public void channelOpen(boolean wasInitiated) { wireParser.setSocketTimeout(0); // Inform the API user that we're done and ready to roll. channelOpenFuture.set(PaymentChannelClientConnection.this); } }, versionSelector);
socketProtobufHandler = new ProtobufConnection<Protos.TwoWayChannelMessage> (protobufHandlerListener, Protos.TwoWayChannelMessage.getDefaultInstance(), Short.MAX_VALUE, timeoutSeconds*1000);
@Override public void connectionOpened() { setTimeoutEnabled(true); handler.connectionOpen(this); }
@SuppressWarnings("unchecked") // The warning 'unchecked cast' being suppressed here comes from the build() formally returning // a MessageLite-derived class that cannot be statically guaranteed to be the MessageType. private void deserializeMessage(ByteBuffer buff) throws Exception { MessageType msg = (MessageType) prototype.newBuilderForType().mergeFrom(ByteString.copyFrom(buff)).build(); resetTimeout(); handler.messageReceived(this, msg); }
/** * <p>Closes the channel with the client (will generate a * {@link ServerConnectionEventHandler#channelClosed(PaymentChannelCloseException.CloseReason)} event)</p> * * <p>Note that this does <i>NOT</i> actually broadcast the most recent payment transaction, which will be triggered * automatically when the channel times out by the {@link StoredPaymentChannelServerStates}, or manually by calling * {@link StoredPaymentChannelServerStates#closeChannel(StoredServerChannel)} with the channel returned by * {@link StoredPaymentChannelServerStates#getChannel(org.bitcoinj.core.Sha256Hash)} with the id provided in * {@link ServerConnectionEventHandler#channelOpen(org.bitcoinj.core.Sha256Hash)}</p> */ @SuppressWarnings("unchecked") // The warning 'unchecked call to write(MessageType)' being suppressed here comes from the build() // formally returning MessageLite-derived class that cannot be statically guaranteed to be the same MessageType // that is used in connectionChannel. protected final synchronized void closeChannel() { if (connectionChannel == null) throw new IllegalStateException("Channel is not fully initialized/has already been closed"); connectionChannel.write(Protos.TwoWayChannelMessage.newBuilder() .setType(Protos.TwoWayChannelMessage.MessageType.CLOSE) .build()); connectionChannel.closeConnection(); }
client1Disconnected.get(); clientHandler = new ProtobufConnection<>( new ProtobufConnection.Listener<Protos.TwoWayChannelMessage>() { @Override clientHandler.write(msg);
if (messageBytesOffset == messageBytes.length) { deserializeMessage(ByteBuffer.wrap(messageBytes)); messageBytes = null; if (buff.hasRemaining()) return bytesToGet + receiveBytes(buff); deserializeMessage(buff); checkState(buff.remaining() == 0); return len + 4 + receiveBytes(buff); else return len + 4;
@Override public void channelOpen(boolean wasInitiated) { wireParser.setSocketTimeout(0); // Inform the API user that we're done and ready to roll. channelOpenFuture.set(PaymentChannelClientConnection.this); } }, versionSelector);
socketProtobufHandler = new ProtobufConnection<Protos.TwoWayChannelMessage> (protobufHandlerListener, Protos.TwoWayChannelMessage.getDefaultInstance(), Short.MAX_VALUE, timeoutSeconds*1000);
@Override public void connectionOpened() { setTimeoutEnabled(true); handler.connectionOpen(this); }
@SuppressWarnings("unchecked") // The warning 'unchecked cast' being suppressed here comes from the build() formally returning // a MessageLite-derived class that cannot be statically guaranteed to be the MessageType. private void deserializeMessage(ByteBuffer buff) throws Exception { MessageType msg = (MessageType) prototype.newBuilderForType().mergeFrom(ByteString.copyFrom(buff)).build(); resetTimeout(); handler.messageReceived(this, msg); }
/** * Creates a new protobuf handler. * * @param handler The callback listener * @param prototype The default instance of the message type used in both directions of this channel. * This should be the return value from {@link MessageType#getDefaultInstanceForType()} * @param maxMessageSize The maximum message size (not including the 4-byte length prefix). * Note that this has an upper bound of {@link Integer#MAX_VALUE} - 4 * @param timeoutMillis The timeout between messages before the connection is automatically closed. Only enabled * after the connection is established. */ public ProtobufConnection(Listener<MessageType> handler, MessageType prototype, int maxMessageSize, int timeoutMillis) { this.handler = handler; this.prototype = prototype; this.maxMessageSize = Math.min(maxMessageSize, Integer.MAX_VALUE - 4); setTimeoutEnabled(false); setSocketTimeout(timeoutMillis); }
/** * <p>Closes the channel with the client (will generate a * {@link ServerConnectionEventHandler#channelClosed(PaymentChannelCloseException.CloseReason)} event)</p> * * <p>Note that this does <i>NOT</i> actually broadcast the most recent payment transaction, which will be triggered * automatically when the channel times out by the {@link StoredPaymentChannelServerStates}, or manually by calling * {@link StoredPaymentChannelServerStates#closeChannel(StoredServerChannel)} with the channel returned by * {@link StoredPaymentChannelServerStates#getChannel(org.bitcoinj.core.Sha256Hash)} with the id provided in * {@link ServerConnectionEventHandler#channelOpen(org.bitcoinj.core.Sha256Hash)}</p> */ @SuppressWarnings("unchecked") // The warning 'unchecked call to write(MessageType)' being suppressed here comes from the build() // formally returning MessageLite-derived class that cannot be statically guaranteed to be the same MessageType // that is used in connectionChannel. protected final synchronized void closeChannel() { if (connectionChannel == null) throw new IllegalStateException("Channel is not fully initialized/has already been closed"); connectionChannel.write(Protos.TwoWayChannelMessage.newBuilder() .setType(Protos.TwoWayChannelMessage.MessageType.CLOSE) .build()); connectionChannel.closeConnection(); }
/** * Disconnects the network connection but doesn't request the server to settle the channel first (literally just * unplugs the network socket and marks the stored channel state as inactive). */ public void disconnectWithoutSettlement() { wireParser.closeConnection(); } }