Skip to content

Commit

Permalink
Update to Akka 2.3.6, remove custom IRC/TCP stuff, now use Apache Camel.
Browse files Browse the repository at this point in the history
  • Loading branch information
pauldoo committed Oct 1, 2014
1 parent fc2582e commit 6ea3acc
Show file tree
Hide file tree
Showing 15 changed files with 79 additions and 280 deletions.
1 change: 1 addition & 0 deletions spraffbot/.gitignore
Expand Up @@ -42,3 +42,4 @@ build.log

/.cache
/big.txt
/lib_managed
10 changes: 8 additions & 2 deletions spraffbot/README
Expand Up @@ -7,13 +7,19 @@ $ sbt compile

$ sbt test

# Build a jar file inside target/, and copy all runtime deps to target/dependency/
# Build a jar file inside target/, and copy all runtime deps to lib_managed
$ sbt package

# Run with:
$ sbt 'runMain akka.Main com.pauldoo.spraffbot.SpraffBot
$ java -cp target/scala-2.10/spraffbot_2.10-1.0.jar:`find lib_managed -name '*.jar' | tr '\n' ':'` akka.Main com.pauldoo.spraffbot.SpraffBot


TODO:
* Fix SSL. Upgrade to Akka 2.3.x, and use apache camel for IRC protocol implementation?


Channel message:
CamelMessage(hello, Map(irc.user.servername -> pauldoo, irc.target -> #sprafftest, irc.messageType -> PRIVMSG, MessageExchangeId -> ID-jam-lan-57548-1412192617284-0-8, irc.user.username -> ~pauldoo, irc.user.host -> 44.222.200.146.dyn.plus.net, breadcrumbId -> ID-jam-lan-57548-1412192617284-0-7, irc.user.nick -> pauldoo))

Private message:
CamelMessage(hello, Map(irc.user.servername -> pauldoo, irc.target -> spraffbot, irc.messageType -> PRIVMSG, MessageExchangeId -> ID-jam-lan-57548-1412192617284-0-10, irc.user.username -> ~pauldoo, irc.user.host -> 44.222.200.146.dyn.plus.net, breadcrumbId -> ID-jam-lan-57548-1412192617284-0-9, irc.user.nick -> pauldoo))
23 changes: 21 additions & 2 deletions spraffbot/build.sbt
Expand Up @@ -4,9 +4,28 @@ version := "1.0"

scalaVersion := "2.10.4"

libraryDependencies += "com.typesafe.akka" %% "akka-actor" % "2.2.4"
retrieveManaged := true

libraryDependencies += "com.typesafe.akka" %% "akka-testkit" % "2.2.4"
// Normal dependencies

// Logging
libraryDependencies += "ch.qos.logback" % "logback-classic" % "1.0.13"

// Akka

libraryDependencies += "com.typesafe.akka" %% "akka-actor" % "2.3.6"

libraryDependencies += "com.typesafe.akka" %% "akka-camel" % "2.3.6"

// Apache Camel IRC component
// Version of camel-irc matches the version of Apache Camel used by akka-camel above
// http://mavenbrowse.pauldoo.com/central/com/typesafe/akka/akka-camel_2.10/2.3.6/
libraryDependencies += "org.apache.camel" % "camel-irc" % "2.10.3"


// Test dependencies

libraryDependencies += "com.typesafe.akka" %% "akka-testkit" % "2.3.6" % "test"

libraryDependencies += "org.scalatest" %% "scalatest" % "2.2.1" % "test"

Expand Down
3 changes: 3 additions & 0 deletions spraffbot/src/main/resources/application.conf
@@ -0,0 +1,3 @@
akka {
loggers = ["akka.event.slf4j.Slf4jLogger"]
}
Expand Up @@ -7,7 +7,6 @@ import com.pauldoo.spraffbot.irc.IrcUtterance
import akka.actor.ActorRef
import spraffer.Spraffer
import java.io.File
import com.pauldoo.spraffbot.irc.IrcProtocolMessage
import com.pauldoo.spraffbot.irc.SayMessage
import java.net.InetSocketAddress
import com.pauldoo.spraffbot.toys.Cheer
Expand All @@ -17,7 +16,7 @@ object SpraffBot {
val username: String = "spraffbot";
val randomResponseRate = 1.0 / 100;
val ircServer = new InetSocketAddress("chat.freenode.net", 6697);
val ircChannel = "#sprafftest";
val ircChannels = List("#sprafftest", "#sprafftest2");
}

// TODO: Add handler for '\o/' messages
Expand All @@ -35,7 +34,7 @@ class SpraffBot extends Actor with ActorLogging {
}
case k: SayMessage => {
log.info(k.toString);
connection ! new IrcProtocolMessage(None, "PRIVMSG", List(k.to.target, k.message));
connection ! k
}
}
}

This file was deleted.

106 changes: 40 additions & 66 deletions spraffbot/src/main/scala/com/pauldoo/spraffbot/irc/IrcConnection.scala
Expand Up @@ -8,96 +8,70 @@ import akka.actor.Props
import akka.actor.actorRef2Scala
import akka.io.IO
import akka.io.Tcp
import akka.io.TcpPipelineHandler
import akka.io.TcpPipelineHandler.Init
import akka.io.TcpPipelineHandler.WithinActorContext
import akka.io.TcpReadWriteAdapter
import akka.actor.ActorRef
import com.pauldoo.spraffbot.SpraffBot
import scala.concurrent.Future
import javax.net.ssl.SSLEngine
import javax.net.ssl.SSLContext
import akka.io.SslTlsSupport
import akka.io.BackpressureBuffer
import akka.camel.{ CamelMessage, Consumer }
import akka.camel.Oneway
import akka.camel.Producer

