Results 1 to 3 of 3
  1. #1
    kwgivler is offline Member
    Join Date
    Mar 2011
    Posts
    18
    Rep Power
    0

    Default My IRC Bot: Request for criticism

    First of all, hello, this is my first post here :D

    I am in the process of writing an IRC Bot framework, along with an extensible plugin based IRC Bot based on this framework. I would say my Java knowledge is lower intermediate. Everything seems to be working, however I would like constructive criticism regarding the way I am doing things. If anything is hackish, or there is a better/more standard way of doing things I would love suggestions. I am not asking anyone to write any code for me at all, just to let me know what could be done better, and maybe a link to a guide that explains how to do so. Currently I would like comments on the classes in the com.kgivler.KGDBotFramework package, as I know some things in the other packages (Such as the plugin framework) could be done a lot more robustly, however, I'd like to improve the framework first.

    to make things easier to read, I'll reply to this message with the source code from the other files.

    The full source code is at: http://kgivler.com/java/files/KGDBot.tar.gz

    Java Code:
    package com.kgivler.KGDBotFramework;
    
    import java.io.InputStream;
    import java.io.IOException;
    import java.io.OutputStream;
    import java.io.PrintWriter;
    import java.net.InetAddress;
    import java.net.Socket;
    import java.net.UnknownHostException;
    import java.util.Scanner;
    import java.util.logging.Logger;
    import com.kgivler.KGDBotFramework.Message;
    
    /**
     * Provides low-level functionality to IRC Bots
     * @author kwgivler
     *
     */
    public class BotCore implements IMessageReceiver {
    	private String server; // IRC Server address
    	private int port; // port on which to connect
    
    	private Socket socket;
    	private Scanner in; // Scanner for reading lines from the server
    	private PrintWriter out; // PrintWriter for sending lines to the server
    	private IMessageReceiver receiver;
    	private ListenThread listenThread; // Thread which listens for server output
    	private boolean connected = false; // are we connected?
    	private Logger logger; // Used for logging
    
    	/**
    	 * KGDBot constructor
    	 * @param server IRC Server Address
    	 * @param port IRC Port
    	 * @param nick nickname for the bot
    	 * @param realName the realname of the bot
    	 * @param bot the bot we are providing services for
    	 */
    	public BotCore(String server, int port, IMessageReceiver receiver)
    	{
    		logger = Logger.getLogger("KGDBotFramework");
    		this.port = port;
    		this.server = server;
    		this.receiver = receiver;
    	}
    
    	// --------------------------------------------------------------------------------------------------
    
    	/**
    	 * Connect to IRC server
    	 */
    	public void connect(String nick, String realName)
    	{
    		try {
    			socket = new Socket(server, port);
    			InputStream instream = socket.getInputStream();
    			OutputStream outstream = socket.getOutputStream();
    			in = new Scanner(instream);
    			out = new PrintWriter(outstream);
    		} catch (IOException e) {
    			logger.warning("Unable to connect: " + server + ":" + port);
    			e.printStackTrace();
    			System.exit(0);
    		}
    
    		// Set up thread which listens for server output
    		listenThread = new ListenThread(this, in);
    		Thread serverListener = new Thread(listenThread);
    		serverListener.start();
    
    		String hostName="localhost";
    		try {
    			InetAddress addr = InetAddress.getLocalHost();
    			hostName = addr.getHostName();
    			logger.info("hostname: " + hostName);
    		} catch (UnknownHostException e) {
    			e.printStackTrace();
    			System.exit(0);
    		}
    
    		// Register Connection
    		sendRawMessage("NICK " + nick + "\r\n");
    		sendRawMessage("USER " + nick + " " + hostName + " " + server + " :" + realName + "\r\n");
    
    		while(!connected)
    		{
    			System.out.println("Connecting...");
    			try {
    				Thread.sleep(1000);
    			}
    			catch (InterruptedException e) {
    				e.printStackTrace();
    				System.exit(0);
    			}
    		}
    	}
    
    	// --------------------------------------------------------------------------------------------------
    
    	/**
    	 * Disconnect from server
    	 */
    	public void disconnect()
    	{
    		if(!connected)
    			logger.info("Not Connected");
    
    		sendRawMessage("QUIT\r\n");
    		try
    		{
    			socket.close();
    			out.close();
    			in.close();
    		} catch (IOException e)
    		{
    			logger.warning("Exception while disconnecting:");
    			e.printStackTrace();
    			System.exit(0);
    		}
    
    		connected = false;
    	}
    
    	// --------------------------------------------------------------------------------------------------
    
    	/**
    	 * Send string directly to server
    	 * @param command String to send IRC server
    	 */
    	public void sendRawMessage(String command)
    	{	
    		logger.info("SENDING: " + command);
    		out.print(command);
    		out.flush();
    	}
    
    
    	// --------------------------------------------------------------------------------------------------
    
    	/**
    	 * Check if bot is connected
    	 * @return true if connected to server, false if not connected
    	 */
    	public boolean isConnected()
    	{
    		return connected;
    	}
    
    	/**
    	 * Receive parsed messages
    	 */
    	@Override
    	public void receiveMessage(Message message) {
    		String command = message.getCommand();
    
    		if(!connected)
    		{
    			if(command.equals("433"))
    			{
    				System.out.println("Nick in use!");
    				disconnect();
    				System.exit(0);
    			}
    
    			if(command.equals("004"))
    			{
    				System.out.println("Connected!");
    				connected = true;
    			}
    		} else
    			receiver.receiveMessage(message);
    	}
    }

  2. #2
    kwgivler is offline Member
    Join Date
    Mar 2011
    Posts
    18
    Rep Power
    0

    Default

    Java Code:
    package com.kgivler.KGDBotFramework;
    
    public interface IMessageReceiver {
    	/**
    	 * Parsed messages are sent here
    	 * @param message the parsed message
    	 */
    	void receiveMessage(Message message);
    }
    Java Code:
    package com.kgivler.KGDBotFramework;
    
    import java.util.ArrayList;
    
    /**
     * IRC Bots must extend this class
     * 
     * @author kwgivler
     *
     */
    public abstract class IRCBot implements IMessageReceiver
    {
    	private BotCore core;
    	private String nick;
    	private String realName;
    	private ArrayList<String> channels = new ArrayList<String>(); // Channels the bot is currently in
    
    	/**
    	 * Construct IRCBot
    	 * @param server Server to connect to
    	 * @param port Port to connect on
    	 * @param nick bot's nick
    	 * @param realName bot's realname
    	 */
    	public IRCBot(String server, int port, String nick, String realName)
    	{
    		core = new BotCore(server, port, this);
    		this.nick = nick;
    		this.realName = realName;
    	}
    
    	// --------------------------------------------------------------------------------------------------
    
    	public IRCBot(String server, int port, String nick)
    	{
    		this(server, port, nick, "KGDBot");
    	}
    
    	// --------------------------------------------------------------------------------------------------
    
    	public IRCBot(String server, int port)
    	{
    		this(server, port, "KGDBot", "KGDBot");
    	}
    
    	// --------------------------------------------------------------------------------------------------
    
    	/**
    	 * Connect to server
    	 */
    	public void connect()
    	{
    		core.connect(nick, realName);
    	}
    
    	// --------------------------------------------------------------------------------------------------
    
    	/**
    	 * Disconnect from server
    	 */
    	public void disconnect()
    	{
    		core.disconnect();
    	}
    
    	// --------------------------------------------------------------------------------------------------
    
    	/**
    	 * Get the nick of the bot
    	 * @return The bot's nick
    	 */
    	public String getNick()
    	{
    		return nick;
    	}
    
    	// --------------------------------------------------------------------------------------------------
    
    	/**
    	 * Get the channels the bot is in
    	 * @return An ArrayList of the channels the bot is in
    	 */
    	public ArrayList<String> getChannels()
    	{
    		if(!isConnected())
    			throw new IllegalStateException("Not Connected");
    
    		ArrayList<String> myChannels = new ArrayList<String>();
    		for(int i = 0; i < channels.size(); i++)
    		{
    			myChannels.add(channels.get(i));
    		}
    		return myChannels;
    	}
    
    	// --------------------------------------------------------------------------------------------------
    
    	/**
    	 * Join a channel
    	 * @param channel channel to join
    	 * @throws IllegalStateException if not connected
    	 */
    	public void join(String channel)
    	{
    		if(!isConnected())
    			throw new IllegalStateException("Not Connected");
    
    		sendRawMessage("JOIN " + channel + "\r\n");
    		channels.add(channel);
    	}
    
    	// --------------------------------------------------------------------------------------------------
    
    	/**
    	 * Part a channel
    	 * @param channel channel to part
    	 */
    	public void part(String channel)
    	{
    		if(!isConnected())
    			throw new IllegalStateException("Not connected");
    
    		for (int i = 0; i < channels.size(); i++)
    		{
    			if(channels.get(i).equals(channel))
    			{
    				channels.remove(i);
    				sendRawMessage("PART " + channel + "\r\n");
    			}
    		}
    	}
    
    	// --------------------------------------------------------------------------------------------------
    
    	/**
    	 * Send message to channel (PRIVMSG command)
    	 * @param channel channel on which to send message
    	 * @param message message to send to channel
    	 * @throws IllegalStateException if not connected
    	 */
    	public void sendPrivMsg(String channel, String message)
    	{		
    		if(!isConnected())
    			throw new IllegalStateException("Not Connected");
    
    		sendRawMessage("PRIVMSG " + channel + " :" + message + "\r\n");
    	}
    
    
    	/**
    	 * Send a PRIVMSG, determining if we should send it to the channel
    	 * or to a nick based on the message type
    	 * @param who The message we will use to determine who to respond to
    	 * @param message The message to send
    	 */
    	public void sendPrivMsg(Message who, String message)
    	{
    		if(isPrivateMessage(who))
    		{
    			sendPrivMsg(who.getNick(), message);
    		}
    		else
    		{
    			sendPrivMsg(who.getChannel(), message);
    		}
    	}
    
    	// --------------------------------------------------------------------------------------------------
    
    	/**
    	 * Send message directly to irc server
    	 * @param command message to send to server
    	 */
    	public void sendRawMessage(String command)
    	{
    		core.sendRawMessage(command);
    	}
    
    	// --------------------------------------------------------------------------------------------------
    
    	/**
    	 * @return true is bot is connected, false if not connected
    	 */
    	public boolean isConnected()
    	{
    		return core.isConnected();
    	}
    
    	// --------------------------------------------------------------------------------------------------
    
    	/**
    	 * @return true if this is a message sent to the bot
    	 * ex: PRIVMSG botnick :message
    	 * otherwise returns false
    	 */
    	public boolean isPrivateMessage(Message message)
    	{
    		String[] params = message.getParameters();
    		if(params[0].equals(nick))
    		{
    			return true;
    		}
    		return false;
    	}
    
    	/**
    	 * When the bot receives a message it is sent to this method
    	 * @param message the message we just received
    	 */
    	public abstract void receiveMessage(Message message);
    
    }

  3. #3
    kwgivler is offline Member
    Join Date
    Mar 2011
    Posts
    18
    Rep Power
    0

    Default

    Java Code:
    import java.util.Scanner;
    import java.util.logging.Logger;
    
    public class ListenThread implements Runnable {
    	
    	private Scanner in; // Scanner from which we will get input
    	private BotCore core;
    	private Logger logger; // logging
    	
    	/**
    	 * Constructor
    	 * @param core bot core for which we are listening
    	 * @param in Scanner we are listening to
    	 */
    	public ListenThread(BotCore core, Scanner in)
    	{
    		logger = Logger.getLogger("KGDBotFramework");
    		this.core = core;
    		this.in = in;
    	}
    	
    	public void run()
    	{
    		while(true)
    		{
    			if( !in.hasNext() )
    				return;
    				
    			String input = in.nextLine();
    			logger.info("GOT: " + input);
    
    			if (input.startsWith("PING ") )
    				handlePing(input);
    			else
    			{
    				core.receiveMessage(MessageParser.parseMessage(input));
    			}
    		}
    	}
    	
    	
    	/**
    	 * Respond to PING
    	 * @param ping String containing the PING we were sent
    	 */
    	private void handlePing(String ping)
    	{	
    		if( ping.startsWith("PING") )
    		{
    			String command = "PONG " + ping.substring(5) + "\r\n";
    			core.sendRawMessage(command);
    		}
    	}
    	
    }
    Java Code:
    package com.kgivler.KGDBotFramework;
    
    /**
     * Message format for IRC bots
     * @author kwgivler
     *
     */
    public class Message {
    	private int type;
    	private String[] parameters;
    	private String message;
    	private String nick;
    	private String command;
    	
    	public static final int UNKNOWN = -1; // Message we do not know how to parse 
    	public static final int PRIVMSG = 1;  // Message is a PRIVMSG
    	public static final int NUMERIC = 2;  // Numeric command
    	
    	/**
    	 * Message Constructor
    	 * @param type The Message type
    	 * @param command The command portion of the message
    	 * @param nick The nick associated with this message
    	 * @param parameters The parameters to this message
    	 * @param message The Message
    	 */
    	public Message(int type, String command, String nick, String[] parameters, String message)
    	{
    		this.type = type;
    		this.parameters = parameters;
    		this.message = message;
    		this.nick = nick;
    		this.command = command;
    	}
    	
    	/**
    	 * Get the type of this message
    	 * @return The type of message
    	 */
    	public int getType()
    	{
    		return type;
    	}
    	
    	/**
    	 * Get the channel that is relevant to this message
    	 * @return the channel relevant to this message
    	 */
    	public String[] getParameters()
    	{
    		return parameters;
    	}
    	
    	/**
    	 * Get the message
    	 * @return the message
    	 */
    	public String getMessage()
    	{
    		return message;
    	}
    	
    	/**
    	 * Get the nick that caused this message to be created
    	 * @return the nick relevant to this message
    	 */
    	public String getNick()
    	{
    		return nick;
    	}
    	
    	/**
    	 * The command (Such as PRVIMSG)
    	 * @return command
    	 */
    	public String getCommand()
    	{
    		return command;
    	}
    	
    	/**
    	 * The channel this message was sent on
    	 * @return channel message was sent on
    	 */
    	public String getChannel()
    	{
    		return parameters[0];
    	}
    }
    Java Code:
    package com.kgivler.KGDBotFramework;
    
    import java.util.logging.Logger;
    import com.kgivler.KGDBotFramework.Message;
    
    public class MessageParser {
    	private static Logger logger = Logger.getLogger("KGDBotFramework");
    
    	/**
    	 * Constructor
    	 * @param bot The bot we are parsing messages for
    	 */
    	private MessageParser()
    	{
    	}
    
    	// --------------------------------------------------------------------------------------------------
    
    	/**
    	 * Attempt to parse raw message from server
    	 * @param message Message to parse
    	 */
    	public static Message parseMessage(String message)
    	{
    		/*
    		 * Originally Based on code from:
    		 * http://calebdelnay.com/blog/2010/11/parsing-the-irc-message-format-as-a-client
    		 */
    		String trailing = "";
    		String prefix = "";
    		String command = "";
    		String nick = "";
    		String[] parameters;
    		int prefixEnd = -1;
    		int trailingStart = message.indexOf(" :");
    
    		//logger.log(Level.INFO, "Message: " + message);
    
    		// Extract nick
    		if (message.indexOf("!") >= 0)
    		{
    			int nickEnd = message.indexOf("!");
    			nick = message.substring(1, nickEnd);
    		}
    
    		// Extract prefix (contains :Nick!user@host)
    		if (message.startsWith(":"))
    		{
    			prefixEnd = message.indexOf(" ");
    			prefix = message.substring(1, prefixEnd);
    		}
    
    		// Extract trailing (Last part of message, example: The text sent to a channel)
    		if (trailingStart >= 0)
    			trailing = message.substring(trailingStart + 2);
    		else
    			trailingStart = message.length();
    
    		// extract command and command parameters (example: command = PRIVMSG parameters = #channel)
    		String[] commandAndParameters = message.substring(prefixEnd + 1, trailingStart).split(" ");
    		command = commandAndParameters[0];
    		parameters = new String[commandAndParameters.length -1];
    
    		if (commandAndParameters.length > 1){
    			for(int i = 1; i < commandAndParameters.length; i++){
    				parameters[i-1] = commandAndParameters[i];
    			}
    		}
    
    		int type = getType(command, parameters);
    
    		// Debugging
    		// TODO StringBuilder
    		String debug = "Type: " + type;
    		debug += " Prefix: " + prefix;
    		debug += " Command: " + command;
    		for(int i = 0; i < parameters.length; i++)
    		{
    			debug += " Param[" + i + "]: " + parameters[i];
    		}
    		debug += " Trailing: " + trailing;
    		logger.info(debug);
    
    		return new Message(type, command, nick, parameters, trailing);
    	}
    
    	// --------------------------------------------------------------------------------------------------
    
    	/**
    	 * Determine the type of the message we are parsing
    	 * @return The message type
    	 */
    	private static int getType(String command, String[] parameters)
    	{
    		// Determine message type
    		int type = Message.UNKNOWN;
    		if(command.equals("PRIVMSG"))
    			type = Message.PRIVMSG;
    
    		try{
    			Integer.parseInt(command);
    			type = Message.NUMERIC;
    		} catch (NumberFormatException e)
    		{
    			// do nothing, command is not numeric
    		}
    		return type;
    	}
    
    	// --------------------------------------------------------------------------------------------------
    }

Similar Threads

  1. JSF Request value on Page2
    By mwildam in forum JavaServer Faces (JSF)
    Replies: 5
    Last Post: 09-17-2009, 10:12 AM
  2. Http request
    By arthik_babu in forum Advanced Java
    Replies: 2
    Last Post: 06-29-2009, 01:27 PM
  3. How can i know from which jsp request is coming?
    By vishnujava in forum Java Servlet
    Replies: 1
    Last Post: 08-06-2008, 02:13 PM
  4. First post as per request
    By happyknappy in forum Introductions
    Replies: 3
    Last Post: 07-30-2008, 02:33 AM
  5. Session and request in JSF
    By felixtfelix in forum Web Frameworks
    Replies: 0
    Last Post: 05-08-2008, 06:10 PM

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •