Skip to content
This repository has been archived by the owner on Aug 18, 2020. It is now read-only.

Commit

Permalink
Merge branch 'hotfix/0.2.1-prealpha'
Browse files Browse the repository at this point in the history
  • Loading branch information
J0B10 committed Jul 14, 2019
2 parents a6bac81 + 71fc2c9 commit 8fdba80
Show file tree
Hide file tree
Showing 15 changed files with 196 additions and 31 deletions.
2 changes: 1 addition & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// ---------------------------------------------------------------------------------------------------------------------

name := "ChatOverflow"
version := "0.2"
version := "0.2.1"
mainClass := Some("org.codeoverflow.chatoverflow.Launcher")

// One version for all sub projects. Use "retrieveManaged := true" to download and show all library dependencies.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,15 @@ abstract class EventInputImpl[T <: Event, C <: Connector](implicit ctc: ClassTag
handlers.filter(handler => handler.clazz == cts.runtimeClass)
.foreach(handler => handler.consumer.asInstanceOf[Consumer[S]].accept(event))
}

override def shutdown(): Boolean = {
if (sourceConnector.isDefined) {
val stopped = stop()
handlers.clear()
stopped & sourceConnector.get.shutdown()
} else {
logger warn "Source connector not set."
false
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,21 @@ class DiscordChatConnector(override val sourceIdentifier: String) extends Connec
def addReactionDelEventListener(listener: MessageReactionRemoveEvent => Unit): Unit =
discordChatListener.addReactionDelEventListener(listener)

def removeMessageReceivedListener(listener: MessageReceivedEvent => Unit): Unit =
discordChatListener.removeMessageReceivedListener(listener)

def removeMessageUpdateListener(listener: MessageUpdateEvent => Unit): Unit =
discordChatListener.removeMessageUpdateEventListener(listener)

def removeMessageDeleteListener(listener: MessageDeleteEvent => Unit): Unit =
discordChatListener.removeMessageDeleteEventListener(listener)

def removeReactionAddEventListener(listener: MessageReactionAddEvent => Unit): Unit =
discordChatListener.removeReactionAddEventListener(listener)

def removeReactionDelEventListener(listener: MessageReactionRemoveEvent => Unit): Unit =
discordChatListener.removeReactionDelEventListener(listener)

/**
* Connects to discord
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,16 @@ class DiscordChatListener extends EventListener {

def addReactionDelEventListener(listener: MessageReactionRemoveEvent => Unit): Unit = reactionDelEventListener += listener

def removeMessageReceivedListener(listener: MessageReceivedEvent => Unit): Unit = messageEventListener -= listener

def removeMessageUpdateEventListener(listener: MessageUpdateEvent => Unit): Unit = messageUpdateEventListener -= listener

def removeMessageDeleteEventListener(listener: MessageDeleteEvent => Unit): Unit = messageDeleteEventListener -= listener

def removeReactionAddEventListener(listener: MessageReactionAddEvent => Unit): Unit = reactionAddEventListener -= listener

def removeReactionDelEventListener(listener: MessageReactionRemoveEvent => Unit): Unit = reactionDelEventListener -= listener

override def onEvent(event: Event): Unit = {
event match {
case receivedEvent: MessageReceivedEvent => messageEventListener.foreach(listener => listener(receivedEvent))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,18 @@ class DiscordChatInputImpl extends EventInputImpl[DiscordEvent, DiscordChatConne
private val privateMessages = ListBuffer[DiscordChatMessage]()
private var channelId: Option[String] = None

private val onMessageFn = onMessage _
private val onMessageUpdateFn = onMessageUpdate _
private val onMessageDeleteFn = onMessageDelete _
private val onReactionAddedFn = onReactionAdded _
private val onReactionRemovedFn = onReactionRemoved _

override def start(): Boolean = {
sourceConnector.get.addMessageReceivedListener(onMessage)
sourceConnector.get.addMessageUpdateListener(onMessageUpdate)
sourceConnector.get.addMessageDeleteListener(onMessageDelete)
sourceConnector.get.addReactionAddEventListener(onReactionAdded)
sourceConnector.get.addReactionDelEventListener(onReactionRemoved)
sourceConnector.get.addMessageReceivedListener(onMessageFn)
sourceConnector.get.addMessageUpdateListener(onMessageUpdateFn)
sourceConnector.get.addMessageDeleteListener(onMessageDeleteFn)
sourceConnector.get.addReactionAddEventListener(onReactionAddedFn)
sourceConnector.get.addReactionDelEventListener(onReactionRemovedFn)
true
}

Expand Down Expand Up @@ -81,7 +87,14 @@ class DiscordChatInputImpl extends EventInputImpl[DiscordEvent, DiscordChatConne
*
* @return true if stopping was successful
*/
override def stop(): Boolean = true
override def stop(): Boolean = {
sourceConnector.get.removeMessageReceivedListener(onMessageFn)
sourceConnector.get.removeMessageUpdateListener(onMessageUpdateFn)
sourceConnector.get.removeMessageDeleteListener(onMessageDeleteFn)
sourceConnector.get.removeReactionAddEventListener(onReactionAddedFn)
sourceConnector.get.removeReactionDelEventListener(onReactionRemovedFn)
true
}

/**
* Listens for received messages, parses the data, adds them to the buffer and handles them over to the correct handler
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ package org.codeoverflow.chatoverflow.requirement.service.serial

import java.io.{InputStream, PrintStream}

import com.fazecast.jSerialComm.{SerialPort, SerialPortInvalidPortException}
import com.fazecast.jSerialComm.{SerialPort, SerialPortEvent, SerialPortInvalidPortException}
import org.codeoverflow.chatoverflow.WithLogger
import org.codeoverflow.chatoverflow.connector.Connector

import scala.collection.mutable

/**
* The serial connector allows to communicate with a device connected to the pcs serial port (like an Arduino)
*
Expand All @@ -19,6 +21,7 @@ class SerialConnector(override val sourceIdentifier: String) extends Connector(s
private var serialPort: Option[SerialPort] = None
private var out: Option[PrintStream] = None
private var in: Option[InputStream] = None
private val inputListeners: mutable.Map[Array[Byte] => Unit, SerialPortEvent => Unit] = mutable.Map()

/**
* @throws java.lang.IllegalStateException if the serial port is not available yet
Expand Down Expand Up @@ -49,11 +52,20 @@ class SerialConnector(override val sourceIdentifier: String) extends Connector(s
@throws(classOf[IllegalStateException])
def addInputListener(listener: Array[Byte] => Unit): Unit = {
if (serialPort.isEmpty) throw new IllegalStateException("Serial port is not available yet")
serialPortInputListener.addDataAvailableListener(_ => {
val l: SerialPortEvent => Unit = _ => {
val buffer = new Array[Byte](serialPort.get.bytesAvailable())
serialPort.get.readBytes(buffer, buffer.length)
listener(buffer)
})
}
inputListeners += (listener -> l)
serialPortInputListener.addDataAvailableListener(l)
}

def removeInputListener(listener: Array[Byte] => Unit): Unit = {
inputListeners remove listener match {
case Some(l) => serialPortInputListener.removeDataAvailableListener(l)
case _ => //listener not found, do nothing
}
}

/**
Expand Down Expand Up @@ -93,6 +105,7 @@ class SerialConnector(override val sourceIdentifier: String) extends Connector(s
* Closes the connection with the port
*/
override def stop(): Boolean = {

serialPort.foreach(_.closePort())
true
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,6 @@ class SerialPortInputListener extends SerialPortDataListener {
}

def addDataAvailableListener(listener: SerialPortEvent => Unit): Unit = listeners += listener

def removeDataAvailableListener(listener: SerialPortEvent => Unit): Unit = listeners += listener
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,24 @@ import org.codeoverflow.chatoverflow.requirement.service.serial.SerialConnector
@Impl(impl = classOf[SerialInput], connector = classOf[SerialConnector])
class SerialInputImpl extends EventInputImpl[SerialEvent, SerialConnector] with SerialInput with WithLogger {

private val onInputFn = onInput _

override def start(): Boolean = {
sourceConnector.get.addInputListener(bytes => call(new SerialDataAvailableEvent(bytes)))
sourceConnector.get.addInputListener(onInputFn)
true
}

private def onInput(bytes: Array[Byte]): Unit = call(new SerialDataAvailableEvent(bytes))

override def getInputStream: InputStream = sourceConnector.get.getInputStream

/**
* Stops the input, called before source connector will shutdown
*
* @return true if stopping was successful
*/
override def stop(): Boolean = true
override def stop(): Boolean = {
sourceConnector.get.removeInputListener(onInputFn)
true
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,12 @@ class TipeeestreamConnector(override val sourceIdentifier: String) extends Conne

def addFollowEventListener(listener: JSONObject => Unit): Unit = tipeeeStreamListener.addFollowEventListener(listener)

def removeSubscriptionEventListener(listener: JSONObject => Unit): Unit = tipeeeStreamListener.removeSubscriptionEventListener(listener)

def removeDonationEventListener(listener: JSONObject => Unit): Unit = tipeeeStreamListener.removeDonationEventListener(listener)

def removeFollowEventListener(listener: JSONObject => Unit): Unit = tipeeeStreamListener.removeFollowEventListener(listener)

override def stop(): Boolean = {
socket.foreach(_.close())
true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,18 @@ class TipeeestreamListener {
followEventListeners += listener
}

def removeSubscriptionEventListener(listener: JSONObject => Unit): Unit = {
subscriptionEventListeners -= listener
}

def removeDonationEventListener(listener: JSONObject => Unit): Unit = {
donationEventListeners -= listener
}

def removeFollowEventListener(listener: JSONObject => Unit): Unit = {
followEventListeners -= listener
}

def onSocketEvent(objects : Array[AnyRef]) : Unit = {
val json: JSONObject = objects(0).asInstanceOf[JSONObject]
val event: JSONObject = json.getJSONObject("event")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,14 @@ class TipeestreamEventInputImpl extends EventInputImpl[TipeeestreamEvent, Tipeee
private val DATE_FORMATTER = new DateTimeFormatterBuilder()
.parseCaseInsensitive().append(DateTimeFormatter.ISO_LOCAL_DATE_TIME).appendOffset("+HHMM", "Z").toFormatter

private val onFollowFn = onFollow _
private val onSubscriptionFn = onSubscription _
private val onDonationFn = onDonation _

override def start(): Boolean = {
sourceConnector.get.addFollowEventListener(onFollow)
sourceConnector.get.addSubscriptionEventListener(onSubscription)
sourceConnector.get.addDonationEventListener(onDonation)
sourceConnector.get.addFollowEventListener(onFollowFn)
sourceConnector.get.addSubscriptionEventListener(onSubscriptionFn)
sourceConnector.get.addDonationEventListener(onDonationFn)
true
}

Expand Down Expand Up @@ -83,5 +87,10 @@ class TipeestreamEventInputImpl extends EventInputImpl[TipeeestreamEvent, Tipeee
}
}

override def stop(): Boolean = true
override def stop(): Boolean = {
sourceConnector.get.removeFollowEventListener(onFollowFn)
sourceConnector.get.removeSubscriptionEventListener(onSubscriptionFn)
sourceConnector.get.removeDonationEventListener(onDonationFn)
true
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package org.codeoverflow.chatoverflow.requirement.service.twitch.chat

import org.pircbotx.hooks.events.{ConnectAttemptFailedEvent, ConnectEvent, NoticeEvent}
import org.pircbotx.hooks.{Event, ListenerAdapter}

/**
* Handles connection events for the TwitchChatConnector.
* Calls the callback function once the bot connected and reports connection errors.
* @param fn the callback which will be called once suitable event has been received.
* The first param informs whether the connection could be established successfully
* and the second param includes a error description if something has gone wrong.
*/
class TwitchChatConnectListener(fn: (Boolean, String) => Unit) extends ListenerAdapter {
override def onEvent(event: Event): Unit = {
event match {
case _: ConnectEvent => fn(true, "")
case e: ConnectAttemptFailedEvent => fn(false, "couldn't connect to irc chat server")
case e: NoticeEvent =>
if (e.getNotice.contains("authentication failed")) {
fn(false, "authentication failed")
}
case _ =>
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,12 @@ import scala.collection.mutable.ListBuffer
*/
class TwitchChatConnector(override val sourceIdentifier: String) extends Connector(sourceIdentifier) with WithLogger {
private val twitchChatListener = new TwitchChatListener
private val connectionListener = new TwitchChatConnectListener(onConnect)
private val oauthKey = "oauth"
override protected var requiredCredentialKeys: List[String] = List(oauthKey)
override protected var optionalCredentialKeys: List[String] = List()
private var bot: PircBotX = _
private var status: Option[(Boolean, String)] = None
private val channels = ListBuffer[String]()

def addMessageEventListener(listener: MessageEvent => Unit): Unit = {
Expand All @@ -29,6 +31,14 @@ class TwitchChatConnector(override val sourceIdentifier: String) extends Connect
twitchChatListener.addUnknownEventListener(listener)
}

def removeMessageEventListener(listener: MessageEvent => Unit): Unit = {
twitchChatListener.removeMessageEventListener(listener)
}

def removeUnknownEventListener(listener: UnknownEvent => Unit): Unit = {
twitchChatListener.removeUnknownEventListener(listener)
}

def joinChannel(channel: String): Unit = {
bot.send().joinChannel(channel)
channels += channel
Expand Down Expand Up @@ -63,6 +73,7 @@ class TwitchChatConnector(override val sourceIdentifier: String) extends Connect
.setName(credentials.get.credentialsIdentifier)
.setServerPassword(password.getOrElse(""))
.addListener(twitchChatListener)
.addListener(connectionListener)
.buildConfiguration()
} else {
logger error "No credentials set!"
Expand All @@ -71,33 +82,47 @@ class TwitchChatConnector(override val sourceIdentifier: String) extends Connect

}

/**
* Gets called by the TwitchChatConnectListener when the bot has connected.
* Saves the passed information into the status variable.
*/
private def onConnect(success: Boolean, msg: String): Unit = {
status.synchronized {
// tell the thread which starts the connector that the status has been reported
status.notify()
status = Some((success, msg))
}
}

/**
* Starts the connector, e.g. creates a connection with its platform.
*/
override def start(): Boolean = {
bot = new PircBotX(getConfig)
startBot()
true
}

private def startBot(): Unit = {

var errorCount = 0

private def startBot(): Boolean = {
new Thread(() => {
bot.startBot()
}).start()

while (bot.getState != PircBotX.State.CONNECTED && errorCount < 30) {
logger info "Waiting while the bot is connecting..."
Thread.sleep(100)
errorCount += 1
logger info "Waiting while the bot is connecting and logging in..."
status.synchronized {
status.wait(10000)
}

if (status.isEmpty) {
logger error "Bot couldn't connect within timeout of 10 seconds."
return false
}

if (errorCount >= 30) {
logger error "Fatal. Unable to start bot."
val (success, msg) = status.get
if (!success) {
logger error s"Bot couldn't connect. Reason: $msg."
}

success
}

/**
Expand All @@ -106,6 +131,8 @@ class TwitchChatConnector(override val sourceIdentifier: String) extends Connect
override def stop(): Boolean = {
bot.sendIRC().quitServer()
bot.close()
status = None
channels.clear()
true
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,12 @@ class TwitchChatListener extends ListenerAdapter {
unknownEventListener += listener
}

def removeMessageEventListener(listener: MessageEvent => Unit): Unit = {
messageEventListener -= listener
}

def removeUnknownEventListener(listener: UnknownEvent => Unit): Unit = {
unknownEventListener -= listener
}

}
Loading

0 comments on commit 8fdba80

Please sign in to comment.