diff --git a/gemp-lotr/gemp-lotr-async/src/main/java/com/gempukku/lotro/async/LotroHttpRequestHandler.java b/gemp-lotr/gemp-lotr-async/src/main/java/com/gempukku/lotro/async/LotroHttpRequestHandler.java index db3b660ff..2f5d6164b 100644 --- a/gemp-lotr/gemp-lotr-async/src/main/java/com/gempukku/lotro/async/LotroHttpRequestHandler.java +++ b/gemp-lotr/gemp-lotr-async/src/main/java/com/gempukku/lotro/async/LotroHttpRequestHandler.java @@ -5,7 +5,12 @@ import com.gempukku.lotro.db.IpBanDAO; import org.apache.commons.io.IOUtils; import org.apache.log4j.Logger; import org.jboss.netty.buffer.ChannelBuffers; -import org.jboss.netty.channel.*; +import org.jboss.netty.channel.ChannelFuture; +import org.jboss.netty.channel.ChannelFutureListener; +import org.jboss.netty.channel.ChannelHandlerContext; +import org.jboss.netty.channel.ExceptionEvent; +import org.jboss.netty.channel.MessageEvent; +import org.jboss.netty.channel.SimpleChannelUpstreamHandler; import org.jboss.netty.handler.codec.http.DefaultHttpResponse; import org.jboss.netty.handler.codec.http.HttpRequest; import org.jboss.netty.handler.codec.http.HttpResponse; @@ -17,7 +22,11 @@ import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; -import java.io.*; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.StringWriter; import java.lang.reflect.Type; import java.net.InetSocketAddress; import java.text.SimpleDateFormat; @@ -26,10 +35,16 @@ import java.util.Date; import java.util.HashMap; import java.util.Map; -import static org.jboss.netty.handler.codec.http.HttpHeaders.Names.*; +import static org.jboss.netty.handler.codec.http.HttpHeaders.Names.CACHE_CONTROL; +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.Names.EXPIRES; +import static org.jboss.netty.handler.codec.http.HttpHeaders.Names.PRAGMA; 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.HttpResponseStatus.BAD_REQUEST; +import static org.jboss.netty.handler.codec.http.HttpResponseStatus.CONTINUE; +import static org.jboss.netty.handler.codec.http.HttpResponseStatus.OK; import static org.jboss.netty.handler.codec.http.HttpVersion.HTTP_1_1; public class LotroHttpRequestHandler extends SimpleChannelUpstreamHandler { @@ -110,9 +125,7 @@ public class LotroHttpRequestHandler extends SimpleChannelUpstreamHandler { } @Override - public void writeByteResponse(String contentType, byte[] bytes) { - Map headers = new HashMap(); - headers.put(CONTENT_TYPE, contentType); + public void writeByteResponse(byte[] bytes, Map headers) { writeHttpByteResponse(requestInformation, request, bytes, headers, e); } diff --git a/gemp-lotr/gemp-lotr-async/src/main/java/com/gempukku/lotro/async/ResponseWriter.java b/gemp-lotr/gemp-lotr-async/src/main/java/com/gempukku/lotro/async/ResponseWriter.java index 7b102ee1d..6a1030765 100644 --- a/gemp-lotr/gemp-lotr-async/src/main/java/com/gempukku/lotro/async/ResponseWriter.java +++ b/gemp-lotr/gemp-lotr-async/src/main/java/com/gempukku/lotro/async/ResponseWriter.java @@ -13,7 +13,7 @@ public interface ResponseWriter { public void writeHtmlResponse(String html); - public void writeByteResponse(String contentType, byte[] bytes); + public void writeByteResponse(byte[] bytes, Map headers); public void writeXmlResponse(Document document); diff --git a/gemp-lotr/gemp-lotr-async/src/main/java/com/gempukku/lotro/async/handler/MtgCardsRequestHandler.java b/gemp-lotr/gemp-lotr-async/src/main/java/com/gempukku/lotro/async/handler/MtgCardsRequestHandler.java new file mode 100644 index 000000000..8ab568acc --- /dev/null +++ b/gemp-lotr/gemp-lotr-async/src/main/java/com/gempukku/lotro/async/handler/MtgCardsRequestHandler.java @@ -0,0 +1,49 @@ +package com.gempukku.lotro.async.handler; + +import com.gempukku.lotro.async.ResponseWriter; +import com.gempukku.mtg.MtgCardServer; +import org.jboss.netty.channel.MessageEvent; +import org.jboss.netty.handler.codec.http.HttpHeaders; +import org.jboss.netty.handler.codec.http.HttpRequest; + +import java.lang.reflect.Type; +import java.util.HashMap; +import java.util.Map; + +import static org.jboss.netty.handler.codec.http.HttpHeaders.Names.CONTENT_TYPE; +import static org.jboss.netty.handler.codec.http.HttpHeaders.Names.IF_NONE_MATCH; + +public class MtgCardsRequestHandler implements UriRequestHandler { + private MtgCardServer _mtgCardServer; + + public MtgCardsRequestHandler(Map context) { + _mtgCardServer = (MtgCardServer) context.get(MtgCardServer.class); + } + + @Override + public void handleRequest(String uri, HttpRequest request, Map context, ResponseWriter responseWriter, MessageEvent e) throws Exception { + MtgCardServer.CardDatabaseHolder cardDatabaseHolder = _mtgCardServer.getCardDatabaseHolder(); + if (cardDatabaseHolder == null || clientHasCurrentVersion(request, cardDatabaseHolder.getUpdateMarker())) { + responseWriter.writeError(304); + return; + } + + Map headers = new HashMap(); + headers.put(CONTENT_TYPE, "application/json; charset=UTF-8"); + headers.put(HttpHeaders.Names.ETAG, cardDatabaseHolder.getUpdateMarker()); + + responseWriter.writeByteResponse(cardDatabaseHolder.getBytes(), headers); + } + + private boolean clientHasCurrentVersion(HttpRequest request, String version) { + String ifNoneMatch = request.getHeader(IF_NONE_MATCH); + if (ifNoneMatch != null) { + String[] clientKnownVersions = ifNoneMatch.split(","); + for (String clientKnownVersion : clientKnownVersions) { + if (clientKnownVersion.trim().equals(version)) + return true; + } + } + return false; + } +} diff --git a/gemp-lotr/gemp-lotr-async/src/main/java/com/gempukku/lotro/async/handler/ReplayRequestHandler.java b/gemp-lotr/gemp-lotr-async/src/main/java/com/gempukku/lotro/async/handler/ReplayRequestHandler.java index 8b3a2d4a2..8da6eb424 100644 --- a/gemp-lotr/gemp-lotr-async/src/main/java/com/gempukku/lotro/async/handler/ReplayRequestHandler.java +++ b/gemp-lotr/gemp-lotr-async/src/main/java/com/gempukku/lotro/async/handler/ReplayRequestHandler.java @@ -10,8 +10,11 @@ import org.jboss.netty.handler.codec.http.HttpRequest; import java.io.ByteArrayOutputStream; import java.io.InputStream; import java.lang.reflect.Type; +import java.util.HashMap; import java.util.Map; +import static org.jboss.netty.handler.codec.http.HttpHeaders.Names.CONTENT_TYPE; + public class ReplayRequestHandler extends LotroServerRequestHandler implements UriRequestHandler { private GameRecorder _gameRecorder; @@ -49,7 +52,10 @@ public class ReplayRequestHandler extends LotroServerRequestHandler implements U recordedGame.close(); } - responseWriter.writeByteResponse("application/html; charset=UTF-8", baos.toByteArray()); + Map headers = new HashMap(); + headers.put(CONTENT_TYPE, "application/html; charset=UTF-8"); + + responseWriter.writeByteResponse(baos.toByteArray(), headers); } else { responseWriter.writeError(404); } diff --git a/gemp-lotr/gemp-lotr-async/src/main/java/com/gempukku/lotro/async/handler/RootUriRequestHandler.java b/gemp-lotr/gemp-lotr-async/src/main/java/com/gempukku/lotro/async/handler/RootUriRequestHandler.java index 22d5caca2..cf9d3f70d 100644 --- a/gemp-lotr/gemp-lotr-async/src/main/java/com/gempukku/lotro/async/handler/RootUriRequestHandler.java +++ b/gemp-lotr/gemp-lotr-async/src/main/java/com/gempukku/lotro/async/handler/RootUriRequestHandler.java @@ -30,6 +30,7 @@ public class RootUriRequestHandler implements UriRequestHandler { private ServerStatsRequestHandler _serverStatsRequestHandler; private PlayerStatsRequestHandler _playerStatsRequestHandler; private TournamentRequestHandler _tournamentRequestHandler; + private MtgCardsRequestHandler _mtgCardsRequestHandler; public RootUriRequestHandler(Map context) { _webRequestHandler = new WebRequestHandler(ApplicationConfiguration.getProperty("web.path")); @@ -50,12 +51,15 @@ public class RootUriRequestHandler implements UriRequestHandler { _serverStatsRequestHandler = new ServerStatsRequestHandler(context); _playerStatsRequestHandler = new PlayerStatsRequestHandler(context); _tournamentRequestHandler = new TournamentRequestHandler(context); + _mtgCardsRequestHandler = new MtgCardsRequestHandler(context); } @Override public void handleRequest(String uri, HttpRequest request, Map context, ResponseWriter responseWriter, MessageEvent e) throws Exception { if (uri.startsWith(_webContextPath)) { _webRequestHandler.handleRequest(uri.substring(_webContextPath.length()), request, context, responseWriter, e); + } else if (uri.equals("/mtg-cards/database.json")) { + _mtgCardsRequestHandler.handleRequest(uri, request, context, responseWriter, e); } else if (uri.equals("/gemp-lotr")) { responseWriter.writeError(301, Collections.singletonMap("Location", "/gemp-lotr/")); } else if (uri.startsWith(_serverContextPath +"hall")) { diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/builder/ServerBuilder.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/builder/ServerBuilder.java index 1f2c41e86..61c367fb6 100644 --- a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/builder/ServerBuilder.java +++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/builder/ServerBuilder.java @@ -32,9 +32,13 @@ import com.gempukku.lotro.tournament.TournamentMatchDAO; import com.gempukku.lotro.tournament.TournamentPlayerDAO; import com.gempukku.lotro.tournament.TournamentPrizeSchemeRegistry; import com.gempukku.lotro.tournament.TournamentService; +import com.gempukku.mtg.MtgCardServer; import java.lang.reflect.Type; +import java.text.ParseException; +import java.text.SimpleDateFormat; import java.util.Map; +import java.util.TimeZone; public class ServerBuilder { public static void fillObjectMap(Map objectMap) { @@ -120,6 +124,17 @@ public class ServerBuilder { pairingMechanismRegistry, extract(objectMap, CardSets.class) )); + + try { + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + sdf.setTimeZone(TimeZone.getTimeZone("EST")); + + long someDownloadTime = sdf.parse("2015-01-01 04:25:00").getTime(); + objectMap.put(MtgCardServer.class, + new MtgCardServer(someDownloadTime, 24L * 60 * 60 * 1000)); + } catch (ParseException exp) { + + } } private static T extract(Map objectMap, Class clazz) { @@ -130,12 +145,14 @@ public class ServerBuilder { } public static void constructObjects(Map objectMap) { + extract(objectMap, MtgCardServer.class).startServer(); extract(objectMap, HallServer.class).startServer(); extract(objectMap, LotroServer.class).startServer(); extract(objectMap, ChatServer.class).startServer(); } public static void destroyObjects(Map objectMap) { + extract(objectMap, MtgCardServer.class).stopServer(); extract(objectMap, HallServer.class).stopServer(); extract(objectMap, LotroServer.class).stopServer(); extract(objectMap, ChatServer.class).stopServer(); diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/mtg/MtgCardServer.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/mtg/MtgCardServer.java new file mode 100644 index 000000000..d66beb2a4 --- /dev/null +++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/mtg/MtgCardServer.java @@ -0,0 +1,73 @@ +package com.gempukku.mtg; + +import com.gempukku.lotro.AbstractServer; + +import java.nio.charset.Charset; + +public class MtgCardServer extends AbstractServer { + private volatile CardDatabaseHolder _cardDatabaseHolder; + private long _downloadEvery; + private long _nextStart; + + public MtgCardServer(long someDownloadTime, long downloadEvery) { + _downloadEvery = downloadEvery; + + long number = (System.currentTimeMillis() - someDownloadTime) / downloadEvery; + + _nextStart = someDownloadTime + number * downloadEvery; + } + + private void updateDatabase() { + Thread thr = new Thread(new UpdateDatabase()); + thr.start(); + } + + public CardDatabaseHolder getCardDatabaseHolder() { + return _cardDatabaseHolder; + } + + @Override + protected void cleanup() { + if (_nextStart < System.currentTimeMillis()) { + updateDatabase(); + _nextStart += _downloadEvery; + } + } + + public class CardDatabaseHolder { + private String _updateMarker; + private byte[] _bytes; + + public CardDatabaseHolder(byte[] bytes, String updateMarker) { + _bytes = bytes; + _updateMarker = updateMarker; + } + + public String getUpdateMarker() { + return _updateMarker; + } + + public byte[] getBytes() { + return _bytes; + } + } + + private byte[] getDatabase() { + String exampleString = "[" + + "{\"id\":\"sc\",\"name\":\"Snapcaster Mage\",\"info\":\"Innistrad\",\"midPrice\":5956}," + + "{\"id\":\"scf\",\"name\":\"Snapcaster Mage\",\"info\":\"Innistrad ยท Foil\",\"midPrice\":18040}," + + "{\"id\":\"ara\",\"name\":\"Ancestral Recall\",\"info\":\"Alpha\",\"midPrice\":500000}," + + "{\"id\":\"ara\",\"name\":\"Ancestral Recall\",\"info\":\"Beta\",\"midPrice\":300000}," + + "{\"id\":\"ara\",\"name\":\"Ancestral Recall\",\"info\":\"Unlimited\",\"midPrice\":50000}" + + "]"; + return exampleString.getBytes(Charset.forName("UTF-8")); + } + + public class UpdateDatabase implements Runnable { + public void run() { + String updateMarker = String.valueOf(System.currentTimeMillis()); + + _cardDatabaseHolder = new CardDatabaseHolder(getDatabase(), updateMarker); + } + } +}