Index: lams_tool_doku/src/java/org/lamsfoundation/lams/tool/dokumaran/web/action/LearningWebsocketServer.java =================================================================== diff -u -rf06669784fcf047185a7f9c48587b3096474aa2a -r6ba026f6469b284e631a6c4027aae840a2416c02 --- lams_tool_doku/src/java/org/lamsfoundation/lams/tool/dokumaran/web/action/LearningWebsocketServer.java (.../LearningWebsocketServer.java) (revision f06669784fcf047185a7f9c48587b3096474aa2a) +++ lams_tool_doku/src/java/org/lamsfoundation/lams/tool/dokumaran/web/action/LearningWebsocketServer.java (.../LearningWebsocketServer.java) (revision 6ba026f6469b284e631a6c4027aae840a2416c02) @@ -3,8 +3,8 @@ import java.io.IOException; import java.util.Iterator; import java.util.Map; -import java.util.Set; import java.util.Map.Entry; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import javax.websocket.CloseReason; @@ -63,14 +63,16 @@ continue; } - Dokumaran dokumaran = getDokumaranService().getDokumaranByContentId(toolContentId); + Dokumaran dokumaran = LearningWebsocketServer.getDokumaranService() + .getDokumaranByContentId(toolContentId); int timeLimit = dokumaran.getTimeLimit(); if (dokumaran.getTimeLimitLaunchedDate() != null && timeLimit != 0) { Integer cachedTimeLimit = timeLimitCache.get(toolContentId); - if (cachedTimeLimit == null || !cachedTimeLimit.equals(timeLimit)) { + if (cachedTimeLimit == null) { timeLimitCache.put(toolContentId, timeLimit); - sendAddTimeRequest(toolContentId, - timeLimit - (cachedTimeLimit == null ? 0 : cachedTimeLimit)); + LearningWebsocketServer.sendPageRefreshRequest(toolContentId); + } else if (!cachedTimeLimit.equals(timeLimit)) { + LearningWebsocketServer.sendAddTimeRequest(toolContentId, timeLimit - cachedTimeLimit); } } } @@ -93,8 +95,8 @@ private static final Logger log = Logger.getLogger(LearningWebsocketServer.class); private static final SendWorker sendWorker = new SendWorker(); - private static final Map> websockets = new ConcurrentHashMap>(); - private static final Map timeLimitCache = new ConcurrentHashMap(); + private static final Map> websockets = new ConcurrentHashMap<>(); + private static final Map timeLimitCache = new ConcurrentHashMap<>(); private static IDokumaranService dokumaranService; @@ -148,7 +150,7 @@ * Monitor has added one more minute to the time limit. All learners will need * to add +1 minute to their countdown counters. */ - public static void sendAddTimeRequest(Long toolContentId, int timeLimit) throws JSONException, IOException { + private static void sendAddTimeRequest(Long toolContentId, int timeLimit) throws JSONException, IOException { Set toolContentWebsockets = websockets.get(toolContentId); if (toolContentWebsockets == null) { return; @@ -165,6 +167,27 @@ } } + /** + * Monitor has launched time limit. All learners will need to refresh the page in order to stop showing them + * waitForTimeLimitLaunch page. + */ + private static void sendPageRefreshRequest(Long toolContentId) throws JSONException, IOException { + Set toolContentWebsockets = websockets.get(toolContentId); + if (toolContentWebsockets == null) { + return; + } + + JSONObject responseJSON = new JSONObject(); + responseJSON.put("pageRefresh", true); + String response = responseJSON.toString(); + + for (Session websocket : toolContentWebsockets) { + if (websocket.isOpen()) { + websocket.getBasicRemote().sendText(response); + } + } + } + private static IDokumaranService getDokumaranService() { if (dokumaranService == null) { WebApplicationContext wac = WebApplicationContextUtils Index: lams_tool_doku/web/pages/learning/waitForTimeLimitLaunch.jsp =================================================================== diff -u -r7a4b493a0008b281e8c3ec7aafbd325165085ed9 -r6ba026f6469b284e631a6c4027aae840a2416c02 --- lams_tool_doku/web/pages/learning/waitForTimeLimitLaunch.jsp (.../waitForTimeLimitLaunch.jsp) (revision 7a4b493a0008b281e8c3ec7aafbd325165085ed9) +++ lams_tool_doku/web/pages/learning/waitForTimeLimitLaunch.jsp (.../waitForTimeLimitLaunch.jsp) (revision 6ba026f6469b284e631a6c4027aae840a2416c02) @@ -15,11 +15,39 @@ //setTimeout("refresh();", 30000); //init the connection with server using server URL but with different protocol - var websocket = new WebSocket(''.replace('http', 'ws') - + 'learningWebsocket?toolContentID=' + ${toolContentID}); + var dokuWebsocketInitTime = Date.now(), + dokuWebsocket = new WebSocket(''.replace('http', 'ws') + + 'learningWebsocket?toolContentID=' + ${toolContentID}), + dokuWebsocketPingTimeout = null, + dokuWebsocketPingFunc = null; + dokuWebsocket.onclose = function(){ + // react only on abnormal close + if (e.code === 1006 && + Date.now() - dokuWebsocketInitTime > 1000) { + location.reload(); + } + }; + + dokuWebsocketPingFunc = function(skipPing){ + if (dokuWebsocket.readyState == dokuWebsocket.CLOSING + || dokuWebsocket.readyState == dokuWebsocket.CLOSED){ + return; + } + + // check and ping every 3 minutes + dokuWebsocketPingTimeout = setTimeout(dokuWebsocketPingFunc, 3*60*1000); + // initial set up does not send ping + if (!skipPing) { + dokuWebsocket.send("ping"); + } + }; + + // set up timer for the first time + dokuWebsocketPingFunc(true); + // run when the server pushes new reports and vote statistics - websocket.onmessage = function(e) { + dokuWebsocket.onmessage = function(e) { // create JSON object var input = JSON.parse(e.data); @@ -29,7 +57,11 @@ location.reload(); return; } - }; + + // reset ping timer + clearTimeout(dokuWebsocketPingTimeout); + dokuWebsocketPingFunc(true); + };