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."); } }