package se.sics.gvod.video.msgs;
import io.netty.buffer.ByteBuf;
import java.util.*;
import se.sics.gvod.common.msgs.MessageEncodingException;
import se.sics.gvod.common.msgs.DirectMsgNetty;
import se.sics.gvod.net.VodAddress;
import se.sics.gvod.net.VodMsgFrameDecoder;
import se.sics.gvod.net.msgs.RewriteableMsg;
import se.sics.gvod.net.util.UserTypesEncoderFactory;
import se.sics.gvod.net.util.VideoTypesEncoderFactory;
import se.sics.gvod.timer.ScheduleTimeout;
import se.sics.gvod.timer.Timeout;
import se.sics.gvod.timer.TimeoutId;
/**
* Message types used in Three-phase Gossip.
*
* @author Niklas Wahlén <nwahlen@kth.se>
*/
public class VideoPieceMsg {
/**
* Contains advertisements of EncodedSubPiece IDs that a peer is ready to
* disseminate into the system. These IDs are unique among all
* EncodedSubPieces in the system.
*
* @see EncodedSubPiece
*/
public static final class Advertisement extends DirectMsgNetty.Oneway {
private final Set<Integer> piecesIds;
public Advertisement(VodAddress gvodSrc, VodAddress gvodDest, Set<Integer> piecesIds) {
super(gvodSrc, gvodDest);
checkSetValidity(piecesIds);
this.piecesIds = Collections.unmodifiableSet(piecesIds);
}
@Override
public int getSize() {
return super.getHeaderSize()
+ 2 // length of Set<Integer> saves as to bytes
+ 4 * piecesIds.size();
}
@Override
public RewriteableMsg copy() {
Advertisement copy = new Advertisement(vodSrc, vodDest, new HashSet<Integer>(piecesIds));
return copy;
}
@Override
public ByteBuf toByteArray() throws MessageEncodingException {
ByteBuf buffer = createChannelBufferWithHeader();
UserTypesEncoderFactory.writeIntegerSet(buffer, piecesIds);
return buffer;
}
@Override
public byte getOpcode() {
return VodMsgFrameDecoder.VIDEO_PIECES_ADVERTISEMENT;
}
public Set<Integer> getAdvertisedPiecesIds() {
return piecesIds;
}
}
public static final class Request extends DirectMsgNetty.Request {
private final Set<Integer> piecesIds;
public Request(VodAddress gvodSrc, VodAddress gvodDest, Set<Integer> piecesIds) {
super(gvodSrc, gvodDest);
checkSetValidity(piecesIds);
this.piecesIds = Collections.unmodifiableSet(piecesIds);
}
@Override
public int getSize() {
return super.getHeaderSize()
+ 2 // length of Set<Integer> saves as to bytes
+ 4 * piecesIds.size();
}
@Override
public RewriteableMsg copy() {
Request r = new Request(vodSrc, vodDest, new HashSet<Integer>(piecesIds));
r.setTimeoutId(timeoutId);
return r;
}
@Override
public ByteBuf toByteArray() throws MessageEncodingException {
ByteBuf buffer = createChannelBufferWithHeader();
UserTypesEncoderFactory.writeIntegerSet(buffer, piecesIds);
return buffer;
}
@Override
public byte getOpcode() {
return VodMsgFrameDecoder.VIDEO_PIECES_REQUEST;
}
public Set<Integer> getPiecesIds() {
return piecesIds;
}
}
public static final class RequestTimeout extends Timeout {
private final Request requestMsg;
private final long delay;
public RequestTimeout(ScheduleTimeout st, Request requestMsg) {
super(st);
if (requestMsg == null) {
throw new IllegalArgumentException("Request msg cannot be null");
}
this.requestMsg = requestMsg;
delay = st.getDelay();
}
public Request getRequestMsg() {
return requestMsg;
}
public long getDelay() {
return delay;
}
}
public static final class Response extends DirectMsgNetty.Response {
private final EncodedSubPiece esp;
public Response(VodAddress gvodSrc, VodAddress gvodDest, TimeoutId timeoutId, EncodedSubPiece esp) {
super(gvodSrc, gvodDest, timeoutId);
if(esp == null) {
throw new IllegalArgumentException("Message content cannot be null");
}
this.esp = esp;
}
@Override
public int getSize() {
return super.getHeaderSize()
+ esp.getSize();
}
@Override
public RewriteableMsg copy() {
EncodedSubPiece espCopy = new EncodedSubPiece(esp.getGlobalId(), esp.getEncodedIndex(), Arrays.copyOf(esp.getData(), esp.getData().length), esp.getParentId());
return new Response(vodSrc, vodDest, timeoutId, espCopy);
}
@Override
public ByteBuf toByteArray() throws MessageEncodingException {
ByteBuf buffer = createChannelBufferWithHeader();
VideoTypesEncoderFactory.writeEncodedSubPiece(buffer, esp);
return buffer;
}
@Override
public byte getOpcode() {
return VodMsgFrameDecoder.VIDEO_PIECES_RESPONSE;
}
public EncodedSubPiece getEncodedSubPiece() {
return esp;
}
}
private static void checkSetValidity(Set set) {
if (set.isEmpty()) {
throw new IllegalArgumentException("Message has to contain data");
}
for (Object pieceId : set) {
if (pieceId == null) {
throw new IllegalArgumentException("Message content cannot be null");
}
}
}
}