bridgempp.bot.wrapper.BotWrapper.java Source code

Java tutorial

Introduction

Here is the source code for bridgempp.bot.wrapper.BotWrapper.java

Source

package bridgempp.bot.wrapper;

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.protobuf.ProtobufDecoder;
import io.netty.handler.codec.protobuf.ProtobufEncoder;
import io.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder;
import io.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.StringReader;
import java.net.InetSocketAddress;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.xml.sax.InputSource;

/**
 *
 * @author Vincent Bode
 */
public class BotWrapper {

    private static Bootstrap bootstrap;

    /**
     * @param args
     *            the command line arguments
     */
    public static void main(String[] args) {
        EventLoopGroup loopGroup = new NioEventLoopGroup(2);
        bootstrap = new Bootstrap();
        bootstrap.group(loopGroup);
        bootstrap.channel(NioSocketChannel.class);
        bootstrap.handler(new ChannelInitializer<Channel>() {

            @Override
            protected void initChannel(Channel channel) throws Exception {

            }
        });
        File botsDir = new File("bots/");
        if (!botsDir.exists()) {
            botsDir.mkdir();
            Properties exampleBotProperties = new Properties();
            try {
                writeDefaultConfig(exampleBotProperties);
                exampleBotProperties.store(new FileOutputStream("bots/exampleBot.config"),
                        "Bot Wrapper Configuration");
            } catch (IOException e) {
                e.printStackTrace();
            }
            System.out.println("Created Example Config. Please Edit");
            return;
        }
        for (File botConfig : botsDir.listFiles()) {
            botInitialize(botConfig);
        }

    }

    public static void printMessage(Message message, Bot bot) {
        if (bot.channelFuture == null) {
            if (message.message.length() == 0) {
                System.out.println("CONSOLE BOT: Empty Message");
            }
            System.out.println("CONSOLE BOT: " + message.toComplexString());
            return;
        }
        if (message.message.length() == 0) {
            return;
        }
        try {
            message.validate();
        } catch (Exception e) {
            throw new InvalidMessageFormatException(e);
        }

        ProtoBuf.Message protoMessage = ProtoBuf.Message.newBuilder().setMessageFormat(message.getMessageFormat())
                .setMessage(message.getMessage()).setSender(message.getSender()).setTarget(message.getTarget())
                .setGroup(message.group).build();
        bot.channelFuture.channel().writeAndFlush(protoMessage);
        Logger.getLogger(BotWrapper.class.getSimpleName()).log(Level.INFO,
                "Outbound: " + message.toComplexString());
    }

    public static void printCommand(String command, Bot bot) {
        printMessage(new Message("operator", command), bot);
    }