object IrcConnection {
def props(app: ActorRef): Props =
Props(classOf[IrcConnection], SpraffBot.ircServer, app);
}

class IrcConnection(remote: InetSocketAddress, app: ActorRef) extends Actor with ActorLogging {
import context._
object IrcConsumer {
def props(endpointUri: String, app: ActorRef): Props =
Props(classOf[IrcConsumer], endpointUri, app)
}

private val handlers: List[ActorRef] =
List(
context.actorOf(Ping.props, "ping"),
context.actorOf(Privmsg.props(app), "privmsg"));
object IrcProducer {
def props(endpointUri: String): Props =
Props(classOf[IrcProducer], endpointUri)
}

{
IO(Tcp) ! Tcp.Connect(remote);
}
class IrcConsumer(val endpointUri: String, val app: ActorRef) extends Actor with ActorLogging with Consumer {

def receive = unconnectedReceive;
def receive: Receive = {
case msg: CamelMessage => {
val messageType = msg.headerAs[String]("irc.messageType").get
if (messageType == "PRIVMSG") {
val message: String = msg.bodyAs[String]
val target: String = msg.headerAs[String]("irc.target").get
val source: String = msg.headerAs[String]("irc.user.nick").get

private val sslEngine: SSLEngine = {
val engine = SSLContext.getDefault.createSSLEngine()
engine.setUseClientMode(true)
log.info(s"Supported SSL protocols: ${engine.getSupportedProtocols().toList}")
log.info(s"Enabled SSL protocols: ${engine.getEnabledProtocols().toList}")
engine
app ! IrcUtterance(IrcUser(source), IrcDestination(target), message)
}
}
}
}

def unconnectedReceive: Receive = {
case Tcp.Connected(remote, local) => {
log.info("Connected!");
val connection = sender;
class IrcProducer(val endpointUri: String) extends Producer with Oneway {
}

val init = TcpPipelineHandler.withLogger(log,
new IrcMessageStage() >>
new BreakIntoLinesStage() >>
new TcpReadWriteAdapter() >>
new SslTlsSupport(sslEngine) >>
new BackpressureBuffer(lowBytes = 1000000, highBytes = 2000000, maxBytes = 4000000) // Don't think this helps
);
class IrcConnection(remote: InetSocketAddress, app: ActorRef) extends Actor with ActorLogging {
import context._

val pipeline = context.actorOf(TcpPipelineHandler.props(
init, connection, self).withDeploy(Deploy.local))
val endpointUri: String = {
import SpraffBot._
import SpraffBot.ircServer.{ getHostName, getPort }
s"ircs:${username}@${getHostName}:${getPort}/${ircChannels.reduce(_ + "," + _)}"
}
log.info(s"Endpoint: ${endpointUri}")

connection ! Tcp.Register(pipeline);
private val consumer: ActorRef =
context.actorOf(IrcConsumer.props(endpointUri, app), "inbound")

val send = sendMessage(pipeline, init)_;
context become connectedReceive(init, send);
private val producer: ActorRef =
context.actorOf(IrcProducer.props(endpointUri), "outbound")

// TODO: Why does this step need to be delayed?
Future {
Thread.sleep(2000);
self ! IrcProtocolMessage(None, "NICK", List(SpraffBot.username));
self ! IrcProtocolMessage(None, "USER", List(SpraffBot.username, "0", "*", "Sir Spraff"));
self ! IrcProtocolMessage(None, "JOIN", List(SpraffBot.ircChannel));
}
def receive: Receive = {
case msg: SayMessage => {
producer ! CamelMessage(msg.message, Map("irc.target" -> msg.to.target))
}
}

def sendMessage(pipeline: ActorRef, init: Init[WithinActorContext, IrcProtocolMessage, IrcProtocolMessage])(message: IrcProtocolMessage): Unit = {
log.info(s"> ${message}")
pipeline ! init.Command(message)
}

def connectedReceive( //
init: Init[WithinActorContext, IrcProtocolMessage, IrcProtocolMessage], //
send: IrcProtocolMessage => Unit): Receive = {
case init.Event(data) => {
log.info(s"< ${data}")
// TODO: replace with a pub-sub thing.
for (h <- handlers) h ! data
}
case _: Tcp.ConnectionClosed => {
log.info("Connection closed")
context stop self
}
case message: IrcProtocolMessage => {
send(message)
}
}
}

This file was deleted.

This file was deleted.

This file was deleted.

Expand Up @@ -6,7 +6,9 @@ case class IrcUtterance(
val to: IrcDestination,
val message: String) {

def replyDestination: IrcDestination = to.target.startsWith("#") match {
def isSentToChannel: Boolean = to.target.startsWith("#")

def replyDestination: IrcDestination = isSentToChannel match {
case true => to
case false => IrcDestination(from.user)
}
Expand Down
26 changes: 0 additions & 26 deletions spraffbot/src/main/scala/com/pauldoo/spraffbot/irc/Ping.scala

This file was deleted.

0 comments on commit 6ea3acc

Please sign in to comment.