package eu.hgross.blaubot.websocket;
import java.io.IOException;
import java.io.InputStream;
import java.net.SocketTimeoutException;
import eu.hgross.blaubot.core.IBlaubotConnection;
import eu.hgross.blaubot.core.IBlaubotDevice;
import eu.hgross.blaubot.mock.BlaubotConnectionQueueMock;
import eu.hgross.blaubot.util.Log;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufProcessor;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame;
/**
* Blaubot connection to work upon netty websockets.
*/
public class BlaubotWebsocketConnection extends BlaubotConnectionQueueMock implements IBlaubotConnection {
private static final String LOG_TAG = "BlaubotWebsocketConnection";
private final Channel websocketChannel;
public BlaubotWebsocketConnection(IBlaubotDevice remoteDevice, Channel webSocketChannel) {
super(remoteDevice);
this.websocketChannel = webSocketChannel;
websocketChannel.closeFuture().addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
disconnect();
}
});
}
@Override
public void disconnect() {
websocketChannel.disconnect();
super.disconnect();
}
private void handleNotConnectedException(IOException e) throws SocketTimeoutException, IOException {
if(Log.logWarningMessages()) {
Log.w(LOG_TAG, "Got io exception, notifying", e);
}
this.disconnect();
throw e;
}
@Override
public void write(int b) throws IOException {
throw new UnsupportedOperationException();
}
@Override
public void write(byte[] bytes) throws IOException {
if (!connected) {
handleNotConnectedException(new IOException("not connected"));
}
ByteBuf byteBuf = Unpooled.wrappedBuffer(bytes);
websocketChannel.writeAndFlush(new BinaryWebSocketFrame(byteBuf));
}
@Override
public void write(byte[] bytes, int byteOffset, int byteCount) throws IOException {
if (!connected) {
handleNotConnectedException(new IOException("not connected"));
}
ByteBuf byteBuf = Unpooled.wrappedBuffer(bytes, byteOffset, byteCount);
websocketChannel.writeAndFlush(new BinaryWebSocketFrame(byteBuf));
}
/**
* Write data to the stream that can be retrieved via the {@link IBlaubotConnection}s
* read*() methods.
*
* @param data
* the data to write to the input stream as byte array
*/
public synchronized void writeMockDataToInputStream(ByteBuf data) {
data.forEachByte(writeMockDataProcessor);
}
private final ByteBufProcessor writeMockDataProcessor = new ByteBufProcessor() {
@Override
public boolean process(byte b) throws Exception {
inputQueue.add(b);
return true;
}
};
@Override
public InputStream getInputStreamForWrittenConnectionData() {
throw new UnsupportedOperationException("Use the base class if you need this");
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
BlaubotWebsocketConnection that = (BlaubotWebsocketConnection) o;
if (!websocketChannel.equals(that.websocketChannel)) return false;
return true;
}
@Override
public int hashCode() {
int result = super.hashCode();
result = 31 * result + websocketChannel.hashCode();
return result;
}
}