Start workin on async server to be able to support many concurrently open connections for long polling.
This commit is contained in:
25
gemp-lotr/gemp-lotr-async/pom.xml
Normal file
25
gemp-lotr/gemp-lotr-async/pom.xml
Normal file
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>gemp-lotr</artifactId>
|
||||
<groupId>com.gempukku.lotro</groupId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.gempukku.lotro</groupId>
|
||||
<artifactId>gemp-lotr-async</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>gemp-lotr-web-server</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty</artifactId>
|
||||
<version>3.6.1.Final</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -0,0 +1,104 @@
|
||||
package com.gempukku.lotro.async;
|
||||
|
||||
import org.jboss.netty.buffer.ChannelBuffer;
|
||||
import org.jboss.netty.buffer.ChannelBuffers;
|
||||
import org.jboss.netty.channel.*;
|
||||
import org.jboss.netty.handler.codec.http.*;
|
||||
import static org.jboss.netty.handler.codec.http.HttpHeaders.Names.CONTENT_LENGTH;
|
||||
import static org.jboss.netty.handler.codec.http.HttpHeaders.Names.CONTENT_TYPE;
|
||||
import static org.jboss.netty.handler.codec.http.HttpHeaders.is100ContinueExpected;
|
||||
import static org.jboss.netty.handler.codec.http.HttpHeaders.isKeepAlive;
|
||||
import static org.jboss.netty.handler.codec.http.HttpResponseStatus.*;
|
||||
import static org.jboss.netty.handler.codec.http.HttpVersion.HTTP_1_1;
|
||||
import org.jboss.netty.util.CharsetUtil;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class HttpRequestHandler extends SimpleChannelUpstreamHandler {
|
||||
|
||||
private HttpRequest _request;
|
||||
private boolean _readingChunks;
|
||||
private String _uri;
|
||||
private Map<Type, Object> _objects;
|
||||
|
||||
public HttpRequestHandler(Map<Type, Object> objects) {
|
||||
_objects = objects;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
|
||||
_request = (HttpRequest) e.getMessage();
|
||||
|
||||
if (is100ContinueExpected(_request)) {
|
||||
send100Continue(e);
|
||||
}
|
||||
|
||||
String uri = _request.getUri();
|
||||
|
||||
if (uri.indexOf("?")>-1)
|
||||
_uri = uri.substring(0, uri.indexOf("?"));
|
||||
else
|
||||
_uri = uri;
|
||||
|
||||
QueryStringDecoder queryStringDecoder = new QueryStringDecoder(_request.getUri());
|
||||
Map<String, List<String>> queryStringParams = queryStringDecoder.getParameters();
|
||||
|
||||
HttpMethod httpMethod = _request.getMethod();
|
||||
|
||||
if (_request.isChunked()) {
|
||||
send400Error(e);
|
||||
} else {
|
||||
ChannelBuffer content = _request.getContent();
|
||||
if (content.readable()) {
|
||||
}
|
||||
writeResponse(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void writeResponse(MessageEvent e) {
|
||||
// Decide whether to close the connection or not.
|
||||
boolean keepAlive = isKeepAlive(_request);
|
||||
|
||||
// Build the response object.
|
||||
HttpResponse response = new DefaultHttpResponse(HTTP_1_1, OK);
|
||||
response.setContent(ChannelBuffers.copiedBuffer("Response: " + _uri, CharsetUtil.UTF_8));
|
||||
response.setHeader(CONTENT_TYPE, "text/plain; charset=UTF-8");
|
||||
|
||||
if (keepAlive) {
|
||||
// Add 'Content-Length' header only for a keep-alive connection.
|
||||
response.setHeader(CONTENT_LENGTH, response.getContent().readableBytes());
|
||||
}
|
||||
|
||||
// Write the response.
|
||||
ChannelFuture future = e.getChannel().write(response);
|
||||
|
||||
// Close the non-keep-alive connection after the write operation is done.
|
||||
if (!keepAlive) {
|
||||
future.addListener(ChannelFutureListener.CLOSE);
|
||||
}
|
||||
}
|
||||
|
||||
private void send400Error(MessageEvent e) {
|
||||
boolean keepAlive = isKeepAlive(_request);
|
||||
|
||||
HttpResponse response = new DefaultHttpResponse(HTTP_1_1, BAD_REQUEST);
|
||||
ChannelFuture future = e.getChannel().write(response);
|
||||
if (!keepAlive) {
|
||||
future.addListener(ChannelFutureListener.CLOSE);
|
||||
}
|
||||
}
|
||||
|
||||
private void send100Continue(MessageEvent e) {
|
||||
HttpResponse response = new DefaultHttpResponse(HTTP_1_1, CONTINUE);
|
||||
e.getChannel().write(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e)
|
||||
throws Exception {
|
||||
e.getCause().printStackTrace();
|
||||
e.getChannel().close();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.gempukku.lotro.async;
|
||||
|
||||
import com.gempukku.lotro.packs.PacksStorage;
|
||||
import com.gempukku.lotro.server.provider.DaoBuilder;
|
||||
import com.gempukku.lotro.server.provider.PacksStorageBuilder;
|
||||
import com.gempukku.lotro.server.provider.ServerBuilder;
|
||||
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.HttpContentCompressor;
|
||||
import org.jboss.netty.handler.codec.http.HttpRequestDecoder;
|
||||
import org.jboss.netty.handler.codec.http.HttpResponseEncoder;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class HttpServerPipelineFactory implements ChannelPipelineFactory {
|
||||
public ChannelPipeline getPipeline() throws Exception {
|
||||
// Create a default pipeline implementation.
|
||||
ChannelPipeline pipeline = Channels.pipeline();
|
||||
|
||||
// Uncomment the following line if you want HTTPS
|
||||
//SSLEngine engine = SecureChatSslContextFactory.getServerContext().createSSLEngine();
|
||||
//engine.setUseClientMode(false);
|
||||
//pipeline.addLast("ssl", new SslHandler(engine));
|
||||
|
||||
pipeline.addLast("decoder", new HttpRequestDecoder());
|
||||
// Uncomment the following line if you don't want to handle HttpChunks.
|
||||
//pipeline.addLast("aggregator", new HttpChunkAggregator(1048576));
|
||||
pipeline.addLast("encoder", new HttpResponseEncoder());
|
||||
// Remove the following line if you don't want automatic content compression.
|
||||
pipeline.addLast("deflater", new HttpContentCompressor());
|
||||
|
||||
Map<Type, Object> objects = new HashMap<Type, Object>();
|
||||
objects.put(PacksStorage.class, PacksStorageBuilder.createPacksStorage());
|
||||
DaoBuilder.fillObjectMap(objects);
|
||||
ServerBuilder.fillObjectMap(objects);
|
||||
ServerBuilder.constructObjects(objects);
|
||||
|
||||
pipeline.addLast("handler", new HttpRequestHandler(objects));
|
||||
return pipeline;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.gempukku.lotro.async;
|
||||
|
||||
import org.jboss.netty.bootstrap.ServerBootstrap;
|
||||
import org.jboss.netty.channel.ChannelFactory;
|
||||
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
public class LotroAsyncServer {
|
||||
public static void main(String[] server) {
|
||||
ChannelFactory factory =
|
||||
new NioServerSocketChannelFactory(
|
||||
Executors.newCachedThreadPool(),
|
||||
Executors.newCachedThreadPool());
|
||||
|
||||
|
||||
ServerBootstrap bootstrap = new ServerBootstrap(factory);
|
||||
|
||||
bootstrap.setPipelineFactory(new HttpServerPipelineFactory());
|
||||
|
||||
bootstrap.setOption("child.tcpNoDelay", true);
|
||||
bootstrap.setOption("child.keepAlive", true);
|
||||
bootstrap.bind(new InetSocketAddress(8080));
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import com.gempukku.lotro.game.PhysicalCard;
|
||||
import com.gempukku.lotro.logic.decisions.AwaitingDecision;
|
||||
import com.gempukku.lotro.logic.timing.GameStats;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
public class GameEvent {
|
||||
@@ -18,9 +19,10 @@ public class GameEvent {
|
||||
AT, RT,
|
||||
M, W,
|
||||
GS,
|
||||
CAC, EP, CA, D
|
||||
CAC, EP, CA, D, CH
|
||||
}
|
||||
|
||||
private Date _date;
|
||||
private String _message;
|
||||
private String _side;
|
||||
private Type _type;
|
||||
@@ -43,6 +45,15 @@ public class GameEvent {
|
||||
_type = type;
|
||||
}
|
||||
|
||||
public Date getDate() {
|
||||
return _date;
|
||||
}
|
||||
|
||||
public GameEvent date(Date date) {
|
||||
_date = date;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Integer getIndex() {
|
||||
return _index;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user