Package org.iremake.client.network

Source Code of org.iremake.client.network.RemoteClient

/*
* Copyright (C) 2012 Trilarion
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
package org.iremake.client.network;

import com.esotericsoftware.kryonet.Client;
import com.esotericsoftware.kryonet.Connection;
import com.esotericsoftware.kryonet.Listener;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.iremake.client.network.handler.ClientHandler;
import org.iremake.common.Settings;
import org.iremake.common.network.messages.KryoRegistration;
import org.iremake.common.network.messages.Message;
import org.iremake.common.network.messages.MessageContainer;

/**
* Fires up network connection for the client.
*/
public class RemoteClient extends Listener implements ClientContext {

    /* Timeout in ms for connection */
    private static final Logger LOG = Logger.getLogger(RemoteClient.class.getName());

    public static final ClientContext CONTEXT = new RemoteClient();

    /* Kryonet client */
    private Client kryoClient;
    /* The only instance */
    /**
     *
     */

    private List<ClientHandler> handlerList = new LinkedList<>();
    private ExecutorService threadPool;
   /**
     * Avoid instantiation.
     */
    private RemoteClient() {
    }

    /**
     * Connects to server.
     *
     * @param host
     * @return
     */
    @Override
    public boolean start(String host) {
        LOG.log(Level.INFO, "[CLIENT] Client connection initiated.");
        if (kryoClient != null) {
            return false;
        }

        kryoClient = new Client();

        KryoRegistration.register(kryoClient.getKryo());

        kryoClient.start();
        kryoClient.addListener(this);

        try {
            kryoClient.connect(5_000, host, Settings.NETWORK_PORT);
        } catch (IOException ex) {
            // LOG.log(Level.SEVERE, null, ex);
            LOG.log(Level.SEVERE, "[CLIENT] Client could not connect.");
            stop();
            return false;
        }
        LOG.log(Level.INFO, "[CLIENT] Client connection successful.");

        return true;
    }

    /**
     * Send message.
     *
     * @param message
     */
    // TODO do we need this here?
    @Override
    public void send(MessageContainer message) {
        if (kryoClient != null && kryoClient.isConnected()) {
            LOG.log(Level.INFO, "[CLIENT] Send message of type {0}", message.getType().name());
            kryoClient.sendTCP(message);
        }
    }

    /**
     * Stops the client.
     */
    @Override
    public void stop() {
        // TODO what happens to operations being sent?
        if (kryoClient != null) {
            LOG.log(Level.INFO, "[CLIENT] Client will shutdown.");
            kryoClient.close();
            kryoClient.stop();
            kryoClient = null;
        }
    }

    /**
     * @return A text line telling to whom we are connected
     */
    public String getStatus() {
        if (kryoClient != null) {
            return String.format("[CLIENT] Connected to server at %s.", kryoClient.getRemoteAddressTCP().getHostString());
        } else {
            return "[CLIENT] Not connected.";
        }
    }

    /**
     * @return True if running.
     */
    @Override
    public boolean isConnected() {
        return kryoClient != null && kryoClient.isConnected();
    }

    /**
     * Force disconnect.
     *
     * @param error Error message, if null nothing is sent.
     */
    @Override
    public void disconnect(String error) {
        if (kryoClient != null) {
            LOG.log(Level.INFO, "[CLIENT] We want to disconnect.");
            if (error != null) {
                send(Message.GEN_ERROR.createNew(error));
            }
            kryoClient.close();
        }
    }

    /**
     *
     * @param channel
     * @param handler
     */
    @Override
    public void addHandler(ClientHandler handler) {
        if (!handlerList.contains(handler)) {
            handlerList.add(handler);
        }
    }

    /**
     *
     * @param channel
     * @param handler
     * @return
     */
    @Override
    public boolean removeHandler(ClientHandler handler) {
        return handlerList.remove(handler);
    }

    /**
     * Sends to all handler in a channel until someone processed it (returns
     * true).
     *
     * @param message
     */
    @Override
    public void process(MessageContainer message) {

       for (ClientHandler handler : handlerList) {
            if (handler.process(message, this)) {
                break;
            }
        }
    }

    /**
     * We connected to the server.
     *
     * @param connection Can be ignored, we already know the connection from the
     * manager.
     */
    @Override
    public void connected(Connection connection) {
        LOG.log(Level.INFO, "[CLIENT] Client has connected.");
        // exactly one thread, so processing will be one by one
        threadPool = Executors.newFixedThreadPool(1);
    }

    /**
     * We disconnected from the server. Either the server disconnected us or we
     * disconnected from him.
     *
     * @param connection Can be ignored, is also stored in the context.
     */
    @Override
    public void disconnected(Connection connection) {
        LOG.log(Level.INFO, "[CLIENT] Our client was/has disconnected.");
        // TODO either we or somebody else disconnected, do something or tell somebody about it
        threadPool.shutdown();
        kryoClient = null;
    }

    /**
     * We received a message from the server, first we make sure it's of type
     * Message, then we schedule processing of this message in the
     * ExecutorService.
     *
     * @param connection Used connection
     * @param object Incoming object (message)
     */
    @Override
    public void received(Connection connection, final Object object) {
        if (connection.isConnected() && object instanceof MessageContainer) {
            final MessageContainer message = (MessageContainer) object;
            LOG.log(Level.INFO, "[CLIENT] Received message of type {0}", message.getType().name());
            // schedule for processing
            threadPool.execute(new Runnable() {
                @Override
                public void run() {
                    process(message);
                }
            });
        }
        // if it was another message, it could have been a keepalive message from the framework
    }
}
TOP

Related Classes of org.iremake.client.network.RemoteClient

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.