Repackage timer tasks. Add new timer task to broadcast game list updates every 60 seconds instead of every time a game changes (massive bandwidth use). Change chat rate limit from 5 per 10 sec to 6 per 30 sec.
This commit is contained in:
parent
7a574d39b8
commit
aa43eac98b
|
@ -242,6 +242,7 @@ select {
|
|||
<th>Delete</th>
|
||||
<th>Edit</th>
|
||||
<th>Weight</th>
|
||||
<th>Active</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
@ -253,6 +254,7 @@ select {
|
|||
<td><a href="?delete=<%=cardSet.getId()%>" onclick="return confirm('Are you sure?')">Delete</a></td>
|
||||
<td><a href="?edit=<%=cardSet.getId()%>">Edit</a></td>
|
||||
<td><%=cardSet.getWeight()%></td>
|
||||
<td><%=cardSet.isActive()%></td>
|
||||
</tr>
|
||||
<%
|
||||
}
|
||||
|
|
|
@ -86,27 +86,16 @@ HttpSession hSession = request.getSession(true);
|
|||
If this is your first time playing, you may wish to read <a href="/">the changelog and list of
|
||||
known issues</a>.
|
||||
</p>
|
||||
<p tabindex="0">Most recent update: 21 February 2015:</p>
|
||||
<p tabindex="0">Most recent update: 3 May 2015:</p>
|
||||
<ul>
|
||||
<li>Servers now run in Amazon Web Services. This is going to cost me more, but at least it
|
||||
should be more stable and not take down my other stuff when it does go down...<ul>
|
||||
<li>I am still tweaking server settings in AWS. It likely is going to be unstable for another
|
||||
week or two while I fine-tune cost and performance.</li></ul></li>
|
||||
<li>Card set filters are fixed.</li>
|
||||
<li><pre>/removecardcast</pre> is fixed.</li>
|
||||
<li>Connect and disconnect notices are disabled server-wide. This was a major source of
|
||||
bandwidth and processing time.</li>
|
||||
<li><strong>You can start a game without using any local card sets.</strong>You must have at
|
||||
least 50 black cards and (20 times player limit) white cards to be able to start a game.</li>
|
||||
<li>Several other back-end performance and code maintainability improvements.</li>
|
||||
<li><strong>Custom card sets will be removed from local storage in the near future.</strong>You
|
||||
will have to use Cardcast to use custom card sets. If a card set you want is not already in
|
||||
Cardcast, you can attempt to extract it from
|
||||
<a href='https://github.com/ajanata/PretendYoureXyzzy/blob/737b468/cah_cards.sql'>the last
|
||||
version of the database dump which contains them</a> and add it to Cardcast yourself; I will be
|
||||
unable to provide help in doing so.</li>
|
||||
<li>At roughly the same time, all officially released Cards Against Humanity sets which are not
|
||||
already in the system will be added as local decks.</li>
|
||||
<li>The game list automatically updates once per minute now, instead of several times per
|
||||
second. You can still click the Refresh Games button in the top left corner at any time.</li>
|
||||
<li>Chat flood protection has been made more strict.</li>
|
||||
<li>Other back-end changes to attempt to get the AWS bill in control.</li>
|
||||
<li><strong>All locally-stored custom card sets have been removed.</strong> You must use
|
||||
Cardcast for custom card sets now.</li>
|
||||
<li>The 5th and 6th Expansions, PAX Prime 2014 Panel, Ten Days or Whatever of Kwanzaa,
|
||||
and Science packs have all been added.</li>
|
||||
<li>Remaining known issues and high priority features:<ul>
|
||||
<li>Leaving a game as a spectator doesn't work right.</li>
|
||||
<li>Game owners still can't kick players from their game.</li>
|
||||
|
|
|
@ -54,6 +54,16 @@ to, for instance, display the number of connected players.
|
|||
</p>
|
||||
<p>Recent Changes:</p>
|
||||
<ul>
|
||||
<li>3 May 2015:<ul>
|
||||
<li>The game list automatically updates once per minute now, instead of several times per
|
||||
second. You can still click the Refresh Games button in the top left corner at any time.</li>
|
||||
<li>Chat flood protection has been made more strict.</li>
|
||||
<li>Other back-end changes to attempt to get the AWS bill in control.</li>
|
||||
<li><strong>All locally-stored custom card sets have been removed.</strong> You must use
|
||||
Cardcast for custom card sets now.</li>
|
||||
<li>The 5th and 6th Expansions, PAX Prime 2014 Panel, 10 Days or Whatever of Kwanzaa,
|
||||
and Science packs have all been added.</li>
|
||||
</ul></li>
|
||||
<li>21 February 2015:<ul>
|
||||
<li>Servers now run in Amazon Web Services. This is going to cost me more, but at least it
|
||||
should be more stable and not take down my other stuff when it does go down...<ul>
|
||||
|
|
|
@ -44,8 +44,8 @@ import net.socialgamer.cah.data.Game;
|
|||
*/
|
||||
public class Constants {
|
||||
|
||||
public static final int CHAT_FLOOD_MESSAGE_COUNT = 5;
|
||||
public static final int CHAT_FLOOD_TIME = 10 * 1000;
|
||||
public static final int CHAT_FLOOD_MESSAGE_COUNT = 6;
|
||||
public static final int CHAT_FLOOD_TIME = 30 * 1000;
|
||||
public static final int CHAT_MAX_LENGTH = 200;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
|
|
|
@ -35,6 +35,8 @@ import javax.servlet.ServletContextEvent;
|
|||
|
||||
import net.socialgamer.cah.cardcast.CardcastModule;
|
||||
import net.socialgamer.cah.cardcast.CardcastService;
|
||||
import net.socialgamer.cah.task.BroadcastGameListUpdateTask;
|
||||
import net.socialgamer.cah.task.UserPingTask;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import org.apache.log4j.PropertyConfigurator;
|
||||
|
@ -70,6 +72,16 @@ public class StartupUtils extends GuiceServletContextListener {
|
|||
*/
|
||||
private static final long PING_CHECK_DELAY = 5 * 1000;
|
||||
|
||||
/**
|
||||
* Delay before the "update game list" broadcast timer is started, in milliseconds.
|
||||
*/
|
||||
private static final long BROADCAST_UPDATE_START_DELAY = TimeUnit.SECONDS.toMillis(60);
|
||||
|
||||
/**
|
||||
* Delay between invocations of the "update game list" broadcast timer, in milliseconds.
|
||||
*/
|
||||
private static final long BROADCAST_UPDATE_DELAY = TimeUnit.SECONDS.toMillis(60);
|
||||
|
||||
/**
|
||||
* Context attribute key name for the time the server was started.
|
||||
*/
|
||||
|
@ -104,10 +116,18 @@ public class StartupUtils extends GuiceServletContextListener {
|
|||
public void contextInitialized(final ServletContextEvent contextEvent) {
|
||||
final ServletContext context = contextEvent.getServletContext();
|
||||
final Injector injector = getInjector();
|
||||
final UserPing ping = injector.getInstance(UserPing.class);
|
||||
|
||||
final ScheduledThreadPoolExecutor timer = injector
|
||||
.getInstance(ScheduledThreadPoolExecutor.class);
|
||||
|
||||
final UserPingTask ping = injector.getInstance(UserPingTask.class);
|
||||
timer.scheduleAtFixedRate(ping, PING_START_DELAY, PING_CHECK_DELAY, TimeUnit.MILLISECONDS);
|
||||
|
||||
final BroadcastGameListUpdateTask broadcastUpdate = injector
|
||||
.getInstance(BroadcastGameListUpdateTask.class);
|
||||
timer.scheduleAtFixedRate(broadcastUpdate, BROADCAST_UPDATE_START_DELAY,
|
||||
BROADCAST_UPDATE_DELAY, TimeUnit.MILLISECONDS);
|
||||
|
||||
serverStarted = new Date();
|
||||
context.setAttribute(INJECTOR, injector);
|
||||
context.setAttribute(DATE_NAME, serverStarted);
|
||||
|
|
|
@ -50,11 +50,11 @@ import net.socialgamer.cah.Constants.LongPollEvent;
|
|||
import net.socialgamer.cah.Constants.LongPollResponse;
|
||||
import net.socialgamer.cah.Constants.ReturnableData;
|
||||
import net.socialgamer.cah.Constants.WhiteCardData;
|
||||
import net.socialgamer.cah.SafeTimerTask;
|
||||
import net.socialgamer.cah.cardcast.CardcastDeck;
|
||||
import net.socialgamer.cah.cardcast.CardcastService;
|
||||
import net.socialgamer.cah.data.GameManager.GameId;
|
||||
import net.socialgamer.cah.data.QueuedMessage.MessageType;
|
||||
import net.socialgamer.cah.task.SafeTimerTask;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import org.hibernate.Session;
|
||||
|
|
|
@ -27,17 +27,13 @@ import java.lang.annotation.Retention;
|
|||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import net.socialgamer.cah.Constants.LongPollEvent;
|
||||
import net.socialgamer.cah.Constants.LongPollResponse;
|
||||
import net.socialgamer.cah.Constants.ReturnableData;
|
||||
import net.socialgamer.cah.data.Game.TooManyPlayersException;
|
||||
import net.socialgamer.cah.data.GameManager.GameId;
|
||||
import net.socialgamer.cah.data.QueuedMessage.MessageType;
|
||||
import net.socialgamer.cah.task.BroadcastGameListUpdateTask;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
|
@ -62,7 +58,8 @@ public class GameManager implements Provider<Integer> {
|
|||
private final Provider<Integer> maxGamesProvider;
|
||||
private final Map<Integer, Game> games = new TreeMap<Integer, Game>();
|
||||
private final Provider<Game> gameProvider;
|
||||
private final ConnectedUsers users;
|
||||
private final BroadcastGameListUpdateTask broadcastUpdate;
|
||||
|
||||
/**
|
||||
* Potential next game id.
|
||||
*/
|
||||
|
@ -81,10 +78,10 @@ public class GameManager implements Provider<Integer> {
|
|||
@Inject
|
||||
public GameManager(final Provider<Game> gameProvider,
|
||||
@MaxGames final Provider<Integer> maxGamesProvider,
|
||||
final ConnectedUsers users) {
|
||||
final BroadcastGameListUpdateTask broadcastUpdate) {
|
||||
this.gameProvider = gameProvider;
|
||||
this.maxGamesProvider = maxGamesProvider;
|
||||
this.users = users;
|
||||
this.broadcastUpdate = broadcastUpdate;
|
||||
}
|
||||
|
||||
private int getMaxGames() {
|
||||
|
@ -183,9 +180,7 @@ public class GameManager implements Provider<Integer> {
|
|||
* Broadcast an event to all users that they should refresh the game list.
|
||||
*/
|
||||
public void broadcastGameListRefresh() {
|
||||
final HashMap<ReturnableData, Object> broadcastData = new HashMap<ReturnableData, Object>();
|
||||
broadcastData.put(LongPollResponse.EVENT, LongPollEvent.GAME_LIST_REFRESH.toString());
|
||||
users.broadcastToAll(MessageType.GAME_EVENT, broadcastData);
|
||||
broadcastUpdate.needsUpdate();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
package net.socialgamer.cah.task;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
import net.socialgamer.cah.Constants.LongPollEvent;
|
||||
import net.socialgamer.cah.Constants.LongPollResponse;
|
||||
import net.socialgamer.cah.Constants.ReturnableData;
|
||||
import net.socialgamer.cah.data.ConnectedUsers;
|
||||
import net.socialgamer.cah.data.QueuedMessage.MessageType;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
|
||||
|
||||
@Singleton
|
||||
public class BroadcastGameListUpdateTask extends SafeTimerTask {
|
||||
|
||||
private volatile boolean needsUpdate = false;
|
||||
private final ConnectedUsers users;
|
||||
|
||||
@Inject
|
||||
public BroadcastGameListUpdateTask(final ConnectedUsers users) {
|
||||
this.users = users;
|
||||
}
|
||||
|
||||
public void needsUpdate() {
|
||||
needsUpdate = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process() {
|
||||
if (needsUpdate) {
|
||||
final HashMap<ReturnableData, Object> broadcastData = new HashMap<ReturnableData, Object>();
|
||||
broadcastData.put(LongPollResponse.EVENT, LongPollEvent.GAME_LIST_REFRESH.toString());
|
||||
users.broadcastToAll(MessageType.GAME_EVENT, broadcastData);
|
||||
needsUpdate = false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package net.socialgamer.cah;
|
||||
package net.socialgamer.cah.task;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
|
|
@ -21,13 +21,14 @@
|
|||
* WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package net.socialgamer.cah;
|
||||
package net.socialgamer.cah.task;
|
||||
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
|
||||
import net.socialgamer.cah.data.ConnectedUsers;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -35,13 +36,14 @@ import com.google.inject.Inject;
|
|||
*
|
||||
* @author Andy Janata (ajanata@gmail.com)
|
||||
*/
|
||||
public class UserPing extends SafeTimerTask {
|
||||
@Singleton
|
||||
public class UserPingTask extends SafeTimerTask {
|
||||
|
||||
private final ConnectedUsers users;
|
||||
private final ScheduledThreadPoolExecutor globalTimer;
|
||||
|
||||
@Inject
|
||||
public UserPing(final ConnectedUsers users, final ScheduledThreadPoolExecutor globalTimer) {
|
||||
public UserPingTask(final ConnectedUsers users, final ScheduledThreadPoolExecutor globalTimer) {
|
||||
this.users = users;
|
||||
this.globalTimer = globalTimer;
|
||||
}
|
|
@ -96,27 +96,23 @@ public class GameManagerTest {
|
|||
bind(ScheduledThreadPoolExecutor.class).toInstance(threadPool);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Provides
|
||||
@MaxGames
|
||||
Integer provideMaxGames() {
|
||||
return 3;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Provides
|
||||
@GameId
|
||||
Integer provideGameId() {
|
||||
return gameId;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Provides
|
||||
Session provideSession() {
|
||||
return HibernateUtil.instance.sessionFactory.openSession();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Provides
|
||||
@CardcastCardId
|
||||
Integer provideCardcastCardId() {
|
||||
|
@ -133,11 +129,8 @@ public class GameManagerTest {
|
|||
verify(userMock);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void testGetAndDestroyGame() {
|
||||
cuMock.broadcastToAll(eq(MessageType.GAME_EVENT), anyObject(HashMap.class));
|
||||
expectLastCall().times(3);
|
||||
replay(cuMock);
|
||||
replay(userMock);
|
||||
|
||||
|
@ -172,8 +165,6 @@ public class GameManagerTest {
|
|||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void testCreateGame() {
|
||||
cuMock.broadcastToAll(eq(MessageType.GAME_EVENT), anyObject(HashMap.class));
|
||||
expectLastCall().times(3);
|
||||
cuMock.broadcastToList(anyObject(Collection.class), eq(MessageType.GAME_PLAYER_EVENT),
|
||||
anyObject(HashMap.class));
|
||||
expectLastCall().times(3);
|
||||
|
|
Loading…
Reference in New Issue