Kicks and bans.
Admin chat in blue. Chat commands (/names, /kick, /ban to start). Close Hibernate session after loading card sets when a user connects -- Oops! Games have their own Hibernate session for their duration, and this is used instead of a per-request session for loading card sets when changing options. Fix changing game options without having a card set selected.
This commit is contained in:
parent
69ec34e072
commit
7fccd69b15
|
@ -28,6 +28,9 @@ Administration tools.
|
|||
--%>
|
||||
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
|
||||
<%@ page import="com.google.inject.Injector" %>
|
||||
<%@ page import="com.google.inject.Key" %>
|
||||
<%@ page import="com.google.inject.TypeLiteral" %>
|
||||
<%@ page import="net.socialgamer.cah.CahModule.BanList" %>
|
||||
<%@ page import="net.socialgamer.cah.Constants.DisconnectReason" %>
|
||||
<%@ page import="net.socialgamer.cah.Constants.LongPollEvent" %>
|
||||
<%@ page import="net.socialgamer.cah.Constants.LongPollResponse" %>
|
||||
|
@ -41,6 +44,7 @@ Administration tools.
|
|||
<%@ page import="java.util.Date" %>
|
||||
<%@ page import="java.util.HashMap" %>
|
||||
<%@ page import="java.util.Map" %>
|
||||
<%@ page import="java.util.Set" %>
|
||||
|
||||
<%
|
||||
String remoteAddr = request.getRemoteAddr();
|
||||
|
@ -55,6 +59,7 @@ ServletContext servletContext = pageContext.getServletContext();
|
|||
Injector injector = (Injector) servletContext.getAttribute(StartupUtils.INJECTOR);
|
||||
|
||||
ConnectedUsers connectedUsers = injector.getInstance(ConnectedUsers.class);
|
||||
Set<String> banList = injector.getInstance(Key.get(new TypeLiteral<Set<String>>(){}, BanList.class));
|
||||
|
||||
// process verbose toggle
|
||||
String verboseParam = request.getParameter("verbose");
|
||||
|
@ -84,13 +89,38 @@ if (kickParam != null) {
|
|||
return;
|
||||
}
|
||||
|
||||
// process ban
|
||||
String banParam = request.getParameter("ban");
|
||||
if (banParam != null) {
|
||||
User user = connectedUsers.getUser(banParam);
|
||||
if (user != null) {
|
||||
Map<ReturnableData, Object> data = new HashMap<ReturnableData, Object>();
|
||||
data.put(LongPollResponse.EVENT, LongPollEvent.BANNED.toString());
|
||||
QueuedMessage qm = new QueuedMessage(MessageType.KICKED, data);
|
||||
user.enqueueMessage(qm);
|
||||
|
||||
connectedUsers.removeUser(user, DisconnectReason.BANNED);
|
||||
banList.add(user.getHostName());
|
||||
}
|
||||
response.sendRedirect("admin.jsp");
|
||||
return;
|
||||
}
|
||||
|
||||
// process unban
|
||||
String unbanParam = request.getParameter("unban");
|
||||
if (unbanParam != null) {
|
||||
banList.remove(unbanParam);
|
||||
response.sendRedirect("admin.jsp");
|
||||
return;
|
||||
}
|
||||
|
||||
%>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
<title>CAH - Admin</title>
|
||||
<title>PYX - Admin</title>
|
||||
<style type="text/css" media="screen">
|
||||
table, th, td {
|
||||
border: 1px solid black;
|
||||
|
@ -125,8 +155,8 @@ th, td {
|
|||
</tr>
|
||||
<tr>
|
||||
<td>In Use</td>
|
||||
<td><% out.print((Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory())
|
||||
/ 1024L / 1024L); %></td>
|
||||
<td><%= (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory())
|
||||
/ 1024L / 1024L %></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Free</td>
|
||||
|
@ -142,6 +172,25 @@ th, td {
|
|||
</tr>
|
||||
</table>
|
||||
<br/>
|
||||
Ban list:
|
||||
<table>
|
||||
<tr>
|
||||
<th>Host</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
<%
|
||||
for (String host : banList) {
|
||||
%>
|
||||
<tr>
|
||||
<td><%= host %></td>
|
||||
<td><a href="?unban=<%= host %>">Unban</a></td>
|
||||
</tr>
|
||||
<%
|
||||
}
|
||||
%>
|
||||
</table>
|
||||
<br/>
|
||||
User list:
|
||||
<table>
|
||||
<tr>
|
||||
<th>Username</th>
|
||||
|
@ -154,9 +203,12 @@ th, td {
|
|||
// TODO have a ban system. would need to store them somewhere.
|
||||
%>
|
||||
<tr>
|
||||
<td><% out.print(u.getNickname()); %></td>
|
||||
<td><% out.print(u.getHostName()); %></td>
|
||||
<td><a href="?kick=<% out.print(u.getNickname()); %>">Kick</a></td>
|
||||
<td><%= u.getNickname() %></td>
|
||||
<td><%= u.getHostName() %></td>
|
||||
<td>
|
||||
<a href="?kick=<%= u.getNickname() %>">Kick</a>
|
||||
<a href="?ban=<%= u.getNickname() %>">Ban</a>
|
||||
</td>
|
||||
</tr>
|
||||
<%
|
||||
}
|
||||
|
@ -168,7 +220,7 @@ Boolean verboseDebugObj = (Boolean) servletContext.getAttribute(StartupUtils.VER
|
|||
boolean verboseDebug = verboseDebugObj != null ? verboseDebugObj.booleanValue() : false;
|
||||
%>
|
||||
<p>
|
||||
Verbose logging is currently <strong><% out.print(verboseDebug ? "ON" : "OFF"); %></strong>.
|
||||
Verbose logging is currently <strong><%= verboseDebug ? "ON" : "OFF" %></strong>.
|
||||
<a href="?verbose=on">Turn on.</a> <a href="?verbose=off">Turn off.</a>
|
||||
</p>
|
||||
|
||||
|
|
|
@ -53,6 +53,14 @@ to, for instance, display the number of connected players.
|
|||
</p>
|
||||
<p>Recent Changes:</p>
|
||||
<ul>
|
||||
<li>21 August, 6:00 AM UTC:<ul>
|
||||
<li>Ban list. Only admins can ban.</li>
|
||||
<li>Chat from admins shows up in blue.</li>
|
||||
<li>
|
||||
Currently, the admin list contains just me and a close friend. I am not taking applications.
|
||||
</li>
|
||||
<li>Performance and stability tweaks.</li>
|
||||
</ul></li>
|
||||
<li>7 July, 10:00 PM UTC:<ul>
|
||||
<li>Proper Card Set support. Currently, only I can define the cards and card sets, but I hope to
|
||||
eventually let users define their own. This leads into the next item...</li>
|
||||
|
|
|
@ -167,3 +167,11 @@ cah.ajax.SuccessHandlers[cah.$.AjaxOperation.JUDGE_SELECT] = function(data) {
|
|||
cah.ajax.SuccessHandlers[cah.$.AjaxOperation.CHANGE_GAME_OPTIONS] = function(data) {
|
||||
// pass
|
||||
};
|
||||
|
||||
cah.ajax.SuccessHandlers[cah.$.AjaxOperation.KICK] = function(data) {
|
||||
// pass
|
||||
};
|
||||
|
||||
cah.ajax.SuccessHandlers[cah.$.AjaxOperation.BAN] = function(data) {
|
||||
// pass
|
||||
};
|
||||
|
|
|
@ -109,9 +109,34 @@ function chatsubmit_click() {
|
|||
if (text == "") {
|
||||
return;
|
||||
}
|
||||
var cmd = '';
|
||||
if ('/' == text.substring(0, 1)) {
|
||||
cmd = text.substring(1, text.indexOf(' ') >= 0 ? text.indexOf(' ') : undefined);
|
||||
if (text.indexOf(' ') >= 0) {
|
||||
text = text.substring(text.indexOf(' ') + 1);
|
||||
} else {
|
||||
text = '';
|
||||
}
|
||||
}
|
||||
switch (cmd) {
|
||||
case '':
|
||||
// TODO when I get multiple channels working, this needs to know active and pass it
|
||||
cah.Ajax.build(cah.$.AjaxOperation.CHAT).withMessage(text).run();
|
||||
cah.log.status("<" + cah.nickname + "> " + text);
|
||||
break;
|
||||
case 'kick':
|
||||
cah.Ajax.build(cah.$.AjaxOperation.KICK).withNickname(text.split(' ')[0]).run();
|
||||
break;
|
||||
case 'ban':
|
||||
// this could also be an IP address
|
||||
cah.Ajax.build(cah.$.AjaxOperation.BAN).withNickname(text.split(' ')[0]).run();
|
||||
break;
|
||||
case 'names':
|
||||
cah.Ajax.build(cah.$.AjaxOperation.NAMES).run();
|
||||
break;
|
||||
default:
|
||||
}
|
||||
|
||||
$("#chat").val("");
|
||||
$("#chat").focus();
|
||||
}
|
||||
|
|
|
@ -8,20 +8,22 @@ cah.$.AjaxOperation = function() {
|
|||
cah.$.AjaxOperation.prototype.dummyForAutocomplete = undefined;
|
||||
cah.$.AjaxOperation.START_GAME = "sg";
|
||||
cah.$.AjaxOperation.FIRST_LOAD = "fl";
|
||||
cah.$.AjaxOperation.JUDGE_SELECT = "js";
|
||||
cah.$.AjaxOperation.LOG_OUT = "lo";
|
||||
cah.$.AjaxOperation.BAN = "b";
|
||||
cah.$.AjaxOperation.JUDGE_SELECT = "js";
|
||||
cah.$.AjaxOperation.GAME_LIST = "ggl";
|
||||
cah.$.AjaxOperation.CHANGE_GAME_OPTIONS = "cgo";
|
||||
cah.$.AjaxOperation.GET_GAME_INFO = "ggi";
|
||||
cah.$.AjaxOperation.PLAY_CARD = "pc";
|
||||
cah.$.AjaxOperation.CREATE_GAME = "cg";
|
||||
cah.$.AjaxOperation.KICK = "K";
|
||||
cah.$.AjaxOperation.ADMIN_SET_VERBOSE_LOG = "svl";
|
||||
cah.$.AjaxOperation.GET_CARDS = "gc";
|
||||
cah.$.AjaxOperation.JOIN_GAME = "jg";
|
||||
cah.$.AjaxOperation.REGISTER = "r";
|
||||
cah.$.AjaxOperation.CHAT = "c";
|
||||
cah.$.AjaxOperation.LEAVE_GAME = "lg";
|
||||
cah.$.AjaxOperation.NAMES = "gn";
|
||||
cah.$.AjaxOperation.LEAVE_GAME = "lg";
|
||||
|
||||
cah.$.AjaxRequest = function() {
|
||||
// Dummy constructor to make Eclipse auto-complete.
|
||||
|
@ -84,6 +86,7 @@ cah.$.DisconnectReason = function() {
|
|||
// Dummy constructor to make Eclipse auto-complete.
|
||||
};
|
||||
cah.$.DisconnectReason.prototype.dummyForAutocomplete = undefined;
|
||||
cah.$.DisconnectReason.BANNED = "B&";
|
||||
cah.$.DisconnectReason.PING_TIMEOUT = "pt";
|
||||
cah.$.DisconnectReason.KICKED = "k";
|
||||
cah.$.DisconnectReason.MANUAL = "man";
|
||||
|
@ -103,18 +106,21 @@ cah.$.ErrorCode.SESSION_EXPIRED = "se";
|
|||
cah.$.ErrorCode.BAD_OP = "bo";
|
||||
cah.$.ErrorCode.NO_SESSION = "ns";
|
||||
cah.$.ErrorCode.NOT_REGISTERED = "nr";
|
||||
cah.$.ErrorCode.NOT_JUDGE = "nj";
|
||||
cah.$.ErrorCode.OP_NOT_SPECIFIED = "ons";
|
||||
cah.$.ErrorCode.NOT_JUDGE = "nj";
|
||||
cah.$.ErrorCode.WRONG_PASSWORD = "wp";
|
||||
cah.$.ErrorCode.NOT_IN_THAT_GAME = "nitg";
|
||||
cah.$.ErrorCode.NICK_IN_USE = "niu";
|
||||
cah.$.ErrorCode.SERVER_ERROR = "serr";
|
||||
cah.$.ErrorCode.GAME_FULL = "gf";
|
||||
cah.$.ErrorCode.NO_NICK_SPECIFIED = "nns";
|
||||
cah.$.ErrorCode.NOT_ADMIN = "na";
|
||||
cah.$.ErrorCode.NOT_YOUR_TURN = "nyt";
|
||||
cah.$.ErrorCode.BANNED = "B&";
|
||||
cah.$.ErrorCode.INVALID_NICK = "in";
|
||||
cah.$.ErrorCode.ALREADY_STARTED = "as";
|
||||
cah.$.ErrorCode.BAD_REQUEST = "br";
|
||||
cah.$.ErrorCode.NO_SUCH_USER = "nsu";
|
||||
cah.$.ErrorCode.DO_NOT_HAVE_CARD = "dnhc";
|
||||
cah.$.ErrorCode.MESSAGE_TOO_LONG = "mtl";
|
||||
cah.$.ErrorCode.NOT_ENOUGH_PLAYERS = "nep";
|
||||
|
@ -136,19 +142,22 @@ cah.$.ErrorCode_msg['ngs'] = "No game specified.";
|
|||
cah.$.ErrorCode_msg['ic'] = "Invalid card specified.";
|
||||
cah.$.ErrorCode_msg['bo'] = "Invalid operation.";
|
||||
cah.$.ErrorCode_msg['dnhc'] = "You don't have that card.";
|
||||
cah.$.ErrorCode_msg['cjag'] = "You cannot join another game.";
|
||||
cah.$.ErrorCode_msg['ons'] = "Operation not specified.";
|
||||
cah.$.ErrorCode_msg['cjag'] = "You cannot join another game.";
|
||||
cah.$.ErrorCode_msg['ig'] = "Invalid game specified.";
|
||||
cah.$.ErrorCode_msg['nns'] = "No nickname specified.";
|
||||
cah.$.ErrorCode_msg['ngh'] = "Only the game host can do that.";
|
||||
cah.$.ErrorCode_msg['nec'] = "You must select at least one base card set.";
|
||||
cah.$.ErrorCode_msg['serr'] = "An error occured on the server.";
|
||||
cah.$.ErrorCode_msg['nsu'] = "No such user.";
|
||||
cah.$.ErrorCode_msg['wp'] = "That password is incorrect.";
|
||||
cah.$.ErrorCode_msg['as'] = "The game has already started.";
|
||||
cah.$.ErrorCode_msg['se'] = "Your session has expired. Refresh the page.";
|
||||
cah.$.ErrorCode_msg['in'] = "Nickname must contain only upper and lower case letters, numbers, or underscores, must be 3 to 30 characters long, and must not start with a number.";
|
||||
cah.$.ErrorCode_msg['nms'] = "No message specified.";
|
||||
cah.$.ErrorCode_msg['na'] = "You are not an administrator.";
|
||||
cah.$.ErrorCode_msg['niu'] = "Nickname is already in use.";
|
||||
cah.$.ErrorCode_msg['B&'] = "Banned.";
|
||||
cah.$.ErrorCode_msg['ad'] = "Access denied.";
|
||||
cah.$.ErrorCode_msg['nj'] = "You aren't the judge.";
|
||||
|
||||
|
@ -219,6 +228,7 @@ cah.$.LongPollEvent = function() {
|
|||
// Dummy constructor to make Eclipse auto-complete.
|
||||
};
|
||||
cah.$.LongPollEvent.prototype.dummyForAutocomplete = undefined;
|
||||
cah.$.LongPollEvent.BANNED = "B&";
|
||||
cah.$.LongPollEvent.KICKED = "k";
|
||||
cah.$.LongPollEvent.HURRY_UP = "hu";
|
||||
cah.$.LongPollEvent.KICKED_FROM_GAME_IDLE = "kfgi";
|
||||
|
|
|
@ -43,8 +43,11 @@ cah.longpoll.EventHandlers[cah.$.LongPollEvent.NEW_PLAYER] = function(data) {
|
|||
cah.longpoll.EventHandlers[cah.$.LongPollEvent.PLAYER_LEAVE] = function(data) {
|
||||
var friendly_reason = "Leaving";
|
||||
switch (data[cah.$.LongPollResponse.REASON]) {
|
||||
case cah.$.DisconnectReason.BANNED:
|
||||
friendly_reason = "Banned";
|
||||
break;
|
||||
case cah.$.DisconnectReason.KICKED:
|
||||
friendly_reason = "Kicked by server";
|
||||
friendly_reason = "Kicked by server administrator";
|
||||
break;
|
||||
case cah.$.DisconnectReason.MANUAL:
|
||||
friendly_reason = "Leaving";
|
||||
|
@ -70,6 +73,15 @@ cah.longpoll.EventHandlers[cah.$.LongPollEvent.KICKED] = function() {
|
|||
$("#info_area").empty();
|
||||
};
|
||||
|
||||
cah.longpoll.EventHandlers[cah.$.LongPollEvent.BANNED] = function() {
|
||||
cah.log.status("You have been banned by the server administrator.");
|
||||
cah.longpoll.Resume = false;
|
||||
$("input").attr("disabled", "disabled");
|
||||
$("#menubar_left").empty();
|
||||
$("#main").empty();
|
||||
$("#info_area").empty();
|
||||
};
|
||||
|
||||
cah.longpoll.EventHandlers[cah.$.LongPollEvent.CHAT] = function(data) {
|
||||
// TODO deal with multiple channels eventually
|
||||
// don't display our own chat
|
||||
|
|
|
@ -23,6 +23,12 @@
|
|||
|
||||
package net.socialgamer.cah;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import net.socialgamer.cah.data.GameManager;
|
||||
import net.socialgamer.cah.data.GameManager.GameId;
|
||||
import net.socialgamer.cah.data.GameManager.MaxGames;
|
||||
|
@ -30,6 +36,7 @@ import net.socialgamer.cah.data.GameManager.MaxGames;
|
|||
import org.hibernate.Session;
|
||||
|
||||
import com.google.inject.AbstractModule;
|
||||
import com.google.inject.BindingAnnotation;
|
||||
import com.google.inject.Provides;
|
||||
|
||||
|
||||
|
@ -53,7 +60,7 @@ public class CahModule extends AbstractModule {
|
|||
@Provides
|
||||
@MaxGames
|
||||
Integer provideMaxGames() {
|
||||
return 30;
|
||||
return 60;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -64,4 +71,21 @@ public class CahModule extends AbstractModule {
|
|||
Session provideHibernateSession() {
|
||||
return HibernateUtil.instance.sessionFactory.openSession();
|
||||
}
|
||||
|
||||
private final static Set<String> banList = Collections.synchronizedSet(new HashSet<String>());
|
||||
|
||||
/**
|
||||
* @return A mutable Set of IP addresses (in String format) which are banned. This Set is
|
||||
* thread-safe.
|
||||
*/
|
||||
@Provides
|
||||
@BanList
|
||||
Set<String> provideBanList() {
|
||||
return banList;
|
||||
}
|
||||
|
||||
@BindingAnnotation
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface BanList {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -92,6 +92,10 @@ public class Constants {
|
|||
* Reason why a client disconnected.
|
||||
*/
|
||||
public enum DisconnectReason {
|
||||
/**
|
||||
* The client was banned by the server administrator.
|
||||
*/
|
||||
BANNED("B&"),
|
||||
/**
|
||||
* The client was kicked by the server administrator.
|
||||
*/
|
||||
|
@ -150,6 +154,7 @@ public class Constants {
|
|||
*/
|
||||
public enum AjaxOperation {
|
||||
ADMIN_SET_VERBOSE_LOG("svl"),
|
||||
BAN("b"),
|
||||
CHANGE_GAME_OPTIONS("cgo"),
|
||||
CHAT("c"),
|
||||
CREATE_GAME("cg"),
|
||||
|
@ -162,6 +167,7 @@ public class Constants {
|
|||
GET_GAME_INFO("ggi"),
|
||||
JOIN_GAME("jg"),
|
||||
JUDGE_SELECT("js"),
|
||||
KICK("K"),
|
||||
LEAVE_GAME("lg"),
|
||||
LOG_OUT("lo"),
|
||||
/**
|
||||
|
@ -268,6 +274,8 @@ public class Constants {
|
|||
ALREADY_STARTED("as", "The game has already started."),
|
||||
BAD_OP("bo", "Invalid operation."),
|
||||
BAD_REQUEST("br", "Bad request."),
|
||||
@DuplicationAllowed
|
||||
BANNED(DisconnectReason.BANNED, "Banned."),
|
||||
CANNOT_JOIN_ANOTHER_GAME("cjag", "You cannot join another game."),
|
||||
DO_NOT_HAVE_CARD("dnhc", "You don't have that card."),
|
||||
GAME_FULL("gf", "That game is full. Join another."),
|
||||
|
@ -289,6 +297,8 @@ public class Constants {
|
|||
NO_MSG_SPECIFIED("nms", "No message specified."),
|
||||
NO_NICK_SPECIFIED("nns", "No nickname specified."),
|
||||
NO_SESSION("ns", "Session not detected. Make sure you have cookies enabled."),
|
||||
NO_SUCH_USER("nsu", "No such user."),
|
||||
NOT_ADMIN("na", "You are not an administrator."),
|
||||
NOT_ENOUGH_CARDS("nec", "You must select at least one base card set."),
|
||||
NOT_ENOUGH_PLAYERS("nep", "There are not enough players to start the game."),
|
||||
NOT_GAME_HOST("ngh", "Only the game host can do that."),
|
||||
|
@ -317,6 +327,11 @@ public class Constants {
|
|||
this.message = message;
|
||||
}
|
||||
|
||||
ErrorCode(final Enum<?> code, final String message) {
|
||||
this.code = code.toString();
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return code;
|
||||
|
@ -332,6 +347,8 @@ public class Constants {
|
|||
* Events that can be returned in a long poll response.
|
||||
*/
|
||||
public enum LongPollEvent {
|
||||
@DuplicationAllowed
|
||||
BANNED(DisconnectReason.BANNED),
|
||||
@DuplicationAllowed
|
||||
CHAT(AjaxOperation.CHAT),
|
||||
GAME_BLACK_RESHUFFLE("gbr"),
|
||||
|
|
|
@ -52,6 +52,8 @@ import net.socialgamer.cah.db.BlackCard;
|
|||
import net.socialgamer.cah.db.CardSet;
|
||||
import net.socialgamer.cah.db.WhiteCard;
|
||||
|
||||
import org.hibernate.Session;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.sun.istack.internal.Nullable;
|
||||
|
||||
|
@ -129,6 +131,7 @@ public class Game {
|
|||
private int scoreGoal = 8;
|
||||
private final Set<CardSet> cardSets = new HashSet<CardSet>();
|
||||
private String password = "";
|
||||
private final Session hibernateSession;
|
||||
|
||||
/**
|
||||
* Create a new game.
|
||||
|
@ -143,13 +146,18 @@ public class Game {
|
|||
*/
|
||||
@Inject
|
||||
public Game(@GameId final Integer id, final ConnectedUsers connectedUsers,
|
||||
final GameManager gameManager) {
|
||||
final GameManager gameManager, final Session hibernateSession) {
|
||||
this.id = id;
|
||||
this.connectedUsers = connectedUsers;
|
||||
this.gameManager = gameManager;
|
||||
this.hibernateSession = hibernateSession;
|
||||
state = GameState.LOBBY;
|
||||
}
|
||||
|
||||
public Session getHibernateSession() {
|
||||
return hibernateSession;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a player to the game.
|
||||
*
|
||||
|
|
|
@ -158,8 +158,8 @@ public class GameManager implements Provider<Integer> {
|
|||
nextId = gameId;
|
||||
}
|
||||
// remove the players from the game
|
||||
final List<User> users = game.getUsers();
|
||||
for (final User user : users) {
|
||||
final List<User> usersToRemove = game.getUsers();
|
||||
for (final User user : usersToRemove) {
|
||||
game.removePlayer(user);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
package net.socialgamer.cah.handlers;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
import net.socialgamer.cah.CahModule.BanList;
|
||||
import net.socialgamer.cah.Constants.AjaxOperation;
|
||||
import net.socialgamer.cah.Constants.AjaxRequest;
|
||||
import net.socialgamer.cah.Constants.DisconnectReason;
|
||||
import net.socialgamer.cah.Constants.ErrorCode;
|
||||
import net.socialgamer.cah.Constants.LongPollEvent;
|
||||
import net.socialgamer.cah.Constants.LongPollResponse;
|
||||
import net.socialgamer.cah.Constants.ReturnableData;
|
||||
import net.socialgamer.cah.Constants.SessionAttribute;
|
||||
import net.socialgamer.cah.RequestWrapper;
|
||||
import net.socialgamer.cah.data.ConnectedUsers;
|
||||
import net.socialgamer.cah.data.QueuedMessage;
|
||||
import net.socialgamer.cah.data.QueuedMessage.MessageType;
|
||||
import net.socialgamer.cah.data.User;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
|
||||
|
||||
public class BanHandler extends Handler {
|
||||
|
||||
public static final String OP = AjaxOperation.BAN.toString();
|
||||
|
||||
private final ConnectedUsers connectedUsers;
|
||||
private final Set<String> banList;
|
||||
|
||||
@Inject
|
||||
public BanHandler(final ConnectedUsers connectedUsers, @BanList final Set<String> banList) {
|
||||
this.connectedUsers = connectedUsers;
|
||||
this.banList = banList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<ReturnableData, Object> handle(final RequestWrapper request, final HttpSession session) {
|
||||
final User user = (User) session.getAttribute(SessionAttribute.USER);
|
||||
assert (user != null);
|
||||
|
||||
if (!user.isAdmin()) {
|
||||
return error(ErrorCode.NOT_ADMIN);
|
||||
}
|
||||
|
||||
if (null == request.getParameter(AjaxRequest.NICKNAME)
|
||||
|| request.getParameter(AjaxRequest.NICKNAME).isEmpty()) {
|
||||
return error(ErrorCode.NO_NICK_SPECIFIED);
|
||||
}
|
||||
|
||||
final String banIp;
|
||||
final User kickUser = connectedUsers.getUser(request.getParameter(AjaxRequest.NICKNAME));
|
||||
if (null != kickUser) {
|
||||
banIp = kickUser.getHostName();
|
||||
|
||||
final Map<ReturnableData, Object> kickData = new HashMap<ReturnableData, Object>();
|
||||
kickData.put(LongPollResponse.EVENT, LongPollEvent.BANNED.toString());
|
||||
final QueuedMessage qm = new QueuedMessage(MessageType.KICKED, kickData);
|
||||
kickUser.enqueueMessage(qm);
|
||||
|
||||
connectedUsers.removeUser(kickUser, DisconnectReason.BANNED);
|
||||
logger.info(String.format("Banning %s (%s) by request of %s", kickUser.getNickname(), banIp,
|
||||
user.getNickname()));
|
||||
} else {
|
||||
banIp = request.getParameter(AjaxRequest.NICKNAME);
|
||||
logger.info(String.format("Banning %s by request of %s", banIp, user.getNickname()));
|
||||
}
|
||||
banList.add(banIp);
|
||||
|
||||
return new HashMap<ReturnableData, Object>();
|
||||
}
|
||||
}
|
|
@ -18,8 +18,6 @@ import net.socialgamer.cah.data.GameManager;
|
|||
import net.socialgamer.cah.data.User;
|
||||
import net.socialgamer.cah.db.CardSet;
|
||||
|
||||
import org.hibernate.Session;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
|
||||
|
||||
|
@ -27,12 +25,9 @@ public class ChangeGameOptionHandler extends GameWithPlayerHandler {
|
|||
|
||||
public static final String OP = AjaxOperation.CHANGE_GAME_OPTIONS.toString();
|
||||
|
||||
private final Session hibernateSession;
|
||||
|
||||
@Inject
|
||||
public ChangeGameOptionHandler(final GameManager gameManager, final Session hibernateSession) {
|
||||
public ChangeGameOptionHandler(final GameManager gameManager) {
|
||||
super(gameManager);
|
||||
this.hibernateSession = hibernateSession;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -51,7 +46,10 @@ public class ChangeGameOptionHandler extends GameWithPlayerHandler {
|
|||
final String[] cardSetsParsed = request.getParameter(AjaxRequest.CARD_SETS).split(",");
|
||||
final Set<CardSet> cardSets = new HashSet<CardSet>();
|
||||
for (final String cardSetId : cardSetsParsed) {
|
||||
cardSets.add((CardSet) hibernateSession.load(CardSet.class, Integer.parseInt(cardSetId)));
|
||||
if (!cardSetId.isEmpty()) {
|
||||
cardSets.add((CardSet) game.getHibernateSession().load(CardSet.class,
|
||||
Integer.parseInt(cardSetId)));
|
||||
}
|
||||
}
|
||||
String password = request.getParameter(AjaxRequest.PASSWORD);
|
||||
if (password == null) {
|
||||
|
|
|
@ -99,6 +99,7 @@ public class FirstLoadHandler extends Handler {
|
|||
}
|
||||
ret.put(AjaxResponse.CARD_SETS, cardSetsData);
|
||||
transaction.commit();
|
||||
hibernateSession.close();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -23,10 +23,8 @@
|
|||
|
||||
package net.socialgamer.cah.handlers;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
@ -36,8 +34,6 @@ import net.socialgamer.cah.Constants.ErrorCode;
|
|||
import net.socialgamer.cah.Constants.ReturnableData;
|
||||
import net.socialgamer.cah.RequestWrapper;
|
||||
|
||||
import org.hibernate.Session;
|
||||
|
||||
|
||||
/**
|
||||
* Implementations of this interface MUST also have a public static final String OP. There will be
|
||||
|
@ -46,7 +42,7 @@ import org.hibernate.Session;
|
|||
* @author Andy Janata (ajanata@socialgamer.net)
|
||||
*/
|
||||
public abstract class Handler {
|
||||
private final Logger logger = Logger.getLogger("net.socialgamer.cah.handlers.Handler");
|
||||
protected final Logger logger = Logger.getLogger("net.socialgamer.cah.handlers.Handler");
|
||||
|
||||
/**
|
||||
* Handle a request.
|
||||
|
@ -80,28 +76,29 @@ public abstract class Handler {
|
|||
* did not already close it.
|
||||
*/
|
||||
public final void cleanUp() {
|
||||
for (final Field field : this.getClass().getDeclaredFields()) {
|
||||
if (field.getType() == Session.class) {
|
||||
try {
|
||||
// This Handler had a Hibernate Session. Try to close it if it wasn't already closed.
|
||||
// This is extremely dirty but also extremely awesome to not have problems if it is
|
||||
// forgotten.
|
||||
field.setAccessible(true);
|
||||
final Session session = (Session) field.get(this);
|
||||
if (session.isOpen()) {
|
||||
session.close();
|
||||
logger.log(Level.INFO, "Closing unclosed Hibernate Session in "
|
||||
+ this.getClass().getName());
|
||||
}
|
||||
} catch (final Exception e) {
|
||||
// Something prevented us from ignoring access control check, so we can't close the
|
||||
// session. Log about it and continue.
|
||||
e.printStackTrace();
|
||||
logger.log(Level.SEVERE, "Unable to reflect and get Hibernate Session from "
|
||||
+ this.getClass().getName());
|
||||
logger.log(Level.SEVERE, e.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
// this actually breaks stuff, I'll have to think it through later.
|
||||
// for (final Field field : this.getClass().getDeclaredFields()) {
|
||||
// if (field.getType() == Session.class) {
|
||||
// try {
|
||||
// // This Handler had a Hibernate Session. Try to close it if it wasn't already closed.
|
||||
// // This is extremely dirty but also extremely awesome to not have problems if it is
|
||||
// // forgotten.
|
||||
// field.setAccessible(true);
|
||||
// final Session session = (Session) field.get(this);
|
||||
// if (session.isOpen()) {
|
||||
// session.close();
|
||||
// logger.log(Level.INFO, "Closing unclosed Hibernate Session in "
|
||||
// + this.getClass().getName());
|
||||
// }
|
||||
// } catch (final Exception e) {
|
||||
// // Something prevented us from ignoring access control check, so we can't close the
|
||||
// // session. Log about it and continue.
|
||||
// e.printStackTrace();
|
||||
// logger.log(Level.SEVERE, "Unable to reflect and get Hibernate Session from "
|
||||
// + this.getClass().getName());
|
||||
// logger.log(Level.SEVERE, e.toString());
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ public class Handlers {
|
|||
static {
|
||||
LIST = new HashMap<String, Class<? extends Handler>>();
|
||||
LIST.put(AdminSetVerboseLog.OP, AdminSetVerboseLog.class);
|
||||
LIST.put(BanHandler.OP, BanHandler.class);
|
||||
LIST.put(ChangeGameOptionHandler.OP, ChangeGameOptionHandler.class);
|
||||
LIST.put(ChatHandler.OP, ChatHandler.class);
|
||||
LIST.put(CreateGameHandler.OP, CreateGameHandler.class);
|
||||
|
@ -20,6 +21,7 @@ public class Handlers {
|
|||
LIST.put(GetGameInfoHandler.OP, GetGameInfoHandler.class);
|
||||
LIST.put(JoinGameHandler.OP, JoinGameHandler.class);
|
||||
LIST.put(JudgeSelectHandler.OP, JudgeSelectHandler.class);
|
||||
LIST.put(KickHandler.OP, KickHandler.class);
|
||||
LIST.put(LeaveGameHandler.OP, LeaveGameHandler.class);
|
||||
LIST.put(LogoutHandler.OP, LogoutHandler.class);
|
||||
LIST.put(NamesHandler.OP, NamesHandler.class);
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
package net.socialgamer.cah.handlers;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
import net.socialgamer.cah.Constants.AjaxOperation;
|
||||
import net.socialgamer.cah.Constants.AjaxRequest;
|
||||
import net.socialgamer.cah.Constants.DisconnectReason;
|
||||
import net.socialgamer.cah.Constants.ErrorCode;
|
||||
import net.socialgamer.cah.Constants.LongPollEvent;
|
||||
import net.socialgamer.cah.Constants.LongPollResponse;
|
||||
import net.socialgamer.cah.Constants.ReturnableData;
|
||||
import net.socialgamer.cah.Constants.SessionAttribute;
|
||||
import net.socialgamer.cah.RequestWrapper;
|
||||
import net.socialgamer.cah.data.ConnectedUsers;
|
||||
import net.socialgamer.cah.data.QueuedMessage;
|
||||
import net.socialgamer.cah.data.QueuedMessage.MessageType;
|
||||
import net.socialgamer.cah.data.User;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
|
||||
|
||||
public class KickHandler extends Handler {
|
||||
|
||||
public static final String OP = AjaxOperation.KICK.toString();
|
||||
|
||||
private final ConnectedUsers connectedUsers;
|
||||
|
||||
@Inject
|
||||
public KickHandler(final ConnectedUsers connectedUsers) {
|
||||
this.connectedUsers = connectedUsers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<ReturnableData, Object> handle(final RequestWrapper request, final HttpSession session) {
|
||||
final User user = (User) session.getAttribute(SessionAttribute.USER);
|
||||
assert (user != null);
|
||||
|
||||
if (!user.isAdmin()) {
|
||||
return error(ErrorCode.NOT_ADMIN);
|
||||
}
|
||||
|
||||
if (null == request.getParameter(AjaxRequest.NICKNAME)
|
||||
|| request.getParameter(AjaxRequest.NICKNAME).isEmpty()) {
|
||||
return error(ErrorCode.NO_NICK_SPECIFIED);
|
||||
}
|
||||
|
||||
final User kickUser = connectedUsers.getUser(request.getParameter(AjaxRequest.NICKNAME));
|
||||
if (null == kickUser) {
|
||||
return error(ErrorCode.NO_SUCH_USER);
|
||||
}
|
||||
|
||||
final Map<ReturnableData, Object> kickData = new HashMap<ReturnableData, Object>();
|
||||
kickData.put(LongPollResponse.EVENT, LongPollEvent.KICKED.toString());
|
||||
final QueuedMessage qm = new QueuedMessage(MessageType.KICKED, kickData);
|
||||
kickUser.enqueueMessage(qm);
|
||||
|
||||
connectedUsers.removeUser(kickUser, DisconnectReason.KICKED);
|
||||
logger.info(String.format("Kicking %s by request of %s", kickUser.getNickname(),
|
||||
user.getNickname()));
|
||||
|
||||
return new HashMap<ReturnableData, Object>();
|
||||
}
|
||||
}
|
|
@ -25,10 +25,12 @@ package net.socialgamer.cah.handlers;
|
|||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
import net.socialgamer.cah.CahModule.BanList;
|
||||
import net.socialgamer.cah.Constants;
|
||||
import net.socialgamer.cah.Constants.AjaxOperation;
|
||||
import net.socialgamer.cah.Constants.AjaxRequest;
|
||||
|
@ -55,6 +57,7 @@ public class RegisterHandler extends Handler {
|
|||
private static final Pattern validName = Pattern.compile("[a-zA-Z_][a-zA-Z0-9_]{2,29}");
|
||||
|
||||
private final ConnectedUsers users;
|
||||
private final Set<String> banList;
|
||||
|
||||
/**
|
||||
* I don't want to have to inject the entire server here, but I couldn't figure out how to
|
||||
|
@ -63,8 +66,9 @@ public class RegisterHandler extends Handler {
|
|||
* @param server
|
||||
*/
|
||||
@Inject
|
||||
public RegisterHandler(final ConnectedUsers users) {
|
||||
public RegisterHandler(final ConnectedUsers users, @BanList final Set<String> banList) {
|
||||
this.users = users;
|
||||
this.banList = banList;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -72,6 +76,10 @@ public class RegisterHandler extends Handler {
|
|||
final HttpSession session) {
|
||||
final Map<ReturnableData, Object> data = new HashMap<ReturnableData, Object>();
|
||||
|
||||
if (banList.contains(request.getRemoteAddr())) {
|
||||
return error(ErrorCode.BANNED);
|
||||
}
|
||||
|
||||
if (request.getParameter(AjaxRequest.NICKNAME) == null) {
|
||||
return error(ErrorCode.NO_NICK_SPECIFIED);
|
||||
} else {
|
||||
|
@ -81,8 +89,8 @@ public class RegisterHandler extends Handler {
|
|||
} else if (users.hasUser(nick)) {
|
||||
return error(ErrorCode.NICK_IN_USE);
|
||||
} else {
|
||||
final User user = new User(nick, request.getRemoteHost(),
|
||||
Constants.ADMIN_IP_ADDRESSES.contains(request.getRemoteHost()));
|
||||
final User user = new User(nick, request.getRemoteAddr(),
|
||||
Constants.ADMIN_IP_ADDRESSES.contains(request.getRemoteAddr()));
|
||||
users.newUser(user);
|
||||
// There is a findbugs warning on this line:
|
||||
// cah/src/net/socialgamer/cah/handlers/RegisterHandler.java:85 Store of non serializable
|
||||
|
|
|
@ -36,10 +36,12 @@ import static org.junit.Assert.assertNull;
|
|||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
|
||||
import net.socialgamer.cah.HibernateUtil;
|
||||
import net.socialgamer.cah.data.GameManager.GameId;
|
||||
import net.socialgamer.cah.data.GameManager.MaxGames;
|
||||
import net.socialgamer.cah.data.QueuedMessage.MessageType;
|
||||
|
||||
import org.hibernate.Session;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
@ -87,6 +89,12 @@ public class GameManagerTest {
|
|||
Integer provideGameId() {
|
||||
return gameId;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Provides
|
||||
Session provideSession() {
|
||||
return HibernateUtil.instance.sessionFactory.openSession();
|
||||
}
|
||||
});
|
||||
|
||||
gameManager = injector.getInstance(GameManager.class);
|
||||
|
@ -108,11 +116,11 @@ public class GameManagerTest {
|
|||
|
||||
// fill it up with 3 games
|
||||
assertEquals(0, gameManager.get().intValue());
|
||||
gameManager.getGames().put(0, new Game(0, cuMock, gameManager));
|
||||
gameManager.getGames().put(0, new Game(0, cuMock, gameManager, null));
|
||||
assertEquals(1, gameManager.get().intValue());
|
||||
gameManager.getGames().put(1, new Game(1, cuMock, gameManager));
|
||||
gameManager.getGames().put(1, new Game(1, cuMock, gameManager, null));
|
||||
assertEquals(2, gameManager.get().intValue());
|
||||
gameManager.getGames().put(2, new Game(2, cuMock, gameManager));
|
||||
gameManager.getGames().put(2, new Game(2, cuMock, gameManager, null));
|
||||
// make sure it says it can't make any more
|
||||
assertEquals(-1, gameManager.get().intValue());
|
||||
|
||||
|
@ -120,13 +128,13 @@ public class GameManagerTest {
|
|||
gameManager.destroyGame(1);
|
||||
// make sure it re-uses that id
|
||||
assertEquals(1, gameManager.get().intValue());
|
||||
gameManager.getGames().put(1, new Game(1, cuMock, gameManager));
|
||||
gameManager.getGames().put(1, new Game(1, cuMock, gameManager, null));
|
||||
assertEquals(-1, gameManager.get().intValue());
|
||||
|
||||
// remove game 1 out from under it, to make sure it'll fix itself
|
||||
gameManager.getGames().remove(1);
|
||||
assertEquals(1, gameManager.get().intValue());
|
||||
gameManager.getGames().put(1, new Game(1, cuMock, gameManager));
|
||||
gameManager.getGames().put(1, new Game(1, cuMock, gameManager, null));
|
||||
assertEquals(-1, gameManager.get().intValue());
|
||||
|
||||
gameManager.destroyGame(2);
|
||||
|
|
|
@ -59,7 +59,7 @@ public class GameTest {
|
|||
public void setUp() throws Exception {
|
||||
cuMock = createMock(ConnectedUsers.class);
|
||||
gmMock = createMock(GameManager.class);
|
||||
game = new Game(0, cuMock, gmMock);
|
||||
game = new Game(0, cuMock, gmMock, null);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
|
|
Loading…
Reference in New Issue