/* * Created by Andrey Cherkashin (acherkashin) * http://acherkashin.me * * License * Copyright (c) 2015 Andrey Cherkashin * The project released under the MIT license: http://opensource.org/licenses/MIT */ package ragefist.core.distribution; import com.juniform.JUniform; import com.juniform.JUniformObject; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; import ragefist.Main; import ragefist.core.environment.EnvironmentProcessor; import ragefist.core.environment.EnvironmentProcessor.EnvironmentBuilder; import ragefist.core.network.Connection; import ragefist.core.network.Server; import ragefist.core.network.SocketStrategyConsole; import ragefist.core.network.SocketStrategyDefault; import ragefist.core.network.SocketStrategyHTTP; import ragefist.extension.Extension; /** * * @author acherkashin */ public class DistributedServerController { // ---------------------------------------------------------------------- // // PRIVATE // ---------------------------------------------------------------------- // private final List<Extension> _extensions = new ArrayList<>(); private final List<Thread> _environmentThreads = new ArrayList<>(); private final List<EnvironmentProcessor> _environments = new ArrayList<>(); private Thread _rpcServerThread; private Server _rpcServer; private Thread _consoleServerThread; private Server _consoleServer; private Thread _clientServerThread; private Server _clientServer; private Thread _httpClientServerThread; private Server _httpClientServer; private final DistributedServer _controlledServer; private final DistributedServerGroup _controlledServerGroup; private final DistributedServerControllerAPI _api; private final DistributedServerConnector _connector; private Thread _connectorThread; private final Map<String,DistributedServerGroup> _serverGroupMap; private final DistributedServerPacketHandler _rpcPacketHandler; private final DistributedServerPacketHandler _consolePacketHandler; private final DistributedServerPacketHandler _clientPacketHandler; private final boolean _disableCrossEnvironmentInteraction; private final boolean _isTestServer; // ---------------------------------------------------------------------- // // API // This interface will be used in packet handlers. It gives us a possibility // to hide functions like run() or start() from them. // ---------------------------------------------------------------------- // public final class DistributedServerControllerAPI { public final String getCurrentServerGroupCode() { return _controlledServerGroup.getCode(); } public final int getCurrentServerId() { return _controlledServer.getId(); } public final SelectionPolicy getSelectionPolicy() { return _controlledServer.getSelectionPolicy(); } public final int getEnvironmentCount() { return _environments.size(); } public final EnvironmentProcessor getEnvironmentById(int id) { return _environments.get(id); } public final DistributedServerConnector getConnector() { return _connector; } public final int getRPCConnectionsCount() { return _rpcServer.getConnectionsCount(); } public final int getClientConnectionsCount() { return _clientServer.getConnectionsCount(); } public final int getConsoleConnectionsCount() { return _consoleServer.getConnectionsCount(); } public final boolean isCrossEnvironmentInteractionDisabled() { return _disableCrossEnvironmentInteraction; } public final boolean isTestServer() { return _isTestServer; } public final boolean sendMessageToClient(int id, JUniformObject data) { Connection connection = _clientServer.getConnectionById(id); if (connection != null) { connection.sendPacket(data); return true; } return false; } public final List<Extension> getExtensions() { return _extensions; } } // ---------------------------------------------------------------------- // // BUILDER // ---------------------------------------------------------------------- // public static class DistributedServerControllerBuilder { // @required public DistributedServerGroup controlledServerGroup; public DistributedServer controlledServer; public Map<String,DistributedServerGroup> serverGroupMap; public boolean disableCrossEnvironmentInteraction = false; public boolean isTestServer = false; // @optional public Class<? extends DistributedServerPacketHandler> rpcPacketHandlerClass; public Class<? extends DistributedServerPacketHandler> consolePacketHandlerClass; public Class<? extends DistributedServerPacketHandler> clientPacketHandlerClass; protected void _checkBuildThrowExceptions() throws IllegalArgumentException { if (controlledServerGroup == null) { throw new IllegalArgumentException("DistributedServer.controlledServerGroup is null"); } if (controlledServer == null) { throw new IllegalArgumentException("DistributedServer.controlledServer is null"); } if (serverGroupMap == null || serverGroupMap.isEmpty()) { throw new IllegalArgumentException("DistributedServer.serverGroupMap is null or empty"); } } public DistributedServerController build() throws IllegalArgumentException { _checkBuildThrowExceptions(); return new DistributedServerController(this); } } private DistributedServerController(DistributedServerControllerBuilder builder) throws IllegalArgumentException { _controlledServer = builder.controlledServer; _controlledServerGroup = builder.controlledServerGroup; _api = this.new DistributedServerControllerAPI(); _serverGroupMap = builder.serverGroupMap; _connector = new DistributedServerConnector(_serverGroupMap); _disableCrossEnvironmentInteraction = builder.disableCrossEnvironmentInteraction; _isTestServer = builder.isTestServer; try { if (builder.clientPacketHandlerClass != null) { _clientPacketHandler = builder.clientPacketHandlerClass.getConstructor(DistributedServerControllerAPI.class).newInstance(_api); } else { _clientPacketHandler = null; } if (builder.rpcPacketHandlerClass != null) { _rpcPacketHandler = builder.rpcPacketHandlerClass.getConstructor(DistributedServerControllerAPI.class).newInstance(_api); } else { _rpcPacketHandler = null; } if (builder.consolePacketHandlerClass != null) { _consolePacketHandler = builder.consolePacketHandlerClass.getConstructor(DistributedServerControllerAPI.class).newInstance(_api); } else { _consolePacketHandler = null; } } catch (NoSuchMethodException | InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) { throw new IllegalArgumentException(ex); } } // ---------------------------------------------------------------------- // // Interface // ---------------------------------------------------------------------- // public DistributedServerControllerAPI getAPI() { return _api; } public void addExtension(Extension extension) { _extensions.add(extension); } // ---------------------------------------------------------------------- // // RUN // ---------------------------------------------------------------------- // public boolean start() { // ------------------------ // // CREATING ENVIRONMENTS // ------------------------ // // Environments builder EnvironmentBuilder builder = new EnvironmentBuilder(); builder.luaConnectorFile = _controlledServer.getEnvironmentLuaConnectorFile(); builder.luaMainFile = _controlledServer.getEnvironmentLuaMainFile(); builder.serverControllerAPI = _api; // Creating Lua environments in different threads try { for(int i = 0; i < _controlledServer.getEnvironmentCount(); i++) { // Builder params builder.id = i; // Build & start EnvironmentProcessor environment = builder.build(); _environments.add(environment); Thread thread = new Thread(environment); _environmentThreads.add(thread); thread.start(); } } catch(IllegalArgumentException ex) { Logger.getLogger(DistributedServerController.class.getName()).log(Level.SEVERE, "Failed to create all the environments", ex); return false; } // ------------------------ // // SETTING UP SERVERS // ------------------------ // Server.ServerBuilder serverBuilder = new Server.ServerBuilder(); // RPC SERVER serverBuilder.host = _controlledServer.getRPCHost(); serverBuilder.port = _controlledServer.getRPCPort(); serverBuilder.packetHandler = _rpcPacketHandler; serverBuilder.packetPacker = JUniform.getPackerInstance(_controlledServer.getRPCPacketFormat()); serverBuilder.socketStrategy = SocketStrategyDefault.getInstance(); try { _rpcServer = serverBuilder.build(); _rpcServer.open(); } catch(IllegalArgumentException | IOException ex) { Logger.getLogger(Main.class.getName()).log(Level.SEVERE, "Failed to build RPC server", ex); return false; } _rpcServerThread = new Thread(_rpcServer); _rpcServerThread.start(); // CONSOLE SERVER serverBuilder.host = _controlledServer.getConsoleHost(); serverBuilder.port = _controlledServer.getConsolePort(); serverBuilder.packetHandler = _consolePacketHandler; serverBuilder.packetPacker = JUniform.getPackerInstance(JUniform.PACKER_TYPE_STRING); serverBuilder.socketStrategy = SocketStrategyConsole.getInstance(); try { _consoleServer = serverBuilder.build(); _consoleServer.open(); } catch(IllegalArgumentException | IOException ex) { Logger.getLogger(Main.class.getName()).log(Level.SEVERE, "Failed to build CONSOLE server", ex); return false; } _consoleServerThread = new Thread(_consoleServer); _consoleServerThread.start(); // CLIENT SERVER serverBuilder.host = _controlledServer.getClientHost(); serverBuilder.port = _controlledServer.getClientPort(); serverBuilder.packetHandler = _clientPacketHandler; serverBuilder.packetPacker = JUniform.getPackerInstance(_controlledServer.getClientPacketFormat()); serverBuilder.socketStrategy = SocketStrategyDefault.getInstance(); try { _clientServer = serverBuilder.build(); _clientServer.open(); } catch(IllegalArgumentException | IOException ex) { Logger.getLogger(Main.class.getName()).log(Level.SEVERE, "Failed to build CLIENT server", ex); return false; } _clientServerThread = new Thread(_clientServer); _clientServerThread.start(); // HTTP CLIENT SERVER if (_controlledServer.getHTTPClientHost() != null && _controlledServer.getHTTPClientPort() != 0 ) { serverBuilder.host = _controlledServer.getHTTPClientHost(); serverBuilder.port = _controlledServer.getHTTPClientPort(); serverBuilder.packetHandler = _clientPacketHandler; serverBuilder.packetPacker = JUniform.getPackerInstance(_controlledServer.getHTTPClientPacketFormat()); serverBuilder.socketStrategy = SocketStrategyHTTP.getInstance(); try { _httpClientServer = serverBuilder.build(); _httpClientServer.open(); } catch(IllegalArgumentException | IOException ex) { Logger.getLogger(Main.class.getName()).log(Level.SEVERE, "Failed to build CLIENT server", ex); return false; } _httpClientServerThread = new Thread(_httpClientServer); _httpClientServerThread.start(); } // ------------------------ // // SETTING UP CONNECTOR // ------------------------ // _connectorThread = new Thread(_connector); _connectorThread.start(); return true; } }