    private static void botInitialize(File botConfig) {
        try {
            Properties botProperties = new Properties();
            if (!botConfig.exists()) {
                botConfig.createNewFile();
            }
            botProperties.load(new FileInputStream(botConfig));
            String botClass = botProperties.getProperty("botClass");
            if (botClass == null) {
                writeDefaultConfig(botProperties);
                throw new UnsupportedOperationException(
                        "Bot Class is null, cannot execute BridgeMPP server commands");
            }
            Bot bot = (Bot) Class.forName(botClass).newInstance();
            bot.initializeBot();
            String serverAddress = botProperties.getProperty("serverAddress");
            int portNumber = Integer.parseInt(botProperties.getProperty("serverPort"));
            if (serverAddress == null) {
                writeDefaultConfig(botProperties);
                throw new UnsupportedOperationException(
                        "Server Address is null, cannot execute BridgeMPP server commands");
            }
            ChannelFuture channelFuture = bootstrap.connect(new InetSocketAddress(serverAddress, portNumber));
            byte[] protocol = new byte[1];
            protocol[0] = 0x32;
            channelFuture.await();
            channelFuture.channel().writeAndFlush(Unpooled.wrappedBuffer(protocol));
            channelFuture.channel().pipeline().addLast("frameDecoder", new ProtobufVarint32FrameDecoder());
            channelFuture.channel().pipeline().addLast("protobufDecoder",
                    new ProtobufDecoder(ProtoBuf.Message.getDefaultInstance()));
            channelFuture.channel().pipeline().addLast("frameEncoder", new ProtobufVarint32LengthFieldPrepender());
            channelFuture.channel().pipeline().addLast("protobufEncoder", new ProtobufEncoder());
            channelFuture.channel().pipeline().addLast(new IncommingMessageHandler(bot));
            bot.channelFuture = channelFuture;
            bot.setProperties(botProperties);

            String serverKey = botProperties.getProperty("serverKey");
            if (serverKey == null) {
                writeDefaultConfig(botProperties);
                throw new UnsupportedOperationException(
                        "Server Key is null, cannot execute BridgeMPP server commands");
            }
            printCommand("!usekey " + serverKey, bot);
            String botAlias = botProperties.getProperty("botname");
            if (botAlias != null) {
                printCommand("!createalias " + botAlias, bot);
            }
            bot.name = botAlias;
            String[] groups = botProperties.getProperty("groups").split("; ");
            for (int i = 0; i < groups.length; i++) {
                printCommand("!subscribegroup " + groups[i], bot);
            }
            System.out.println("Joined " + groups.length + " groups");

        } catch (IOException | ClassNotFoundException | InstantiationException | IllegalAccessException
                | InterruptedException ex) {
            Logger.getLogger(BotWrapper.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    private static void writeDefaultConfig(Properties botProperties) throws IOException {
        botProperties.put("serverKey", "<insertserveraccesskey>");
        botProperties.put("botname", "<Ahumanreadablebotname>");
        botProperties.put("groups", "<groupname1>; <groupname2>");
        botProperties.put("process", "<BotProcessWrapperLaunchCommand>");
        botProperties.put("botClass", "<FQ Class Name>");
    }

    public static abstract class Bot {

        public String name;
        Properties properties;
        ChannelFuture channelFuture;

        public final void setProperties(Properties properties) {
            this.properties = properties;
        }

        public abstract void initializeBot();

        public abstract void messageRecieved(Message message);

        public void sendMessage(Message message) {
            printMessage(message, this);
        }
    }

    public static class IncommingMessageHandler extends SimpleChannelInboundHandler<ProtoBuf.Message> {
        private Bot bot;

        public IncommingMessageHandler(Bot bot) {
            this.bot = bot;
        }

        protected void channelRead0(ChannelHandlerContext channelHandlerContext, ProtoBuf.Message protoMessage) {
            Message message = new Message(protoMessage.getGroup(), protoMessage.getSender(),
                    protoMessage.getTarget(), protoMessage.getMessage(), protoMessage.getMessageFormat());
            Logger.getLogger(BotWrapper.class.getName()).log(Level.INFO, "Inbound: " + message.toComplexString());
            if (message.getMessage().startsWith("?botwrapper reload")) {
                bot.sendMessage(new Message(message.getGroup(),
                        "Bot Wrapper reloading. Respawn Throttle 60 seconds", "Plain Text"));
                System.exit(0);
            }
            if (message.getMessage().startsWith("?botwrapper ping")) {
                bot.sendMessage(
                        new Message(message.getGroup(), "This is " + bot.name + " at your service", "Plain Text"));
            }
            try {
                bot.messageRecieved(message);
            } catch (Exception e) {
                printMessage(new Message(message.getGroup(),
                        "A Bot has crashed!\n" + e.toString() + "\n" + e.getStackTrace()[0].toString(),
                        "Plain Text"), bot);
            }
        }

        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
            Logger.getLogger(BotWrapper.class.getName()).log(Level.SEVERE,
                    "A Connection has been disconnected, exiting...", cause);
            System.exit(0);
        }

    }

    public static class Message {
        private String group;
        private String sender;
        private String target;
        private String message;
        private String messageFormat;

        public Message() {

        }

        public void validate() throws Exception {
            if (getMessage().length() > 60000) {
                throw new Exception(
                        "Dangerous Message Length " + getMessage().length() + "! Send request rejected");
            }
            switch (messageFormat) {
            case "XHTML":
                DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
                factory.setNamespaceAware(false);
                factory.setValidating(false);
                factory.setExpandEntityReferences(false);
                DocumentBuilder builder = factory.newDocumentBuilder();
                builder.parse(new InputSource(new StringReader("<body>" + getMessage() + "</body>")));
                break;
            default:
                break;
            }
        }

        @Deprecated
        public Message(String sender, String message) {
            this("", sender, "", message, "Plain Text");
        }

        public Message(String group, String message, String messageFormat) {
            this(group, "", "", message, messageFormat);
        }

        public Message(String group, String sender, String target, String message, String messageFormat) {
            this.setGroup(group);
            this.setSender(sender);
            this.setTarget(target);
            this.setMessage(message);
            this.setMessageFormat(messageFormat);
        }

        public static Message parseMessage(String complexString) {
            Message message = new Message();
            String[] messageSplit = complexString.split("\\s*(?::| -->)\\s+", 5);
            if (messageSplit.length == 5) {
                message.setMessageFormat(messageSplit[0]);
                message.setGroup(messageSplit[1]);
                message.setSender(messageSplit[2]);
                message.setTarget(messageSplit[3]);
                message.setMessage(messageSplit[4]);
            } else {
                message.setMessage(complexString);
            }
            return message;
        }

        public String toComplexString() {
            String messageFormat = getMessageFormat() + ": ";
            String group = (getGroup() != null) ? (getGroup() + ": ") : "Direct Message: ";
            String sender = (getSender() != null) ? getSender().toString() : "Unknown";
            String target = (getTarget() != null) ? (getTarget().toString() + ": ") : ("Unknown: ");
            return messageFormat + group + sender + " --> " + target + getMessage();
        }

        /**
         * @return the group
         */
        public String getGroup() {
            return group;
        }

        /**
         * @param group
         *            the group to set
         */
        public void setGroup(String group) {
            this.group = group;
        }

        /**
         * @return the sender
         */
        public String getSender() {
            return sender;
        }

        /**
         * @param sender
         *            the sender to set
         */
        public void setSender(String sender) {
            this.sender = sender;
        }

        /**
         * @return the target
         */
        public String getTarget() {
            return target;
        }

        /**
         * @param target
         *            the target to set
         */
        public void setTarget(String target) {
            this.target = target;
        }

        /**
         * @return the message
         */
        public String getMessage() {
            return message;
        }

        /**
         * @param message
         *            the message to set
         */
        public void setMessage(String message) {
            this.message = message;
        }

        /**
         * @return the messageFormat
         */
        public String getMessageFormat() {
            return messageFormat;
        }

        /**
         * @param messageFormat
         *            the messageFormat to set
         */
        public void setMessageFormat(String messageFormat) {
            this.messageFormat = messageFormat;
        }

    }
}