init, thx MrExtremez

This commit is contained in:
Nicola Paolucci
2019-06-18 15:04:35 -04:00
commit ea51313125
2488 changed files with 150207 additions and 0 deletions
@@ -0,0 +1,63 @@
package org.apollo.jagcached.net;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apollo.jagcached.FileServer;
import org.apollo.jagcached.dispatch.RequestDispatcher;
import org.apollo.jagcached.net.jaggrab.JagGrabRequest;
import org.apollo.jagcached.net.ondemand.OnDemandRequest;
import org.apollo.jagcached.net.service.ServiceRequest;
import org.apollo.jagcached.net.service.ServiceResponse;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ExceptionEvent;
import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.handler.codec.http.HttpRequest;
import org.jboss.netty.handler.timeout.IdleStateAwareChannelUpstreamHandler;
import org.jboss.netty.handler.timeout.IdleStateEvent;
/**
* An {@link IdleStateAwareChannelUpstreamHandler} for the {@link FileServer}.
* @author Graham
*/
public final class FileServerHandler extends IdleStateAwareChannelUpstreamHandler {
/**
* The logger for this class.
*/
private static final Logger logger = Logger.getLogger(FileServerHandler.class.getName());
@Override
public void channelIdle(ChannelHandlerContext ctx, IdleStateEvent e) throws Exception {
e.getChannel().close();
}
@Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
Object msg = e.getMessage();
if (msg instanceof ServiceRequest) {
ServiceRequest request = (ServiceRequest) msg;
if (request.getId() != ServiceRequest.SERVICE_ONDEMAND) {
e.getChannel().close();
} else {
e.getChannel().write(new ServiceResponse());
}
} else if (msg instanceof OnDemandRequest) {
RequestDispatcher.dispatch(e.getChannel(), (OnDemandRequest) msg);
} else if (msg instanceof JagGrabRequest) {
RequestDispatcher.dispatch(e.getChannel(), (JagGrabRequest) msg);
} else if (msg instanceof HttpRequest) {
RequestDispatcher.dispatch(e.getChannel(), (HttpRequest) msg);
} else {
throw new Exception("unknown message type");
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception {
logger.log(Level.SEVERE, "Exception occured, closing channel...", e.getCause());
e.getChannel().close();
}
}
@@ -0,0 +1,61 @@
package org.apollo.jagcached.net;
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.channel.Channels;
import org.jboss.netty.handler.codec.http.HttpChunkAggregator;
import org.jboss.netty.handler.codec.http.HttpRequestDecoder;
import org.jboss.netty.handler.codec.http.HttpResponseEncoder;
import org.jboss.netty.handler.timeout.IdleStateHandler;
import org.jboss.netty.util.Timer;
/**
* A {@link ChannelPipelineFactory} for the HTTP protocol.
* @author Graham
*/
public final class HttpPipelineFactory implements ChannelPipelineFactory {
/**
* The maximum length of a request, in bytes.
*/
private static final int MAX_REQUEST_LENGTH = 8192;
/**
* The file server event handler.
*/
private final FileServerHandler handler;
/**
* The timer used for idle checking.
*/
private final Timer timer;
/**
* Creates the HTTP pipeline factory.
* @param handler The file server event handler.
* @param timer The timer used for idle checking.
*/
public HttpPipelineFactory(FileServerHandler handler, Timer timer) {
this.handler = handler;
this.timer = timer;
}
@Override
public ChannelPipeline getPipeline() throws Exception {
ChannelPipeline pipeline = Channels.pipeline();
// decoders
pipeline.addLast("decoder", new HttpRequestDecoder());
pipeline.addLast("chunker", new HttpChunkAggregator(MAX_REQUEST_LENGTH));
// encoders
pipeline.addLast("encoder", new HttpResponseEncoder());
// handler
pipeline.addLast("timeout", new IdleStateHandler(timer, NetworkConstants.IDLE_TIME, 0, 0));
pipeline.addLast("handler", handler);
return pipeline;
}
}
@@ -0,0 +1,86 @@
package org.apollo.jagcached.net;
import java.nio.charset.Charset;
import org.apollo.jagcached.net.jaggrab.JagGrabRequestDecoder;
import org.apollo.jagcached.net.jaggrab.JagGrabResponseEncoder;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers;
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.channel.Channels;
import org.jboss.netty.handler.codec.frame.DelimiterBasedFrameDecoder;
import org.jboss.netty.handler.codec.string.StringDecoder;
import org.jboss.netty.handler.timeout.IdleStateHandler;
import org.jboss.netty.util.Timer;
/**
* A {@link ChannelPipelineFactory} for the JAGGRAB protocol.
* @author Graham
*/
public final class JagGrabPipelineFactory implements ChannelPipelineFactory {
/**
* The maximum length of a request, in bytes.
*/
private static final int MAX_REQUEST_LENGTH = 8192;
/**
* The character set used in the request.
*/
private static final Charset JAGGRAB_CHARSET = Charset.forName("US-ASCII");
/**
* A buffer with two line feed (LF) characters in it.
*/
private static final ChannelBuffer DOUBLE_LINE_FEED_DELIMITER = ChannelBuffers.buffer(2);
/**
* Populates the double line feed buffer.
*/
static {
DOUBLE_LINE_FEED_DELIMITER.writeByte(10);
DOUBLE_LINE_FEED_DELIMITER.writeByte(10);
}
/**
* The file server event handler.
*/
private final FileServerHandler handler;
/**
* The timer used for idle checking.
*/
private final Timer timer;
/**
* Creates a {@code JAGGRAB} pipeline factory.
* @param handler The file server event handler.
* @param timer The timer used for idle checking.
*/
public JagGrabPipelineFactory(FileServerHandler handler, Timer timer) {
this.handler = handler;
this.timer = timer;
}
@Override
public ChannelPipeline getPipeline() throws Exception {
ChannelPipeline pipeline = Channels.pipeline();
// decoders
pipeline.addLast("framer", new DelimiterBasedFrameDecoder(MAX_REQUEST_LENGTH, DOUBLE_LINE_FEED_DELIMITER));
pipeline.addLast("string-decoder", new StringDecoder(JAGGRAB_CHARSET));
pipeline.addLast("jaggrab-decoder", new JagGrabRequestDecoder());
// encoders
pipeline.addLast("jaggrab-encoder", new JagGrabResponseEncoder());
// handler
pipeline.addLast("timeout", new IdleStateHandler(timer, NetworkConstants.IDLE_TIME, 0, 0));
pipeline.addLast("handler", handler);
return pipeline;
}
}
@@ -0,0 +1,37 @@
package org.apollo.jagcached.net;
/**
* A class which holds network-related constants.
* @author Graham
*/
public final class NetworkConstants {
/**
* The HTTP port.
*/
public static final int HTTP_PORT = 80;
/**
* The JAGGRAB port.
*/
public static final int JAGGRAB_PORT = 43595;
/**
* The service port (which is also used for the 'on-demand' protocol).
*/
public static final int SERVICE_PORT = 43596;
/**
* The number of seconds a channel can be idle before being closed
* automatically.
*/
public static final int IDLE_TIME = 15;
/**
* Default private constructor to prevent instantiaton.
*/
private NetworkConstants() {
}
}
@@ -0,0 +1,59 @@
package org.apollo.jagcached.net;
import org.apollo.jagcached.net.ondemand.OnDemandRequestDecoder;
import org.apollo.jagcached.net.ondemand.OnDemandResponseEncoder;
import org.apollo.jagcached.net.service.ServiceRequestDecoder;
import org.apollo.jagcached.net.service.ServiceResponseEncoder;
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.channel.Channels;
import org.jboss.netty.handler.timeout.IdleStateHandler;
import org.jboss.netty.util.Timer;
/**
* A {@link ChannelPipelineFactory} for the 'on-demand' protocol.
* @author Graham
*/
public final class OnDemandPipelineFactory implements ChannelPipelineFactory {
/**
* The file server event handler.
*/
private final FileServerHandler handler;
/**
* The timer used for idle checking.
*/
private final Timer timer;
/**
* Creates an 'on-demand' pipeline factory.
* @param handler The file server event handler.
* @param timer The timer used for idle checking.
*/
public OnDemandPipelineFactory(FileServerHandler handler, Timer timer) {
this.handler = handler;
this.timer = timer;
}
@Override
public ChannelPipeline getPipeline() throws Exception {
ChannelPipeline pipeline = Channels.pipeline();
// decoders
pipeline.addLast("serviceDecoder", new ServiceRequestDecoder());
pipeline.addLast("decoder", new OnDemandRequestDecoder());
// encoders
pipeline.addLast("serviceEncoder", new ServiceResponseEncoder());
pipeline.addLast("encoder", new OnDemandResponseEncoder());
// handler
pipeline.addLast("timeout", new IdleStateHandler(timer, NetworkConstants.IDLE_TIME, 0, 0));
pipeline.addLast("handler", handler);
return pipeline;
}
}
@@ -0,0 +1,30 @@
package org.apollo.jagcached.net.jaggrab;
/**
* Represents the request for a single file using the JAGGRAB protocol.
* @author Graham
*/
public final class JagGrabRequest {
/**
* The path to the file.
*/
private final String filePath;
/**
* Creates the request.
* @param filePath The file path.
*/
public JagGrabRequest(String filePath) {
this.filePath = filePath;
}
/**
* Gets the file path.
* @return The file path.
*/
public String getFilePath() {
return filePath;
}
}
@@ -0,0 +1,27 @@
package org.apollo.jagcached.net.jaggrab;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.handler.codec.oneone.OneToOneDecoder;
/**
* A {@link OneToOneDecoder} for the JAGGRAB protocol.
* @author Graham
*/
public final class JagGrabRequestDecoder extends OneToOneDecoder {
@Override
protected Object decode(ChannelHandlerContext ctx, Channel c, Object msg) throws Exception {
if (msg instanceof String) {
String str = ((String) msg);
if (str.startsWith("JAGGRAB /")) {
String filePath = str.substring(8).trim();
return new JagGrabRequest(filePath);
} else {
throw new Exception("corrupted request line");
}
}
return msg;
}
}
@@ -0,0 +1,32 @@
package org.apollo.jagcached.net.jaggrab;
import org.jboss.netty.buffer.ChannelBuffer;
/**
* Represents a single JAGGRAB reponse.
* @author Graham
*/
public final class JagGrabResponse {
/**
* The file data.
*/
private final ChannelBuffer fileData;
/**
* Creates the response.
* @param fileData The file data.
*/
public JagGrabResponse(ChannelBuffer fileData) {
this.fileData = fileData;
}
/**
* Gets the file data.
* @return The file data.
*/
public ChannelBuffer getFileData() {
return fileData;
}
}
@@ -0,0 +1,22 @@
package org.apollo.jagcached.net.jaggrab;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.handler.codec.oneone.OneToOneEncoder;
/**
* A {@link OneToOneEncoder} for the JAGGRAB protocol.
* @author Graham
*/
public final class JagGrabResponseEncoder extends OneToOneEncoder {
@Override
protected Object encode(ChannelHandlerContext ctx, Channel c, Object msg) throws Exception {
if (msg instanceof JagGrabResponse) {
JagGrabResponse resp = (JagGrabResponse) msg;
return resp.getFileData();
}
return msg;
}
}
@@ -0,0 +1,109 @@
package org.apollo.jagcached.net.ondemand;
import org.apollo.jagcached.fs.FileDescriptor;
/**
* Represents a single 'on-demand' request.
* @author Graham
* @author Ryley Kimmel <ryley.kimmel@live.com>
*/
public final class OnDemandRequest implements Comparable<OnDemandRequest> {
/**
* An enumeration containing the different request priorities.
* @author Graham
*/
public enum Priority {
/**
* High priority - used in-game when data is required immediately but
* has not yet been received.
*/
HIGH,
/**
* Medium priority - used while loading the 'bare minimum' required to
* run the game.
*/
MEDIUM,
/**
* Low priority - used when a file is not required urgently. The client
* login screen says "loading extra files.." when low priority loading
* is being performed.
*/
LOW;
/**
* Converts the integer value to a priority.
* @param v The integer value.
* @return The priority.
* @throws IllegalArgumentException if the value is outside of the
* range 1-3 inclusive.
*/
public static Priority valueOf(int v) {
switch (v) {
case 0:
return HIGH;
case 1:
return MEDIUM;
case 2:
return LOW;
default:
throw new IllegalArgumentException("priority out of range");
}
}
}
/**
* The file descriptor.
*/
private final FileDescriptor fileDescriptor;
/**
* The request priority.
*/
private final Priority priority;
/**
* Creates the 'on-demand' request.
* @param fileDescriptor The file descriptor.
* @param priority The priority.
*/
public OnDemandRequest(FileDescriptor fileDescriptor, Priority priority) {
this.fileDescriptor = fileDescriptor;
this.priority = priority;
}
/**
* Gets the file descriptor.
* @return The file descriptor.
*/
public FileDescriptor getFileDescriptor() {
return fileDescriptor;
}
/**
* Gets the priority.
* @return The priority.
*/
public Priority getPriority() {
return priority;
}
@Override
public int compareTo(OnDemandRequest o) {
int thisPriority = priority.ordinal();
int otherPriority = o.priority.ordinal();
if (thisPriority < otherPriority) {
return 1;
} else if (thisPriority == otherPriority) {
return 0;
} else {
return -1;
}
}
}
@@ -0,0 +1,32 @@
package org.apollo.jagcached.net.ondemand;
import org.apollo.jagcached.fs.FileDescriptor;
import org.apollo.jagcached.net.ondemand.OnDemandRequest.Priority;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.handler.codec.frame.FrameDecoder;
/**
* A {@link FrameDecoder} for the 'on-demand' protocol.
* @author Graham
*/
public final class OnDemandRequestDecoder extends FrameDecoder {
@Override
protected Object decode(ChannelHandlerContext ctx, Channel c, ChannelBuffer buf) throws Exception {
if (buf.readableBytes() >= 4) {
int type = buf.readUnsignedByte() + 1;
int file = buf.readUnsignedShort();
int priority = buf.readUnsignedByte();
FileDescriptor desc = new FileDescriptor(type, file);
Priority p = Priority.valueOf(priority);
return new OnDemandRequest(desc, p);
}
return null;
}
}
@@ -0,0 +1,79 @@
package org.apollo.jagcached.net.ondemand;
import org.apollo.jagcached.fs.FileDescriptor;
import org.jboss.netty.buffer.ChannelBuffer;
/**
* Represents a single 'on-demand' response.
* @author Graham
*/
public final class OnDemandResponse {
/**
* The file descriptor.
*/
private final FileDescriptor fileDescriptor;
/**
* The file size.
*/
private final int fileSize;
/**
* The chunk id.
*/
private final int chunkId;
/**
* The chunk data.
*/
private final ChannelBuffer chunkData;
/**
* Creates the 'on-demand' response.
* @param fileDescriptor The file descriptor.
* @param fileSize The file size.
* @param chunkId The chunk id.
* @param chunkData The chunk data.
*/
public OnDemandResponse(FileDescriptor fileDescriptor, int fileSize, int chunkId, ChannelBuffer chunkData) {
this.fileDescriptor = fileDescriptor;
this.fileSize = fileSize;
this.chunkId = chunkId;
this.chunkData = chunkData;
}
/**
* Gets the file descriptor.
* @return The file descriptor.
*/
public FileDescriptor getFileDescriptor() {
return fileDescriptor;
}
/**
* Gets the file size.
* @return The file size.
*/
public int getFileSize() {
return fileSize;
}
/**
* Gets the chunk id.
* @return The chunk id.
*/
public int getChunkId() {
return chunkId;
}
/**
* Gets the chunk data.
* @return The chunk data.
*/
public ChannelBuffer getChunkData() {
return chunkData;
}
}
@@ -0,0 +1,39 @@
package org.apollo.jagcached.net.ondemand;
import org.apollo.jagcached.fs.FileDescriptor;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.handler.codec.oneone.OneToOneEncoder;
/**
* A {@link OneToOneEncoder} for the 'on-demand' protocol.
* @author Graham
*/
public final class OnDemandResponseEncoder extends OneToOneEncoder {
@Override
protected Object encode(ChannelHandlerContext ctx, Channel c, Object msg) throws Exception {
if (msg instanceof OnDemandResponse) {
OnDemandResponse resp = (OnDemandResponse) msg;
FileDescriptor fileDescriptor = resp.getFileDescriptor();
int fileSize = resp.getFileSize();
int chunkId = resp.getChunkId();
ChannelBuffer chunkData = resp.getChunkData();
ChannelBuffer buf = ChannelBuffers.buffer(6 + chunkData.readableBytes());
buf.writeByte(fileDescriptor.getType() - 1);
buf.writeShort(fileDescriptor.getFile());
buf.writeShort(fileSize);
buf.writeByte(chunkId);
buf.writeBytes(chunkData);
return buf;
}
return msg;
}
}
@@ -0,0 +1,40 @@
package org.apollo.jagcached.net.service;
/**
* Represents a service request message.
* @author Graham
*/
public final class ServiceRequest {
/**
* The game service id.
*/
public static final int SERVICE_GAME = 14;
/**
* The 'on-demand' service id.
*/
public static final int SERVICE_ONDEMAND = 15;
/**
* The service id.
*/
private final int id;
/**
* Creates a service request.
* @param id The service id.
*/
public ServiceRequest(int id) {
this.id = id;
}
/**
* Gets the service id.
* @return The service id.
*/
public int getId() {
return id;
}
}
@@ -0,0 +1,39 @@
package org.apollo.jagcached.net.service;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.handler.codec.frame.FrameDecoder;
/**
* A {@link FrameDecoder} which decodes {@link ServiceRequest} messages.
* @author Graham
*/
public final class ServiceRequestDecoder extends FrameDecoder {
/**
* Creates the decoder, enabling the 'unfold' mechanism.
*/
public ServiceRequestDecoder() {
super(true);
}
@Override
protected Object decode(ChannelHandlerContext ctx, Channel c, ChannelBuffer buf) throws Exception {
if (buf.readable()) {
ServiceRequest request = new ServiceRequest(buf.readUnsignedByte());
ChannelPipeline pipeline = ctx.getPipeline();
pipeline.remove(this);
if (buf.readable()) {
return new Object[] { request, buf.readBytes(buf.readableBytes()) };
} else {
return request;
}
}
return null;
}
}
@@ -0,0 +1,9 @@
package org.apollo.jagcached.net.service;
/**
* Represents a response to a service request.
* @author Graham
*/
public final class ServiceResponse {
}
@@ -0,0 +1,25 @@
package org.apollo.jagcached.net.service;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.handler.codec.oneone.OneToOneEncoder;
/**
* A {@link OneToOneEncoder} which encodes {@link ServiceResponse} messages.
* @author Graham
*/
public final class ServiceResponseEncoder extends OneToOneEncoder {
@Override
protected Object encode(ChannelHandlerContext ctx, Channel c, Object msg) throws Exception {
if (msg instanceof ServiceResponse) {
ChannelBuffer buf = ChannelBuffers.buffer(8);
buf.writeLong(0);
return buf;
}
return msg;
}
}