/*
* 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.JUniformMutableObject;
import com.juniform.JUniformObject;
import java.net.ConnectException;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import ragefist.core.Processor;
import ragefist.core.ProcessorTask;
import ragefist.core.ProcessorTask.IProcessorTaskDelegate;
import ragefist.core.network.Client;
import ragefist.core.network.ClientProcessor;
import ragefist.core.network.ClientProcessor.ClientProcessorTask;
import ragefist.core.network.Server;
/**
*
* @author acherkashin
*/
public class DistributedServerConnector extends Processor implements Runnable, IProcessorTaskDelegate
{
// ---------------------------------------------------------------------- //
// TASKS MANAGEMENTS
// ---------------------------------------------------------------------- //
public static class DistributedServerConnectorTask extends ProcessorTask
{
private final String _serverGroupName;
private final int _serverId;
private final JUniformMutableObject _packet;
public DistributedServerConnectorTask(String groupName, int serverId, JUniformMutableObject packet) {
_serverGroupName = groupName;
_serverId = serverId;
_packet = packet;
setAsync(true);
}
@Override
protected boolean _executeImpl(Processor processor) {
DistributedServerConnector target = (DistributedServerConnector)processor;
Client client;
try {
client = target._getRemoteServerSocket(_serverGroupName, _serverId);
} catch (IllegalArgumentException | ConnectException ex) {
Logger.getLogger(DistributedServerConnector.class.getName()).log(Level.SEVERE, "failed to connect to a remote server", ex);
this.failWithError("Failed to connect to a remote server: "+ex.getMessage());
return false;
}
if (client == null) {
this.failWithError("Failed to connect to a remote server: unknown reason");
return false;
}
ClientProcessorTask sendTask = new ClientProcessorTask(client, _packet);
sendTask.setDelegate(target);
sendTask.setAttachment(this);
target._clientProcessor.addTask(sendTask);
return true;
}
}
@Override
public void whenTaskIsFinished(ProcessorTask task) {
DistributedServerConnectorTask parentTask = (DistributedServerConnectorTask) task.getAttachment();
JUniformObject resp = (JUniformObject) task.getData();
Long rs = resp.getProperty("rs").toLong();
JUniformObject data = null;
if (resp.getProperty("data").isNotNull()) {
data = resp.getProperty("data");
}
String error = null;
if (resp.getProperty("error").isNotNull()) {
error = resp.getProperty("error").toString();
}
if (rs == 1) {
if (data != null) {
parentTask.completeWithData(data);
} else {
parentTask.complete();
}
} else {
parentTask.failWithError(error);
}
}
// ---------------------------------------------------------------------- //
// PRIVATE
// ---------------------------------------------------------------------- //
private final Map<String,Map<Integer,Client>> _connectorHash = new HashMap<>();
private final Map<String,DistributedServerGroup> _serverGroups;
private final ClientProcessor _clientProcessor;
public DistributedServerConnector(Map<String,DistributedServerGroup> serverGroups) {
_serverGroups = serverGroups;
_clientProcessor = new ClientProcessor();
}
@Override
public void run() {
while(true) {
this.processTasks();
_clientProcessor.processTasks();
try {
Thread.sleep(1);
} catch (InterruptedException ex) {
Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
private Client _getRemoteServerSocket(String groupName, int serverId) throws IllegalArgumentException, ConnectException {
if (_connectorHash.containsKey(groupName)) {
Map<Integer,Client> socketMap = _connectorHash.get(groupName);
if (socketMap.containsKey(serverId)) {
return socketMap.get(serverId);
}
}
// Getting a server's info
if (!_serverGroups.containsKey(groupName)) {
throw new IllegalArgumentException("Failed to find server group with name "+groupName);
}
DistributedServerGroup serverGroup = _serverGroups.get(groupName);
DistributedServer server;
try {
server = serverGroup.getServers().get(serverId);
} catch (IndexOutOfBoundsException ex) {
throw new IllegalArgumentException("Failed to find server "+serverId+" in group with name "+groupName);
}
// Creating a socket
Client socket = _clientProcessor.getClientForHostPort(server.getRPCHost(), server.getRPCPort());
socket.setPacketPacker(JUniform.getPackerInstance(server.getRPCPacketFormat()));
// Save
Map<Integer,Client> socketMap;
if (!_connectorHash.containsKey(groupName)) {
socketMap = new HashMap<>();
_connectorHash.put(groupName, socketMap);
} else {
socketMap = _connectorHash.get(groupName);
}
socketMap.put(serverId, socket);
return socket;
}
}