package io.muoncore.channel.impl; import io.muoncore.channel.Channel; import io.muoncore.channel.ChannelConnection; import io.muoncore.exception.MuonException; import io.muoncore.message.MuonInboundMessage; import io.muoncore.message.MuonMessageBuilder; import io.muoncore.message.MuonOutboundMessage; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import reactor.core.Dispatcher; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.zip.DeflaterOutputStream; import java.util.zip.InflaterInputStream; /** * Zips/ unzips up the messages moving along the channel */ public class ZipChannel implements Channel<MuonOutboundMessage, MuonInboundMessage> { private ChannelConnection<MuonOutboundMessage, MuonInboundMessage> left; private ChannelConnection<MuonInboundMessage, MuonOutboundMessage> right; private ChannelConnection.ChannelFunction<MuonOutboundMessage> leftFunction; private ChannelConnection.ChannelFunction<MuonInboundMessage> rightFunction; private static Logger logger = LoggerFactory.getLogger(ZipChannel.class); public ZipChannel(Dispatcher dispatcher, String name) { String leftname = name + "left"; String rightname = name + "right"; left = new ChannelConnection<MuonOutboundMessage, MuonInboundMessage>() { @Override public void receive(ChannelFunction<MuonInboundMessage> function) { rightFunction = function; } @Override public void send(MuonOutboundMessage message) { if (leftFunction == null) { throw new MuonException("Other side of the channel [" + rightname + "] is not connected to receive data"); } dispatcher.dispatch(message, msg -> { if (StandardAsyncChannel.echoOut) System.out.println("ZipChannel[" + leftname + " >>>>> " + rightname + "]: Sending " + msg + " to " + leftFunction); leftFunction.apply(zipOutbound(message)); } , Throwable::printStackTrace); } @Override public void shutdown() { leftFunction.apply(null); } }; right = new ChannelConnection<MuonInboundMessage, MuonOutboundMessage>() { @Override public void receive(ChannelFunction<MuonOutboundMessage> function) { leftFunction = function; } @Override public void send(MuonInboundMessage message) { if (rightFunction == null) { throw new MuonException("Other side of the channel [" + rightname + "] is not connected to receive data"); } dispatcher.dispatch(message, msg -> { if (StandardAsyncChannel.echoOut) System.out.println("ZipChannel[" + leftname + " <<<< " + rightname + "]: Receiving " + msg + " to " + rightFunction); rightFunction.apply(zipInbound(message)); }, Throwable::printStackTrace); } @Override public void shutdown() { rightFunction.apply(null); } }; } @Override public ChannelConnection<MuonInboundMessage, MuonOutboundMessage> right() { return right; } @Override public ChannelConnection<MuonOutboundMessage, MuonInboundMessage> left() { return left; } private MuonInboundMessage zipInbound(MuonInboundMessage msg) { if (msg == null) return null; if (msg.getContentType() == null) { return msg; } if (msg.getContentType().indexOf("DEFLATE") <= 0) { return msg; } return MuonMessageBuilder .clone(msg) .payload(zlibInflate(msg.getPayload())) .contentType(msg.getContentType().substring(0, msg.getContentType().indexOf("+DEFLATE"))) .buildInbound(); } private MuonOutboundMessage zipOutbound(MuonOutboundMessage msg) { if (msg == null) return null; return MuonMessageBuilder .clone(msg) .payload(zlibDeflate(msg.getPayload())) .contentType(msg.getContentType() + "+DEFLATE") .build(); } public static byte[] zlibDeflate(final byte[] bytes) { if (bytes == null || bytes.length == 0) return bytes; ByteArrayOutputStream os = new ByteArrayOutputStream(); DeflaterOutputStream dos = new DeflaterOutputStream(os); try { dos.write(bytes); dos.close(); } catch (IOException e) { e.printStackTrace(); } return os.toByteArray(); } public static byte[] zlibInflate(final byte[] bytes) { if (bytes == null || bytes.length == 0) return bytes; final ByteArrayInputStream bais = new ByteArrayInputStream(bytes); final ByteArrayOutputStream baos = new ByteArrayOutputStream(); final InflaterInputStream iis = new InflaterInputStream(bais); final byte[] buf = new byte[1024]; try { int count = iis.read(buf); while (count != -1) { baos.write(buf, 0, count); count = iis.read(buf); } iis.close(); baos.close(); return baos.toByteArray(); } catch (final Exception e) { logger.warn("Unable to inflate zipped payload", e); return null; } } }