package com.webpieces.http2engine.impl.shared;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import com.webpieces.http2parser.api.ConnectionException;
import com.webpieces.http2parser.api.ParseFailReason;
import com.webpieces.http2parser.api.dto.lib.Http2Msg;
import com.webpieces.util.time.Time;
public class StreamState {
private ConcurrentMap<Integer, Stream> streamIdToStream = new ConcurrentHashMap<>();
private long highestOddStream = 0;
private long highestEvenStream = 0;
private Time time;
public StreamState(Time time) {
this.time = time;
}
//chanmgr thread only
public ConcurrentMap<Integer, Stream> closeEngine() {
return streamIdToStream;
}
//client threads
public Stream create(Stream stream) {
int id = stream.getStreamId();
if(id % 2 == 0) {
if(id < highestEvenStream)
throw new IllegalStateException("stream id="+id+" is too low and must be higher than="+highestEvenStream);
highestEvenStream = id;
} else {
if(id < highestOddStream)
throw new IllegalStateException("stream id="+id+" is too low and must be higher than="+highestOddStream);
highestOddStream = id;
}
Stream oldStream = streamIdToStream.putIfAbsent(id, stream);
if(oldStream == stream)
throw new IllegalStateException("stream id="+id+" already exists");
return stream;
}
public boolean isStreamExist(Http2Msg frame) {
Stream stream = streamIdToStream.get(frame.getStreamId());
return stream != null;
}
public Stream getStream(Http2Msg frame) {
Stream stream = streamIdToStream.get(frame.getStreamId());
if (stream == null) {
int id = frame.getStreamId();
if(id % 2 == 0) {
check(frame, id, highestEvenStream);
} else {
check(frame, id, highestOddStream);
}
}
return stream;
}
private void check(Http2Msg frame, int id, long highestOpen) {
if(id > highestOpen)
throw new ConnectionException(ParseFailReason.BAD_FRAME_RECEIVED_FOR_THIS_STATE, id, "Stream in idle state and received this frame which should not happen in idle state. frame="+frame);
throw new ConnectionException(ParseFailReason.CLOSED_STREAM, id, "Stream must have been closed as it no longer exists. high mark="+highestOpen+" your frame="+frame);
}
//this method and create happen on a virtual single thread from channelmgr
//so we do not need to synchronize
public void updateAllStreams(long initialWindow) {
for(Stream stream : streamIdToStream.values()) {
stream.updateInitialWindow(initialWindow);
}
}
public Stream remove(Stream stream) {
stream.setIsClosed(true);
return streamIdToStream.remove(stream.getStreamId());
}
}