eu.matejkormuth.pexel.network.NettyClientComunicator.java Source code

Java tutorial

Introduction

Here is the source code for eu.matejkormuth.pexel.network.NettyClientComunicator.java

Source

// @formatter:off
/*
 * Pexel Project - Minecraft minigame server platform. 
 * Copyright (C) 2014 Matej Kormuth <http://www.matejkormuth.eu>
 * 
 * This file is part of Pexel.
 * 
 * Pexel 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.
 * 
 * Pexel 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/>.
 *
 */
// @formatter:on
package eu.matejkormuth.pexel.network;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.util.InsecureTrustManagerFactory;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.PriorityBlockingQueue;
import java.util.concurrent.TimeUnit;

import javax.net.ssl.SSLException;

import eu.matejkormuth.pexel.commons.Logger;

public class NettyClientComunicator extends MessageComunicator {
    private Bootstrap b;
    private Channel channelToMaster;
    private final ServerInfo master;
    private final Logger log;

    // Queue.
    protected BlockingQueue<NettyMessage> payloads = new PriorityBlockingQueue<NettyMessage>(100,
            new NettyMessageComparator());

    public NettyClientComunicator(final PayloadHandler handler, final int port, final String host,
            final String authKey, final SlaveServer server) {
        super(handler);

        this.master = server.getMasterServerInfo();
        this.log = server.getLogger().getChild("Netty");

        try {
            this.init(port, host, server.getName(), authKey);
        } catch (SSLException | InterruptedException e) {
            e.printStackTrace();
        }
    }

    private void init(final int port, final String host, final String thisSlaveName, final String authKey)
            throws InterruptedException, SSLException {
        this.log.info("Setting up SSL...");
        // Configure SSL.
        final SslContext sslCtx = SslContext.newClientContext(InsecureTrustManagerFactory.INSTANCE);

        EventLoopGroup group = new NioEventLoopGroup();
        try {
            this.b = new Bootstrap();
            this.b.group(group).channel(NioSocketChannel.class)
                    .handler(new NettyClientComunicatorInitializer(sslCtx, port, host));

            group.scheduleAtFixedRate(new Runnable() {
                @Override
                public void run() {
                    NettyClientComunicator.this.sendQueue();
                }
            }, 0L, 10L, TimeUnit.MILLISECONDS);

            this.log.info("Connecting to master...");
            // Start the connection attempt.
            this.channelToMaster = this.b.connect(host, port).sync().channel();

            // Log in.
            this.channelToMaster
                    .writeAndFlush(new NettyMessage(NettyRegisterMesssage.create(authKey, thisSlaveName)));

        } finally {
            // The connection is closed automatically on shutdown.
            this.log.info("Shutting down..");
            group.shutdownGracefully();
        }
    }

    protected void sendQueue() {
        while (!this.payloads.isEmpty()) {
            this.channelToMaster.writeAndFlush(this.payloads.poll());
        }
    }

    @Override
    public void send(final ServerInfo target, final byte[] payload, final int priority) {
        if (target != this.master) {
            throw new RuntimeException("Sorry, slave can only send payloads to master.");
        } else {

            this.payloads.offer(new NettyMessage(payload, priority));
        }
    }

    @Override
    public void send(final ServerInfo target, final byte[] payload) {
        this.send(target, payload, 0);
    }

    @Override
    public void stop() {
        this.channelToMaster.close();
    }

    class NettyClientComunicatorInitializer extends ChannelInitializer<SocketChannel> {
        private final SslContext sslCtx;
        private final String host;
        private final int port;

        public NettyClientComunicatorInitializer(final SslContext sslCtx, final int port, final String host) {
            this.sslCtx = sslCtx;
            this.host = host;
            this.port = port;
        }

        @Override
        public void initChannel(final SocketChannel ch) throws Exception {
            ChannelPipeline pipeline = ch.pipeline();
            pipeline.addLast(this.sslCtx.newHandler(ch.alloc(), this.host, this.port));

            // On top of the SSL handler, add the text line codec.
            pipeline.addLast(new NettyMessageDecoder());
            pipeline.addLast(new NettyMessageEncoder());

            // and then business logic.
            pipeline.addLast(new NettyClientCommunicatorHandler());
        }
    }

    class NettyClientCommunicatorHandler extends SimpleChannelInboundHandler<NettyMessage> {
        @Override
        public void channelRead0(final ChannelHandlerContext ctx, final NettyMessage msg) throws Exception {
            NettyClientComunicator.this.onReceive(NettyClientComunicator.this.master, msg.payload);
        }

        @Override
        public void exceptionCaught(final ChannelHandlerContext ctx, final Throwable cause) {
            cause.printStackTrace();
            ctx.close();
        }
    }

    @Override
    public void start() {
        // TODO Auto-generated method stub

    }

}