/* * 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(); } }