package de.maxgb.minecraft.second_screen; import java.io.IOException; import java.net.InetSocketAddress; import java.util.HashMap; import java.util.Iterator; import net.minecraft.server.MinecraftServer; import net.minecraftforge.fml.common.FMLCommonHandler; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.common.gameevent.TickEvent.ServerTickEvent; import org.java_websocket.WebSocket; import org.java_websocket.WebSocketImpl; import org.java_websocket.handshake.ClientHandshake; import org.java_websocket.server.WebSocketServer; import de.maxgb.minecraft.second_screen.util.ForceUpdateEvent; import de.maxgb.minecraft.second_screen.util.Logger; /** * Manages the websocket and all handlers. * All communication runs through this class * @author Max * */ public class WebSocketListener { private class MSSWebSocketServer extends WebSocketServer { private final static String TAG = "MSSWebSocketServer"; public MSSWebSocketServer(InetSocketAddress address) { super(address); } @Override public void onClose(WebSocket conn, int code, String reason, boolean remote) { WebSocketHandler h = handlers.get(conn.getRemoteSocketAddress()); if (h != null) { synchronized (handlers) { h.close(); handlers.remove(conn.getRemoteSocketAddress()); Logger.i(TAG, "Closed Handler/Connection for " + conn.getRemoteSocketAddress().toString()); } } else { Logger.i(TAG, "Handler for " + conn.getRemoteSocketAddress().toString() + " was already removed"); } } @Override public void onError(WebSocket conn, Exception ex) { Logger.e(TAG, "Received Error", ex); error = ex.getMessage(); running = false; } @Override public void onMessage(WebSocket conn, String message) { synchronized (handlers) { Logger.i(TAG, "Received msg for " + conn.getRemoteSocketAddress().toString() + ": " + message);// TODO // remove WebSocketHandler h = handlers.get(conn.getRemoteSocketAddress()); if (h != null) { h.onMessage(message); } else { Logger.w(TAG, "Could not find handler for " + conn.getRemoteSocketAddress().toString()); // onOpen(conn,null);//?? } } } @Override public void onOpen(WebSocket conn, ClientHandshake handshake) { Logger.i(TAG, "New connection: " + conn.getRemoteSocketAddress().toString()); handlers.put(conn.getRemoteSocketAddress(), new WebSocketHandler(conn)); } /** * Does super{@link #stop(int)}, but adds a debug log call */ @Override public void stop(int timeout) throws InterruptedException{ Logger.d(TAG, "WebsocketServer received stop call with timeout "+timeout); super.stop(timeout); } } private final static String TAG = "WebSocketListener"; public static int getNewHandlerID() { return ++handlerCount; } private HashMap<InetSocketAddress, WebSocketHandler> handlers; private MSSWebSocketServer socketServer; private Thread serverThread; private boolean running; private String error="Unknown"; private static int handlerCount = 0; public WebSocketListener() { handlers = new HashMap<InetSocketAddress, WebSocketHandler>(); FMLCommonHandler.instance().bus().register(this); } private void closeAll() { synchronized (handlers) { Logger.d(TAG, "Closing all handlers"); for (WebSocketHandler h : handlers.values()) { h.close(); } handlers.clear(); } } private MSSWebSocketServer create() { int port = SecondScreenMod.instance.port; String hostname = SecondScreenMod.instance.hostname; if (port == 0) { port = MinecraftServer.getServer().getPort(); } return new MSSWebSocketServer(new InetSocketAddress(hostname, port)); } @SubscribeEvent public void forceUpdate(ForceUpdateEvent e) { Logger.i(TAG, "Forcing update for " + e.listener.toString()); synchronized (handlers) { for (WebSocketHandler h : handlers.values()) { h.forceUpdate(e); } } } public void start() { if(Configs.debug_mode){ WebSocketImpl.DEBUG=true; } socketServer = create(); Logger.i(TAG, "Starting WebSocketListener on " + socketServer.getAddress().toString()); if (socketServer != null) { serverThread = new Thread(socketServer); running = true; serverThread.start(); } else { Logger.e(TAG, "Socket server null"); } } public boolean isRunning(){ return running; } public String getError(){ if(running){ return ""; } return error; } public void stop() { closeAll(); try { socketServer.stop(); } catch (InterruptedException e) { e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } socketServer = null; Logger.i(TAG, "Stopped server"); } @SubscribeEvent public void tick(ServerTickEvent e) { synchronized (handlers) { Iterator<WebSocketHandler> iterator=handlers.values().iterator(); while (iterator.hasNext()) { WebSocketHandler h=iterator.next(); if (h.isGettingRemoved()) { Logger.d(TAG, "Handler "+h+" indicates it wants to be removed"); handlers.remove(h.address); } else { h.tick(); } } } } }