OpenSolaris IRC BotFrom SPCoast[edit] ICR Bot for OpenSolaris RegistrationsWe needed a quick hack to monitor the OpenSolaris annual meeting for member registrations - a task which in last years had been done by hand. Since I had no experience at all with IRC and/or 'bots, of course I volunteered to throw something together. I started with PircBot and LogBot from the Paul at jibble. The main change to LogBot was the addition of additional "commands" that it understood:
and, due to historical usage, the unweildy
The complete application source is in two files (LogBot.java and LogBotMain.java; you also need the pircbot jar and a config file file to make it all work. Here's the details: In LogBotMain.java:
public class LogBotMain {
public static void main(String[] args) throws Exception {
....
LogBot bot = new LogBot(nick, outDir, joinMessage);
bot.readMembers(); // ADD THIS LINE
bot.connect(server);
bot.joinChannel(channel);
The rest of the changes are in LogBot.java:
public void onMessage(String channel, String sender, String login, String hostname, String message) {
append(BLACK, "<" + sender + "> " + message);
botCommand(channel, sender, message);
}
private void botCommand(String channel, String sender, String message) {
message = message.toLowerCase();
if (message.startsWith(getNick().toLowerCase()) ) { // To Me!
if (message.indexOf("help") > 0) {
usage(sender);
} else if (message.indexOf("register") > 0) {
registerMember(channel, sender, message);
} else if (message.indexOf("quorum") > 0) {
quorum(channel);
}
} else if (message.startsWith("hello")) {
registerMember(channel, sender, message);
}
}
Of course, it needed to be robust in the face of failure, and log the registrations to a file that could be replayed, etc, giving rise to
public void logMember(String action, String sender, String login, String fullname) {
try {
Date now = new Date();
String date = DATE_FORMAT.format(now);
String time = TIME_FORMAT.format(now);
File file = new File(outDir, "membership.list");
BufferedWriter writer = new BufferedWriter(new FileWriter(file, true));
String entry = action + ":" + sender + ":" + login + ":" + fullname;
writer.write(entry);
writer.newLine();
writer.flush();
writer.close();
}
catch (IOException e) {
System.out.println("Could not write to membership list: " + e);
}
}
private void readMemberLog() {
try {
File file = new File(outDir, "membership.list");
BufferedReader reader = new BufferedReader(new FileReader(file));
String str;
while ((str = reader.readLine()) != null) {
// System.out.println(str);
String[] group = str.split(":");
String action = group[0];
String sender = group[1];
String login = group[2];
String fullname = group[3];
if (action.contentEquals("NEW")) {
nick2login.put(sender, login);
login2nick.put(login, sender);
login2full.put(login, fullname);
} else if (action.contentEquals("DELETE")) {
if (login2full.containsKey(login)) {
login2full.remove(login); // remove old mapping
}
nick2login.remove(sender);
login2nick.remove(login);
} else if (action.contentEquals("UPDATE")) {
nick2login.put(sender, login);
login2nick.put(login, sender);
login2full.put(login, fullname);
} else if (action.contentEquals("DUPLICATE")) {
// ignore
} else if (action.contentEquals("INVALID")) {
// ignore
}
}
reader.close();
} catch (IOException e) {
System.out.println("Could not read membership list: " + e);
}
}
private void readMemberList() {
try {
File file = new File(outDir, "Official.membership.list");
BufferedReader reader = new BufferedReader(new FileReader(file));
String str;
while ((str = reader.readLine()) != null) {
// System.out.println(str);
String[] group = str.split(":");
String login = group[0];
String fullname = group[1];
official.put(login, fullname);
}
reader.close();
} catch (IOException e) {
System.out.println("Could not read official membership list: " + e);
}
}
and a public routine (to be called by main()) to initialize things:
public void readMembers() {
readMemberLog();
readMemberList();
System.out.println("Read in registered members: " + login2full.size() + ", quorum needed is " + QUORUM);
System.out.println("Read in official members: " + official.size() + ", quorum calculated is " + official.size() / 3);
// QUORUM = official.size() / 3;
}
The final step was to actually use regexp's to parse the messages and extract the OpenSolaris registration info, compare it to the official list, and allow for users to update things:
public void registerMember(String channel, String sender, String line) {
boolean ok = false;
line = Colors.removeFormattingAndColors(line);
String login = "";
String fullname = "";
Pattern p1 = Pattern.compile("^"+ getNick().toLowerCase() +" register ([^ ]*) as (.*)");
Matcher m1 = p1.matcher(line);
if (m1.matches()) {
login = m1.group(1);
fullname = m1.group(2);
ok = true;
}
Pattern p2 = Pattern.compile("^hello,\\s+i\\s+am\\s+(.*)\\s+and\\s+an\\s+opensolaris\\s+core\\s+contributor.\\s+my\\s+opensolaris\\s+id\\s+is\\s+([^.]*)\\.?");
Matcher m2 = p2.matcher(line);
// System.out.println("Checking pattern \""+p2.toString()+"\" against \""+line+"\"");
if (m2.matches()) {
login = m2.group(2);
fullname = m2.group(1);
ok = true; }
if (ok) {
if (official.containsKey(login) ) {
if (nick2login.containsKey(sender)) { // I've already registered under this nick...
String existingLogin = (String) nick2login.get(sender);
String existingFull = "unknown";
if (login2full.containsKey(existingLogin)) {
existingFull = (String) login2full.get(existingLogin);
login2full.remove(existingLogin); // remove old mapping
logMember("DELETE", sender, existingLogin, existingFull);
}
nick2login.put(sender, login);
login2nick.put(login, sender);
login2full.put(login, fullname); logMember("UPDATE", sender, login, fullname);
append(RED, "Updating registration: "+sender+" is changing " + existingLogin + "/" + existingFull + " to " + login + "/" + fullname);
sendMessage(channel, "Updating registration: "+sender+" is changing " +
existingLogin + "/" + existingFull + " to " + login + "/" + fullname);
} else if (login2nick.containsKey(login)) { // someone else trying to register the same login?
String earlybird = (String) login2nick.get(login);
append(RED, "Hmmm, "+sender+", you are trying to register the same OpenSolaris ID ("+ login+") as "+ earlybird +" did earlier. I'm going to ignore the duplicate registration.");
sendMessage(channel, "Hmmm, "+sender+", you are trying to register the same OpenSolaris ID ("+ login+") as "+ earlybird +" did earlier. I'm going to ignore the duplicate registration.");
logMember("DUPLICATE", sender, login, fullname);
} else {
nick2login.put(sender, login);
login2nick.put(login, sender);
login2full.put(login, fullname);
logMember("NEW", sender, login, fullname);
append(RED, "Thank you for registering, "+sender+": " + login + "/" + fullname);
sendMessage(channel, "Thank you for registering, "+sender+": " + login + "/" + fullname);
}
quorum(channel);
} else {
logMember("INVALID", sender, login, fullname);
append(RED, "Sorry "+sender+", the OpenSolaris ID you used ("+login+") is not in the list of valid Core Contributors for this election.");
sendMessage(channel, "Sorry "+sender+", the OpenSolaris ID you used ("+login+") is not in the list of valid Core Contributors for this election.");
}
} else {
append(RED, "Sorry "+sender+", I did not understand \""+line+"\".");
sendMessage(channel, "Sorry "+sender+", I did not understand \""+line+"\".");
usage(sender);
}
}
|

