package net.scapeemulator.game.net.update;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.handler.timeout.ReadTimeoutHandler;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import net.scapeemulator.cache.Cache;
import net.scapeemulator.cache.ChecksumTable;
import net.scapeemulator.cache.Container;
import net.scapeemulator.game.GameServer;
import net.scapeemulator.game.net.Session;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public final class UpdateSession extends Session {
private static final Logger logger = LoggerFactory.getLogger(UpdateSession.class);
private final UpdateService service;
private final Deque<FileRequest> fileQueue = new ArrayDeque<>();
private boolean idle = true;
private boolean handshakeComplete = false;
public UpdateSession(GameServer server, Channel channel) {
super(server, channel);
this.service = server.getUpdateService();
}
public void processFileQueue() {
FileRequest request;
synchronized (fileQueue) {
request = fileQueue.pop();
if (fileQueue.isEmpty()) {
idle = true;
} else {
service.addPendingSession(this);
idle = false;
}
}
if (request != null) {
int type = request.getType();
int file = request.getFile();
Cache cache = server.getCache();
ByteBuf buf;
try {
if (type == 255 && file == 255) {
ChecksumTable table = server.getChecksumTable();
Container container = new Container(Container.COMPRESSION_NONE, table.encode());
buf = Unpooled.wrappedBuffer(container.encode());
} else {
buf = Unpooled.wrappedBuffer(cache.getStore().read(type, file));
if (type != 255)
buf = buf.slice(0, buf.readableBytes() - 2);
}
channel.write(new FileResponse(request.isPriority(), type, file, buf));
} catch (IOException ex) {
logger.warn("Failed to service file request " + type + ", " + file + ".", ex);
}
}
}
@Override
public void messageReceived(Object message) {
if (handshakeComplete) {
if (message instanceof FileRequest) {
FileRequest request = (FileRequest) message;
synchronized (fileQueue) {
if (request.isPriority()) {
fileQueue.addFirst(request);
} else {
fileQueue.addLast(request);
}
if (idle) {
service.addPendingSession(this);
idle = false;
}
}
} else if (message instanceof UpdateEncryptionMessage) {
UpdateEncryptionMessage encryption = (UpdateEncryptionMessage) message;
XorEncoder encoder = channel.pipeline().get(XorEncoder.class);
encoder.setKey(encryption.getKey());
}
} else {
UpdateVersionMessage version = (UpdateVersionMessage) message;
int status;
if (version.getVersion() == server.getVersion()) {
status = UpdateStatusMessage.STATUS_OK;
} else {
status = UpdateStatusMessage.STATUS_OUT_OF_DATE;
}
ChannelFuture future = channel.write(new UpdateStatusMessage(status));
if (status == UpdateStatusMessage.STATUS_OK) {
/* the client won't re-connect so an ondemand session cannot time out */
channel.pipeline().remove(ReadTimeoutHandler.class);
handshakeComplete = true;
} else {
future.addListener(ChannelFutureListener.CLOSE);
}
}
}
}