Package us.aaronweiss.juicebot

Source Code of us.aaronweiss.juicebot.Bot

/*
* Copyright (C) 2013 Aaron Weiss <aaronweiss74@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom
* the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package us.aaronweiss.juicebot;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.channel.oio.OioEventLoopGroup;
import io.netty.channel.socket.oio.OioSocketChannel;
import io.netty.handler.codec.LineBasedFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.handler.ssl.SslHandler;
import io.netty.util.CharsetUtil;
import io.netty.util.concurrent.GlobalEventExecutor;
import us.aaronweiss.juicebot.internal.InternalUtilities;
import us.aaronweiss.juicebot.net.ClientHandlerAdapter;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
* The core of all juicebot bots, handling all necessary internals.
*
* @author Aaron Weiss
* @version 2.0.1
* @since 1.0.0
*/
public abstract class Bot implements Client {
  protected static ScheduledExecutorService executor = Executors.newScheduledThreadPool(Runtime.getRuntime().availableProcessors());
  protected final ChannelGroup sessions = new DefaultChannelGroup("sessions", GlobalEventExecutor.INSTANCE);
  protected TimeUnit timeUnit = TimeUnit.SECONDS;
  protected final Bootstrap bootstrap;
  protected int periodicTime = -1;
  private final boolean simple;
  private String username;

  /**
   * Constructs a new {@code Bot}.
   *
   * @param username the username of the bot
   */
  public Bot(String username) {
    this(username, false);
  }

  /**
   * Constructs a new {@code Bot}.
   *
   * @param username the username of the bot
   * @param simple   whether or not the bot should use the simple messaging API
   */
  public Bot(String username, boolean simple) {
    this(username, simple, false);
  }

  /**
   * Constructs a new {@code Bot}.
   *
   * @param username the username of the bot
   * @param simple   whether or not the bot should use the simple messaging API
   * @param useSSL   whether or not the bot should use SSL
   */
  public Bot(String username, boolean simple, final boolean useSSL) {
    this.username = username;
    this.simple = simple;
    bootstrap = new Bootstrap();
    bootstrap.group(new OioEventLoopGroup());
    bootstrap.channel(OioSocketChannel.class);
    bootstrap.handler(new ChannelInitializer<OioSocketChannel>() {
      @Override
      protected void initChannel(OioSocketChannel ch) throws Exception {
        ChannelPipeline pipeline = ch.pipeline();

        // SSL Support
        if (useSSL) {
          SSLEngine engine = SSLContext.getDefault().createSSLEngine();
          engine.setUseClientMode(true);
          pipeline.addLast("ssl", new SslHandler(engine));
        }

        // Decoders
        pipeline.addLast("frameDecoder", new LineBasedFrameDecoder(1000));
        pipeline.addLast("stringDecoder", new StringDecoder(CharsetUtil.UTF_8));

        // Encoder
        pipeline.addLast("stringEncoder", new StringEncoder(CharsetUtil.UTF_8));

        // Handlers
        pipeline.addLast("botHandler", new ClientHandlerAdapter(Bot.this));
      }
    });
    bootstrap.option(ChannelOption.TCP_NODELAY, true);
  }

  @Override
  public Channel connect(String address) {
    if (address.contains("[") || address.contains("]")) {
      if (address.lastIndexOf(":") > address.indexOf("]")) {
        return connect(address.substring(0, address.lastIndexOf(":")), address.substring(address.lastIndexOf(":")));
      } else {
        return connect(address, "6667");
      }
    } else if (address.contains(":")) {
      if (address.indexOf(":") == address.lastIndexOf(":")) {
        String[] adr = address.split(":");
        return connect(adr[0], adr[1]);
      } else {
        return connect(address, "6667");
      }
    } else {
      return connect(address, "6667");
    }
  }

  @Override
  public Channel connect(String address, String port) {
    return connect(new InetSocketAddress(address, Integer.parseInt(port)));
  }

  @Override
  public Channel connect(SocketAddress address) {
    final ChannelFuture cf = bootstrap.connect(address);
    sessions.add(cf.channel());
    if (periodicTime > 0) {
      // this could be simplified with lambda expressions... cmd = this::periodic(cf.channel())
      Runnable cmd = new Runnable() {
        @Override
        public void run() {
          periodic(cf.channel());
        }
      };
      executor.scheduleAtFixedRate(cmd, periodicTime, periodicTime, timeUnit);
    }
    return cf.channel();
  }

  @Override
  public void disconnect(Channel session) {
    session.close();
  }

  @Override
  public void connected(Channel session) {
    setUsername(username);
  }

  @Override
  public void periodic(Channel session) {
    InternalUtilities.println("Default periodic() method is being run (every " + periodicTime + " " + timeUnit.toString() + ").");
  }

  @Override
  public void disconnected(Channel session) {
    // Do nothing by default.
  }

  @Override
  public boolean isConnected() {
    return sessions.isEmpty();
  }

  @Override
  public boolean isSimpleMessageReceiver() {
    return simple;
  }

  @Override
  public void send(String message) {
    if (!message.endsWith("\r\n"))
      message += "\r\n";
    sessions.write(message);
  }

  @Override
  public void send(String message, Channel session) {
    if (!sessions.contains(session))
      throw new IllegalArgumentException("Not connected to specified session.");
    if (!message.endsWith("\r\n"))
      message += "\r\n";
    session.write(message);
  }

