Skip to content

Commit

Permalink
Merge branch 'feature/extract_system_bots' into develop
Browse files Browse the repository at this point in the history
* feature/extract_system_bots:
  Moved HelpBot into core
  Moved CommandsRecognizerBot into core
  Moved SlackBotActor to core
  • Loading branch information
marioosh committed Jul 2, 2015
2 parents 897dd9f + 0308054 commit 34206d0
Show file tree
Hide file tree
Showing 5 changed files with 159 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package io.scalac.slack.bots.system

import io.scalac.slack.MessageEventBus
import io.scalac.slack.bots.IncomingMessageListener
import io.scalac.slack.common.{BaseMessage, BotInfoKeeper, Command}

class CommandsRecognizerBot(override val bus: MessageEventBus) extends IncomingMessageListener {

val commandChar = '$'

def receive: Receive = {

case bm@BaseMessage(text, channel, user, dateTime, edited) =>
//COMMAND links list with bot's nam jack can be called:
// jack link list
// jack: link list
// @jack link list
// @jack: link list
// $link list
def changeIntoCommand(pattern: String): Boolean = {
if (text.trim.startsWith(pattern)) {
val tokenized = text.trim.drop(pattern.length).trim.split("\\s")
publish(Command(tokenized.head, tokenized.tail.toList.filter(_.nonEmpty), bm))
true
}
false
}

//call by commad character
if (!changeIntoCommand(commandChar.toString))
BotInfoKeeper.current match {
case Some(bi) =>
//call by name
changeIntoCommand(bi.name + ":") ||
changeIntoCommand(bi.name) ||
//call by ID
changeIntoCommand(s"<@${bi.id}>:") ||
changeIntoCommand(s"<@${bi.id}>")

case None => //nothing to do!
}
}
}
20 changes: 20 additions & 0 deletions src/main/scala/io/scalac/slack/bots/system/HelpBot.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package io.scalac.slack.bots.system

import io.scalac.slack.MessageEventBus
import io.scalac.slack.bots.AbstractBot
import io.scalac.slack.common.{Command, HelpRequest, OutboundMessage}

/**
* Maintainer: Patryk
*/
class HelpBot(override val bus: MessageEventBus) extends AbstractBot {
override def act: Receive = {
case Command("help", options, raw) =>
publish(HelpRequest(options.headOption, raw.channel))
}

override def help(channel: String): OutboundMessage = OutboundMessage(channel,
s"*$name* is for helping. Duh \\n" +
s"`help` - display help from all bots \\n " +
s"`help {botName}` - display help for certain bot module")
}
7 changes: 7 additions & 0 deletions src/main/scala/io/scalac/slack/common/BotInfoKeeper.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package io.scalac.slack.common

import io.scalac.slack.api.BotInfo

object BotInfoKeeper {
var current: Option[BotInfo] = None
}
6 changes: 6 additions & 0 deletions src/main/scala/io/scalac/slack/common/Shutdownable.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package io.scalac.slack.common

trait Shutdownable {

def shutdown(): Unit
}
83 changes: 83 additions & 0 deletions src/main/scala/io/scalac/slack/common/actors/SlackBotActor.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package io.scalac.slack.common.actors

import java.util.concurrent.TimeUnit

import akka.actor.{Actor, ActorLogging, ActorRef, Props}
import akka.util.Timeout
import io.scalac.slack.api.{ApiActor, ApiTest, AuthData, AuthTest, BotInfo, Connected, RegisterModules, RtmData, RtmStart, RtmStartResponse, Start, Stop}
import io.scalac.slack.common.{BotInfoKeeper, RegisterDirectChannels, RegisterUsers, Shutdownable}
import io.scalac.slack.websockets.{WSActor, WebSocket}
import io.scalac.slack.{BotModules, Config, MessageEventBus, MigrationInProgress, OutgoingRichMessageProcessor, SlackError}

import scala.concurrent.duration._

class SlackBotActor(modules: BotModules, eventBus: MessageEventBus, master: Shutdownable, usersStorageOpt: Option[ActorRef] = None) extends Actor with ActorLogging {

import context.{dispatcher, system}

val api = context.actorOf(Props[ApiActor])
val richProcessor = context.actorOf(Props(classOf[OutgoingRichMessageProcessor], api, eventBus))
val websocketClient = system.actorOf(Props(classOf[WSActor], eventBus), "ws-actor")

var errors = 0

override def receive: Receive = {
case Start =>
//test connection
log.info("trying to connect to Slack's server...")
api ! ApiTest()
case Stop =>
master.shutdown()
case Connected =>
log.info("connected successfully...")
log.info("trying to auth")
api ! AuthTest(Config.apiKey)
case ad: AuthData =>
log.info("authenticated successfully")
log.info("request for websocket connection...")
api ! RtmStart(Config.apiKey)
case RtmData(url) =>
log.info("fetched WSS URL")
log.info(url)
log.info("trying to connect to websockets channel")
val dropProtocol = url.drop(6)
val host = dropProtocol.split('/')(0)
val resource = dropProtocol.drop(host.length)

implicit val timeout: Timeout = 5.seconds

log.info(s"Connecting to host [$host] and resource [$resource]")

websocketClient ! WebSocket.Connect(host, 443, resource, withSsl = true)

context.system.scheduler.scheduleOnce(Duration.create(5, TimeUnit.SECONDS), self, RegisterModules)

case bi@BotInfo(_, _) =>
BotInfoKeeper.current = Some(bi)
case RegisterModules =>
modules.registerModules(context, websocketClient)
case MigrationInProgress =>
log.warning("MIGRATION IN PROGRESS, next try for 10 seconds")
system.scheduler.scheduleOnce(10.seconds, self, Start)
case se: SlackError if errors < 10 =>
errors += 1
log.error(s"connection error [$errors], repeat for 10 seconds")
log.error(s"SlackError occured [${se.toString}]")
system.scheduler.scheduleOnce(10.seconds, self, Start)
case se: SlackError =>
log.error(s"SlackError occured [${se.toString}]")
master.shutdown()
case res: RtmStartResponse =>
if(usersStorageOpt.isDefined) {
val userStorage = usersStorageOpt.get

userStorage ! RegisterUsers(res.users: _*)
userStorage ! RegisterDirectChannels(res.ims: _*)
}

case WebSocket.Release =>
websocketClient ! WebSocket.Release

}

}

0 comments on commit 34206d0

Please sign in to comment.