< Day Day Up > |
Hack 43 A Continuity Bot
What was everyone talking about just before you joined the middle of their conversation? Joining an IRC channel in the middle of a conversation can be a frustrating experience for all concerned, so wouldn't it be nice if there were someone there to tell you what people were talking about? Wouldn't you like to know if the awkward silence following your appearance was because everyone was busy insulting you before you joined? Now, with the miracle of the Continuity Bot Hack, you can ease seamlessly into the conversation and find out what your friends really think of you in the bargain. This hack takes the form of cont, a simple bot based on the PircBot framework. When someone joins the channel it sits on, the bot sends her the last 10 events that occurred there via private message. Many people set up their clients to join multiple channels on startup. As the history is sent via private message, you may want to modify the message format to include the channel name in this case.
For the sake of simplicity, this bot will keep track of only what is said in a channel. This requires only normal messages and actions to be monitored. 6.5.1 The CodeThe file Cont.java will contain the code that is used to keep an eye on what people are saying in the channel. The Cont class inherits from the PircBot class to make this rather straightforward. Save the following as Cont.java: import org.jibble.pircbot.*; import java.util.*; public class Cont extends PircBot { // Remember up to 10 things that happened in the channel. private ContextList contextList = new ContextList(10); private CurrentTime now = new CurrentTime( ); // Constructor used to set the name of the bot. public Cont( ) { this.setName("cont"); this.setLogin("cont"); } // Handle on-channel messages. public void onMessage(String channel, String sender, String login, String hostname, String message) { contextList.add(now + " <" + sender + "> " + message); } // Handle actions. public void onAction(String sender, String login, String hostname, String target, String action) { contextList.add(now + " * " + sender + " " + action); } // Handle people joining the channel. public void onJoin(String channel, String sender, String login, String hostname) { if (!sender.equals(getName( ))) { // Send out the history of messages to the new channel user. Iterator messageIt = contextList.iterator( ); while (messageIt.hasNext( )) { sendMessage(sender, messageIt.next( ).toString( )); } } } } As you may have noticed, the Cont class makes use of two classes that haven't been made yet! The first of these is ContextList , which has the responsibility of remembering the last 10 events seen by the bot. The second is CurrentTime, which performs the trivial task of creating a simple timestamp, similar to that used by most IRC clients. ContextList is what you might call a ring buffer. It is an ordered list, but its size is limited to 10 items in this case. If the list is full and a new item is added, the oldest item in the list is simply removed. The bot uses this class to store the last 10 (or fewer) events that occurred on-channel, ready to be sent to each user who joins the channel. Now create the file ContextList.java: import java.util.*; public class ContextList extends Vector { private int maxListSize; public ContextList(int maxListSize) { this.maxListSize = maxListSize; } public boolean add(Object o) { if (this.size( ) >= maxListSize) { // Remove the first item if the list is full. this.remove(0); } // Add the new item to the end of the list. return super.add(o); } } To give the user a greater feel of temporal location, it is useful to apply timestamps to the messages. It often helps if you can tell if a message was sent 30 seconds ago or 30 minutes ago. The quickest way of getting the current time is to call the toString() method on a new instance of the java.util.Date class. This method may return slightly different things depending on your locale, but it will look something like this: Sat Feb 14 14:45:13 GMT 2004 This is rather long for messages that appear in an IRC window, and most of it is unnecessary. Not many channels are idle for more than a year, and if they are, it's unlikely that you'll want to keep your bot running in there. The CurrentTime class will generate a timestamp like 14:45. Save this as CurrentTime.java: import java.io.*; import java.util.*; import java.text.*; public class CurrentTime { private SimpleDateFormat shortDateFormat = new SimpleDateFormat("H:mm"); private FieldPosition fp = new FieldPosition(0); public String toString( ) { Date now = new Date( ); StringBuffer output = new StringBuffer( ); try { shortDateFormat.format(now, output, fp); } catch (NullPointerException e) { // Date cannot be null. Ignore this. } return output.toString( ); } } All you need to do now is create a main method to run the bot from, and you're done. Save the following as ContMain.java : public class ContMain { public static void main(String[] args) throws Exception { Cont bot = new Cont( ); // Connect to a server and join a channel. bot.connect("irc.freenode.net"); bot.joinChannel("#irchacks"); } } 6.5.2 Running the HackCompile the classes with the javac command: C:\java\ContBot> javac -classpath .;pircbot.jar *.java Start the continuity bot by running the main method in the ContMain class: C:\java\ContBot> java -classpath .;pircbot.jar ContMain If all goes well, the bot should spring into life. When a user joins the channel, the bot will send private messages containing the last 10 lines of text sent to the channel, as shown in Figure 6-3. Figure 6-3. Receiving private messages from the botUsing a bot like this is a great way of making sure nobody feels lost when he enters the middle of a conversation. —Steve Jolly |
< Day Day Up > |