de.jackwhite20.japs.server.network.Connection.java Source code

Java tutorial

Introduction

Here is the source code for de.jackwhite20.japs.server.network.Connection.java

Source

/*
 * Copyright (c) 2016 "JackWhite20"
 *
 * This file is part of JaPS.
 *
 * JaPS 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 de.jackwhite20.japs.server.network;

import de.jackwhite20.japs.server.JaPS;
import de.jackwhite20.japs.server.JaPSServer;
import de.jackwhite20.japs.shared.net.OpCode;
import de.jackwhite20.japs.shared.pipeline.ChannelUtil;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import org.json.JSONObject;

import java.io.IOException;
import java.net.SocketAddress;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Created by JackWhite20 on 25.03.2016.
 */
public class Connection extends SimpleChannelInboundHandler<JSONObject> {

    private static final Logger LOGGER = JaPS.getLogger();

    private JaPSServer server;

    private List<String> channels = new ArrayList<>();

    private SocketAddress remoteAddress;

    private Channel channel;

    private String host;

    private int port;

    private String name;

    public Connection(JaPSServer server, Channel channel) {

        this.server = server;
        this.channel = channel;
        this.remoteAddress = channel.remoteAddress();
    }

    public void send(JSONObject jsonObject) {

        channel.writeAndFlush(jsonObject);
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {

        server.removeClient(this);

        LOGGER.log(Level.FINE, "[{0}] Connection closed", remoteAddress.toString());
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {

        LOGGER.log(Level.FINE, "[{0}] New connection", remoteAddress.toString());
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, JSONObject jsonObject) throws Exception {

        if (jsonObject.isNull("op")) {
            return;
        }

        int op = ((Integer) jsonObject.remove("op"));

        OpCode opCode = OpCode.of(op);

        switch (opCode) {
        case OP_BROADCAST:
            if (!jsonObject.has("su")) {
                // Broadcast it to all subscriber
                server.broadcast(this, jsonObject.getString("ch"), jsonObject);
            } else {
                // Broadcast to specific subscriber
                server.broadcastTo(this, jsonObject.getString("ch"), jsonObject, jsonObject.getString("su"));
            }
            break;
        case OP_CACHE_GET:
            String getKey = jsonObject.getString("key");
            int getCallbackId = jsonObject.getInt("id");

            Object getValue = server.cache().get(getKey);

            JSONObject getResponse = new JSONObject().put("op", 5).put("id", getCallbackId).put("value", getValue);

            send(getResponse);

            LOGGER.log(Level.FINE, "[{0}] Got cache entry {1}={2} and a callback id of {3}",
                    new Object[] { remoteAddress.toString(), getKey, getValue, getCallbackId });
            break;
        case OP_CACHE_ADD:
            String key = jsonObject.getString("key");
            Object value = jsonObject.get("value");
            int expire = jsonObject.getInt("expire");

            server.cache().put(key, value, expire);

            server.clusterBroadcast(this, jsonObject.put("op", OpCode.OP_CACHE_ADD.getCode()));

            LOGGER.log(Level.FINE, "[{0}] Added cache entry {1}={2} with an expire of {3}",
                    new Object[] { remoteAddress.toString(), key, value, expire });
            break;
        case OP_CACHE_REMOVE:
            String removeKey = jsonObject.getString("key");

            server.cache().remove(removeKey);

            server.clusterBroadcast(this, jsonObject.put("op", OpCode.OP_CACHE_REMOVE.getCode()));

            LOGGER.log(Level.FINE, "[{0}] Removed cache entry with key {1}",
                    new Object[] { remoteAddress.toString(), removeKey });
            break;
        case OP_CACHE_HAS:
            boolean has = server.cache().has(jsonObject.getString("key"));

            JSONObject hasResponse = new JSONObject().put("op", OpCode.OP_CACHE_HAS.getCode())
                    .put("id", jsonObject.getInt("id")).put("has", has);

            send(hasResponse);
            break;
        case OP_CACHE_SET_EXPIRE:
            String expireKey = jsonObject.getString("key");
            int expireSeconds = jsonObject.getInt("expire");

            server.cache().expire(expireKey, expireSeconds);

            server.clusterBroadcast(this, jsonObject.put("op", OpCode.OP_CACHE_SET_EXPIRE.getCode()));

            LOGGER.log(Level.FINE, "[{0}] Set expire seconds for key {1} to {2} seconds",
                    new Object[] { remoteAddress.toString(), expireKey, expireSeconds });
            break;
        case OP_CACHE_GET_EXPIRE:
            String expireGetKey = jsonObject.getString("key");
            int expireGetCallbackId = jsonObject.getInt("id");

            int expireGetValue = ((int) server.cache().expire(expireGetKey));

            JSONObject expireGetResponse = new JSONObject().put("op", 5).put("id", expireGetCallbackId).put("value",
                    expireGetValue);

            send(expireGetResponse);

            LOGGER.log(Level.FINE, "[{0}] Got expire in time for key {1} which will expire in {2} seconds",
                    new Object[] { remoteAddress.toString(), expireGetKey, expireGetValue });
            break;
        case OP_REGISTER_CHANNEL:
            String channelToRegister = jsonObject.getString("ch");

            server.subscribeChannel(channelToRegister, this);
            channels.add(channelToRegister);
            break;
        case OP_UNREGISTER_CHANNEL:
            String channelToRemove = jsonObject.getString("ch");

            server.unsubscribeChannel(channelToRemove, this);
            channels.remove(channelToRemove);
            break;
        case OP_SUBSCRIBER_SET_NAME:
            name = jsonObject.getString("su");

            LOGGER.log(Level.FINE, "[{0}] Subscriber name set to: {1}",
                    new Object[] { remoteAddress.toString(), name });
            break;
        case OP_CLUSTER_INFO_SET:
            host = jsonObject.getString("host");
            port = jsonObject.getInt("port");

            LOGGER.log(Level.FINE, "[{0}] Cluster info set to: {1}:{2}",
                    new Object[] { remoteAddress.toString(), host, String.valueOf(port) });
            break;
        case OP_KEEP_ALIVE:
            // Ignore for now
            //LOGGER.log(Level.FINE, "[{0}] Keep alive time: {1}", new Object[]{remoteAddress.toString(), System.currentTimeMillis()});
            break;
        case OP_UNKNOWN:
            LOGGER.log(Level.WARNING, "[{0}] Unknown OP code received: {0}",
                    new Object[] { remoteAddress.toString(), op });
            break;
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {

        ChannelUtil.closeOnFlush(channel);

        if (!(cause instanceof IOException)) {
            cause.printStackTrace();

            LOGGER.log(Level.SEVERE, "Error: " + cause.toString());
        }
    }

    public List<String> channels() {

        return channels;
    }

    public SocketAddress remoteAddress() {

        return remoteAddress;
    }

    public String host() {

        return host;
    }

    public int port() {

        return port;
    }

    public String name() {

        return name;
    }

    public boolean connected() {

        return channel.isActive();
    }
}