/*
* 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.network;
import com.juniform.JUniformMutableObject;
import com.juniform.JUniformObject;
import java.io.IOException;
import java.net.ConnectException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import ragefist.core.Processor;
import ragefist.core.ProcessorTask;
/**
*
* @author acherkashin
*/
public class ClientProcessor extends Processor
{
private final Map<String,Client> _clientsMap = new HashMap<>();
private final Map<Integer,ClientProcessorTask> _waitingForResponseMap = new HashMap<>();
private final ISocketStrategy _socketStrategy = new SocketStrategyDefault();
private final ByteBuffer _readBuffer = ByteBuffer.allocate(4096);
public static class ClientProcessorTask extends ProcessorTask
{
private final Client _client;
private final JUniformMutableObject _packetToSend;
public ClientProcessorTask(Client client, JUniformMutableObject packetToSend) {
_client = client;
_packetToSend = packetToSend;
setAsync(true);
}
@Override
protected boolean _executeImpl(Processor processor) {
ClientProcessor target = (ClientProcessor)processor;
_packetToSend.setProperty("sq", this.getId());
_client.sendPacket(_packetToSend);
target._waitingForResponseMap.put(this.getId(), this);
return true;
}
}
public Client getClientForHostPort(String host, int port) throws ConnectException {
String hashCode = host + "_" + port;
Client socket;
synchronized(_clientsMap) {
if (_clientsMap.containsKey(hashCode)) {
return _clientsMap.get(hashCode);
}
socket = Client.newInstance();
if (socket == null) {
return null;
}
if (!socket.connect(new InetSocketAddress(host, port))) {
throw new ConnectException("Failed to connect to host "+host+" port "+port);
}
_clientsMap.put(hashCode, socket);
}
return socket;
}
@Override
public int processTasks() {
// check if we have something to read from
Iterator<Map.Entry<String,Client>> it = _clientsMap.entrySet().iterator();
while(it.hasNext()) {
Client client = it.next().getValue();
try {
JUniformObject[] packets = client.readPackets(_readBuffer);
if (packets == null) {
continue;
}
for(JUniformObject packet : packets) {
try {
if (packet.getProperty("sq").isNull()) {
throw new Exception("No sq param in the packet: "+packet);
}
Integer sq = packet.getProperty("sq").toInteger();
if (!_waitingForResponseMap.containsKey(sq)) {
throw new Exception("Packet with sq = "+sq+" is lost: "+packet);
}
ClientProcessorTask task = _waitingForResponseMap.get(sq);
_waitingForResponseMap.remove(sq);
task.completeWithData(packet);
}
catch(Exception ex) {
Logger.getLogger(ClientProcessor.class.getName()).log(Level.SEVERE, "Failed to unpack packet", ex);
}
}
} catch (IOException ex) {
Logger.getLogger(ClientProcessor.class.getName()).log(Level.SEVERE, "Failed to read response from client RPC connection", ex);
}
}
// processing tasks
return super.processTasks();
}
}