package com.mgreau.wildfly.websocket;
import java.io.IOException;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.inject.Inject;
import javax.websocket.EncodeException;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import com.mgreau.wildfly.websocket.decoders.MessageDecoder;
import com.mgreau.wildfly.websocket.encoders.BetMessageEncoder;
import com.mgreau.wildfly.websocket.encoders.MatchMessageEncoder;
import com.mgreau.wildfly.websocket.messages.BetMessage;
import com.mgreau.wildfly.websocket.messages.MatchMessage;
@ServerEndpoint(
value = "/matches/{match-id}",
decoders = { MessageDecoder.class },
encoders = { MatchMessageEncoder.class, BetMessageEncoder.class }
)
public class MatchEndpoint {
/** log */
private static final Logger logger = Logger.getLogger("MatchEndpoint");
/** All open WebSocket sessions */
static Set<Session> peers = Collections.synchronizedSet(new HashSet<Session>());
/** Handle number of bets by match */
static Map<String, AtomicInteger> nbBetsByMatch = new ConcurrentHashMap<>();
@Inject StarterService ejbService;
/**
* Send Live Match message for all peers connected to this match
* @param msg
* @param matchId
*/
public static void send(MatchMessage msg, String matchId) {
try {
/* Send updates to all open WebSocket sessions for this match */
for (Session session : peers) {
if (Boolean.TRUE.equals(session.getUserProperties().get(matchId))){
if (session.isOpen()){
session.getBasicRemote().sendObject(msg);
logger.log(Level.INFO, " Score Sent: {0}", msg);
}
}
}
} catch (IOException | EncodeException e) {
logger.log(Level.INFO, e.toString());
}
}
/**
* When the match is finished, each peer which has bet on this match receive a message.
* @param winner
* @param matchId
*/
public static void sendBetMessages(String winner, String matchId, boolean isFinished) {
try {
/* Send updates to all open WebSocket sessions for this match */
for (Session session : peers) {
if (Boolean.TRUE.equals(session.getUserProperties().get(matchId))){
if (session.isOpen()){
if (session.getUserProperties().containsKey("bet")){
BetMessage betMsg = new BetMessage((String)session.getUserProperties().get("bet"));
if (isFinished){
if (winner != null
&& winner.equals(betMsg.getWinner())){
betMsg.setResult("OK");
} else {
betMsg.setResult("KO");
}
}
sendBetMessage(session, betMsg, matchId);
logger.log(Level.INFO, "Result Sent: {0}", betMsg.getResult());
}
}
if (isFinished){
//Match finished, need to clear properties
session.getUserProperties().clear();
nbBetsByMatch.get(matchId).set(0);
}
}
}
logger.log(Level.INFO, "Match FINISHED");
} catch (Exception e) {
logger.log(Level.SEVERE, e.toString());
}
}
public static void sendBetMessage(Session session, BetMessage betMsg, String matchId) {
try {
betMsg.setNbBets(nbBetsByMatch.get(matchId).get());
session.getBasicRemote().sendObject(betMsg);
logger.log(Level.INFO, "BetMsg Sent: {0}", betMsg.toString());
} catch (IOException | EncodeException e) {
logger.log(Level.SEVERE, e.toString());
}
}
@OnMessage
public void message(final Session session, BetMessage msg, @PathParam("match-id") String matchId) {
logger.log(Level.INFO, "Received: Bet Match Winner - {0}", msg.getWinner());
//check if the user had already bet and save this bet
boolean hasAlreadyBet = session.getUserProperties().containsKey("bet");
session.getUserProperties().put("bet", msg.getWinner());
//Send betMsg with bet count
if (!nbBetsByMatch.containsKey(matchId)){
nbBetsByMatch.put(matchId, new AtomicInteger());
}
if (!hasAlreadyBet){
nbBetsByMatch.get(matchId).incrementAndGet();
}
sendBetMessages(null, matchId, false);
}
@OnOpen
public void openConnection(Session session, @PathParam("match-id") String matchId) {
logger.log(Level.INFO, "Session ID : " + session.getId() +" - Connection opened for match : " + matchId);
session.getUserProperties().put(matchId, true);
peers.add(session);
//Send live result for this match
send(new MatchMessage(ejbService.getMatches().get(matchId)), matchId);
}
@OnClose
public void closedConnection(Session session, @PathParam("match-id") String matchId) {
if (session.getUserProperties().containsKey("bet")){
/* Remove bet */
nbBetsByMatch.get(matchId).decrementAndGet();
sendBetMessages(null, matchId, false);
}
/* Remove this connection from the queue */
peers.remove(session);
logger.log(Level.INFO, "Connection closed.");
}
@OnError
public void error(Session session, Throwable t) {
peers.remove(session);
logger.log(Level.INFO, t.toString());
logger.log(Level.INFO, "Connection error.");
}
}