Created
February 13, 2012 23:36
-
-
Save thowitt/1821480 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package io.alien.scalabot | |
| import org.jivesoftware.smackx.muc.MultiUserChat | |
| import org.jivesoftware.smack.packet.{Packet, Message} | |
| import actors.Actor | |
| import tools.nsc.InterpreterLoop | |
| import java.io._ | |
| import org.jivesoftware.smack.{PacketListener, XMPPConnection} | |
| import scala.tools.nsc.Settings | |
| import tools.nsc.util.ScalaClassLoader | |
| // Use responsibly -- don't connect this to public chat servers! | |
| case class ReplBot(nick: String, pw: String, service: String, room: String = "", prefix: String = ">") | |
| extends Actor with PacketListener { | |
| override def start() = { | |
| super.start() | |
| try { | |
| log("Connecting to %s...".format(service)) | |
| conn = new XMPPConnection(service) | |
| conn.connect() | |
| room.isEmpty match { | |
| case true => | |
| log("Room not specified, so not joining.") | |
| case false => | |
| log("Entering room %s...".format(room)) | |
| chat = new MultiUserChat(conn, room) | |
| chat.addMessageListener(this) | |
| log("Joining with nick %s...".format(nick)) | |
| chat.join(nick, pw) | |
| } | |
| new ReplThread().start() | |
| } catch { | |
| case e: Throwable => | |
| log("Failed to start: %s".format(e.getMessage)) | |
| quit() | |
| } | |
| log("""Chatting.""".format(nick)) | |
| log("""You can send these commands to the ReplBot Actor:""") | |
| log(""" ! "quit" Disconnect and quit""") | |
| log(""" ! "status" Print current status""") | |
| log(""" ! "debug [on|off]" Print realtime activity""") | |
| this | |
| } | |
| def act() { | |
| loop { | |
| react { | |
| case Command(cmd) => handleCommand(cmd) | |
| case Result(rslt) => handleResult(rslt) | |
| case "quit" => quit() | |
| case "status" => logStatus() | |
| case Debug(onoff) => onoff match { | |
| case "on" => debugging = true; log("Debugging turned on") | |
| case "off" => debugging = false; log("Debugging turned off") | |
| case wtf => log("""Unexpected regex match in Debug: %s""".format(wtf)) | |
| } | |
| case wtf => debug("Discarding unknown message %s".format(wtf)) | |
| } | |
| } | |
| } | |
| def processPacket(packet: Packet) = packet match { | |
| case message: Message if message.getBody.startsWith(prefix) => this ! Command(message.getBody.substring(prefix.length)) | |
| case _ => | |
| } | |
| private def handleCommand(cmd: String) { | |
| debug("Processing command: %s".format(cmd)) | |
| commandWriter.write(cmd.toArray) | |
| commandCount = commandCount + 1 | |
| } | |
| private def handleResult(rslt: String) { | |
| debug("Sending result: %s".format(rslt)) | |
| if (!room.isEmpty) chat.sendMessage(rslt) | |
| resultCount = resultCount + 1 | |
| } | |
| protected def quit() = { | |
| log("Bye bye.") | |
| conn.disconnect() | |
| exit() | |
| } | |
| protected def logStatus() = { | |
| log(""" | |
| | Status | |
| | ------ | |
| | Connected: %s | |
| | Authenticated: %s | |
| | Command Messages Processed: %s | |
| | Result Messages Sent: %s | |
| | Debugging: %s | |
| |""".stripMargin.format(conn.isConnected, conn.isAuthenticated, commandCount, resultCount, debugging)) | |
| } | |
| private class ReplThread extends Thread { | |
| override def run() { | |
| val loop = new InterpreterLoop(commandReader, resultWriter) | |
| new ResultThread().start() | |
| val settings = new Settings(s => log(s)) | |
| settings.classpath.value = classpath.distinct.mkString(java.io.File.pathSeparator) | |
| loop.main(settings) | |
| ReplBot.this ! "quit" | |
| def classpath = urls map {_.toString} | |
| def urls = Thread.currentThread.getContextClassLoader match { | |
| case cl: java.net.URLClassLoader => cl.getURLs.toList | |
| case cl: ScalaClassLoader => cl.get | |
| case cl => error("Unsupported ClassLoader %s".format(cl)) | |
| } | |
| } | |
| private class ResultThread extends Thread { | |
| override def run() { | |
| while (true) try { | |
| ReplBot.this ! Result(resultReader.readLine()) | |
| } catch { case _ => } | |
| } | |
| } | |
| } | |
| override def toString = "ReplBot[%s]".format(nick) | |
| protected def log(s: String) = println("%s %s".format(this, s)) | |
| protected def debug(s: String) = debugging match { case true => log(s) case false => } | |
| protected case class Command(string: String) | |
| protected case class Result(string: String) | |
| private val cos = new PipedOutputStream() | |
| private val cis = new PipedInputStream(cos) | |
| private val ros = new PipedOutputStream() | |
| private val ris = new PipedInputStream(ros) | |
| private val commandWriter = new PrintWriter(cos) | |
| private val commandReader = new BufferedReader(new InputStreamReader(cis)) | |
| private val resultWriter = new PrintWriter(ros) | |
| private val resultReader = new BufferedReader(new InputStreamReader(ris)) | |
| private var conn: XMPPConnection = _ | |
| private var chat: MultiUserChat = _ | |
| private var commandCount = 0 | |
| private var resultCount = 0 | |
| private val Debug = "debug (on|off)".r | |
| private var debugging = true | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment