content: package io.activej.csp.process.frame.impl;
  
  import io.activej.bytebuf.ByteBuf;
  import io.activej.bytebuf.ByteBufPool;
  import io.activej.bytebuf.ByteBufs;
  import io.activej.common.annotation.ExposedInternals;
  import io.activej.common.exception.MalformedDataException;
  import io.activej.csp.binary.decoder.ByteBufsDecoder;
  import io.activej.csp.binary.decoder.ByteBufsDecoders;
  import io.activej.csp.process.frame.BlockDecoder;
  import io.activej.csp.process.frame.BlockEncoder;
  import io.activej.csp.process.frame.FrameFormat;
  
  @ExposedInternals
  public final class MagicNumberAdapter implements FrameFormat {
  	public final FrameFormat peerFormat;
  	public final byte[] magicNumber;
  
  	private final ByteBufsDecoder<byte[]> magicNumberValidator;
  
  	public MagicNumberAdapter(FrameFormat peerFormat, byte[] magicNumber) {
  		this.peerFormat = peerFormat;
  		this.magicNumber = magicNumber;
  		this.magicNumberValidator = ByteBufsDecoders.assertBytes(magicNumber);
  	}
  
  	@Override
  	public BlockEncoder createEncoder() {
  		return new BlockEncoder() {
  			final BlockEncoder peer = peerFormat.createEncoder();
  
  			boolean writeMagicNumber = true;
  
  			@Override
  			public ByteBuf encode(ByteBuf inputBuf) {
  				ByteBuf peerEncoded = peer.encode(inputBuf);
  				if (writeMagicNumber) {
  					writeMagicNumber = false;
  					return ByteBufPool.append(ByteBuf.wrapForReading(magicNumber), peerEncoded);
  				}
  				return peerEncoded;
  			}
  
  			@Override
  			public void reset() {
  				writeMagicNumber = true;
  			}
  
  			@Override
  			public ByteBuf encodeEndOfStreamBlock() {
  				ByteBuf peerEncodedEndOfStream = peer.encodeEndOfStreamBlock();
  				if (writeMagicNumber) {
  					writeMagicNumber = false;
  					return ByteBufPool.append(ByteBuf.wrapForReading(magicNumber), peerEncodedEndOfStream);
  				}
  				return peerEncodedEndOfStream;
  			}
  		};
  	}
  
  	@Override
  	public BlockDecoder createDecoder() {
  		return new BlockDecoder() {
  			final BlockDecoder peer = peerFormat.createDecoder();
  
  			boolean validateMagicNumber = true;
  
  			@Override
  			public ByteBuf decode(ByteBufs bufs) throws MalformedDataException {
  				if (validateMagicNumber) {
  					if (magicNumberValidator.tryDecode(bufs) == null) return null;
  					validateMagicNumber = false;
  				}
  				return peer.decode(bufs);
  			}
  
  			@Override
  			public void reset() {
  				validateMagicNumber = true;
  			}
  
  			@Override
  			public boolean ignoreMissingEndOfStreamBlock() {
  				return peer.ignoreMissingEndOfStreamBlock();
  			}
  
  		};
  	}
  }
  