  @Override
  public void send(String[] message) {
    send(join(" ", message));
  }

  @Override
  public void send(String[] message, Channel session) {
    send(join(" ", message), session);
  }

  @Override
  public void receive(String message, Channel session) {
    receive(message.split(" "), session);
  }

  @Override
  public void receive(String[] message, Channel session) {
    receive(new Message(message, this, session));
  }

  @Override
  public void receive(Message message) {
    receive(message.toString(), message.session());
  }

  /**
   * Gets the username of the bot.
   *
   * @return the bot's username
   */
  protected String username() {
    return username;
  }

  /**
   * Sets the bot's username and sends re-registration commands.
   *
   * @param username the desired new username
   */
  protected void setUsername(String username) {
    this.username = username;
    send("NICK :" + username + "\r\n");
    send("USER " + username + " 0 * :" + username + "\r\n");
  }

  // Common IRC Operations

  /**
   * Instructs the bot to join the specified channel.
   *
   * @param channel the channel to join
   */
  public void join(String channel) {
    send("JOIN " + channel + "\r\n");
  }

  /**
   * Instructs the bot to join the specified channel.
   *
   * @param channel the channel to join
   * @param session the session to join on
   */
  public void join(String channel, Channel session) {
    send("JOIN " + channel + "\r\n", session);
  }

  /**
   * Instructs the bot to part the specified channel.
   *
   * @param channel the channel to part
   */
  public void part(String channel) {
    send("PART " + channel + "\r\n");
  }

  /**
   * Instructs the bot to part the specified channel.
   *
   * @param channel the channel to part
   * @param session the session to part on
   */
  public void part(String channel, Channel session) {
    send("PART " + channel + "\r\n", session);
  }

  /**
   * Instructs the bot to part the specified channel with a reason.
   *
   * @param channel the channel to part
   * @param reason  the reason for parting
   */
  public void part(String channel, String reason) {
    send("PART " + channel + " :" + reason + "\r\n");
  }

  /**
   * Instructs the bot to part the specified channel with a reason.
   *
   * @param channel the channel to part
   * @param reason  the reason for parting
   * @param session the session to part on
   */
  public void part(String channel, String reason, Channel session) {
    send("PART " + channel + " :" + reason + "\r\n", session);
  }

  /**
   * Instructs the bot to quit.
   */
  public void quit() {
    send("QUIT\r\n");
  }

  /**
   * Instructs the bot to quit.
   *
   * @param session the session to quit from
   */
  public void quit(Channel session) {
    send("QUIT\r\n", session);
  }

  /**
   * Instructs the bot to quit with a reason.
   *
   * @param reason the reason for quitting
   */
  public void quit(String reason) {
    send("QUIT :" + reason + "\r\n");
  }

  /**
   * Instructs the bot to quit with a reason.
   *
   * @param reason  the reason for quitting
   * @param session the session to quit from
   */
  public void quit(String reason, Channel session) {
    send("QUIT :" + reason + "\r\n", session);
  }

  /**
   * Instructs the bot to send a message to the specified channel.
   *
   * @param message the message to send
   * @param channel the channel to send to
   */
  public void say(String message, String channel) {
    send("PRIVMSG " + channel + " :" + message + "\r\n");
  }

  /**
   * Instructs the bot to send a message to the specified channel.
   *
   * @param message the message to send
   * @param channel the channel to send to
   * @param session the session to send on
   */
  public void say(String message, String channel, Channel session) {
    send("PRIVMSG " + channel + " :" + message + "\r\n", session);
  }

  /**
   * Instructs the bot to send a message in /me form to the specified channel.
   *
   * @param message the message to send
   * @param channel the channel to send to
   */
  public void sayMe(String message, String channel) {
    send("PRIVMSG " + channel + " :\u0001ACTION " + message + "\r\n");
  }

  /**
   * Instructs the bot to send a message in /me form to the specified channel.
   *
   * @param message the message to send
   * @param channel the channel to send to
   * @param session the channel to send on
   */
  public void sayMe(String message, String channel, Channel session) {
    send("PRIVMSG " + channel + " :\u0001ACTION " + message + "\r\n", session);
  }

  // Static Bot utilities

  /**
   * Finds a string within another string ignoring case.
   *
   * @param needle   the string to find
   * @param haystack the string to search in
   * @return whether or not the string was found
   */
  public static boolean containsIgnoreCase(String needle, String haystack) {
    if (needle == null || haystack == null)
      return false;
    return haystack.matches("(?i)(.*)" + needle + "(.*)");
  }

  /**
   * Joins a string from an array.
   *
   * @param joinString the string to use for joining
   * @param message    the array to use
   * @return the joined string
   */
  public static String join(String joinString, String[] message) {
    return joinFromIndex(joinString, 0, message);
  }

  /**
   * Joins a string in an array starting at the specified index.
   *
   * @param joinString the string to use for joining
   * @param index      the index to start at
   * @param message    the array to use
   * @return the string joined from the specified index
   */
  public static String joinFromIndex(String joinString, int index, String[] message) {
    try {
      StringBuilder sb = new StringBuilder();
      for (int i = index; i < message.length; i++) {
        sb.append(message[i]).append(joinString);
      }
      return sb.substring(0, sb.lastIndexOf(joinString));
    } catch (NullPointerException e) {
      return null;
    }
  }
}
TOP

Related Classes of us.aaronweiss.juicebot.Bot

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.