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

Commit 8fdba80

Browse files
committed
Merge branch 'hotfix/0.2.1-prealpha'
2 parents a6bac81 + 71fc2c9 commit 8fdba80

15 files changed

+196
-31
lines changed

build.sbt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
// ---------------------------------------------------------------------------------------------------------------------
44

55
name := "ChatOverflow"
6-
version := "0.2"
6+
version := "0.2.1"
77
mainClass := Some("org.codeoverflow.chatoverflow.Launcher")
88

99
// One version for all sub projects. Use "retrieveManaged := true" to download and show all library dependencies.

src/main/scala/org/codeoverflow/chatoverflow/requirement/impl/EventInputImpl.scala

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,4 +39,15 @@ abstract class EventInputImpl[T <: Event, C <: Connector](implicit ctc: ClassTag
3939
handlers.filter(handler => handler.clazz == cts.runtimeClass)
4040
.foreach(handler => handler.consumer.asInstanceOf[Consumer[S]].accept(event))
4141
}
42+
43+
override def shutdown(): Boolean = {
44+
if (sourceConnector.isDefined) {
45+
val stopped = stop()
46+
handlers.clear()
47+
stopped & sourceConnector.get.shutdown()
48+
} else {
49+
logger warn "Source connector not set."
50+
false
51+
}
52+
}
4253
}

src/main/scala/org/codeoverflow/chatoverflow/requirement/service/discord/DiscordChatConnector.scala

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,21 @@ class DiscordChatConnector(override val sourceIdentifier: String) extends Connec
4747
def addReactionDelEventListener(listener: MessageReactionRemoveEvent => Unit): Unit =
4848
discordChatListener.addReactionDelEventListener(listener)
4949

50+
def removeMessageReceivedListener(listener: MessageReceivedEvent => Unit): Unit =
51+
discordChatListener.removeMessageReceivedListener(listener)
52+
53+
def removeMessageUpdateListener(listener: MessageUpdateEvent => Unit): Unit =
54+
discordChatListener.removeMessageUpdateEventListener(listener)
55+
56+
def removeMessageDeleteListener(listener: MessageDeleteEvent => Unit): Unit =
57+
discordChatListener.removeMessageDeleteEventListener(listener)
58+
59+
def removeReactionAddEventListener(listener: MessageReactionAddEvent => Unit): Unit =
60+
discordChatListener.removeReactionAddEventListener(listener)
61+
62+
def removeReactionDelEventListener(listener: MessageReactionRemoveEvent => Unit): Unit =
63+
discordChatListener.removeReactionDelEventListener(listener)
64+
5065
/**
5166
* Connects to discord
5267
*/

src/main/scala/org/codeoverflow/chatoverflow/requirement/service/discord/DiscordChatListener.scala

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,16 @@ class DiscordChatListener extends EventListener {
3232

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

35+
def removeMessageReceivedListener(listener: MessageReceivedEvent => Unit): Unit = messageEventListener -= listener
36+
37+
def removeMessageUpdateEventListener(listener: MessageUpdateEvent => Unit): Unit = messageUpdateEventListener -= listener
38+
39+
def removeMessageDeleteEventListener(listener: MessageDeleteEvent => Unit): Unit = messageDeleteEventListener -= listener
40+
41+
def removeReactionAddEventListener(listener: MessageReactionAddEvent => Unit): Unit = reactionAddEventListener -= listener
42+
43+
def removeReactionDelEventListener(listener: MessageReactionRemoveEvent => Unit): Unit = reactionDelEventListener -= listener
44+
3545
override def onEvent(event: Event): Unit = {
3646
event match {
3747
case receivedEvent: MessageReceivedEvent => messageEventListener.foreach(listener => listener(receivedEvent))

src/main/scala/org/codeoverflow/chatoverflow/requirement/service/discord/impl/DiscordChatInputImpl.scala

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,18 @@ class DiscordChatInputImpl extends EventInputImpl[DiscordEvent, DiscordChatConne
3434
private val privateMessages = ListBuffer[DiscordChatMessage]()
3535
private var channelId: Option[String] = None
3636

37+
private val onMessageFn = onMessage _
38+
private val onMessageUpdateFn = onMessageUpdate _
39+
private val onMessageDeleteFn = onMessageDelete _
40+
private val onReactionAddedFn = onReactionAdded _
41+
private val onReactionRemovedFn = onReactionRemoved _
42+
3743
override def start(): Boolean = {
38-
sourceConnector.get.addMessageReceivedListener(onMessage)
39-
sourceConnector.get.addMessageUpdateListener(onMessageUpdate)
40-
sourceConnector.get.addMessageDeleteListener(onMessageDelete)
41-
sourceConnector.get.addReactionAddEventListener(onReactionAdded)
42-
sourceConnector.get.addReactionDelEventListener(onReactionRemoved)
44+
sourceConnector.get.addMessageReceivedListener(onMessageFn)
45+
sourceConnector.get.addMessageUpdateListener(onMessageUpdateFn)
46+
sourceConnector.get.addMessageDeleteListener(onMessageDeleteFn)
47+
sourceConnector.get.addReactionAddEventListener(onReactionAddedFn)
48+
sourceConnector.get.addReactionDelEventListener(onReactionRemovedFn)
4349
true
4450
}
4551

@@ -81,7 +87,14 @@ class DiscordChatInputImpl extends EventInputImpl[DiscordEvent, DiscordChatConne
8187
*
8288
* @return true if stopping was successful
8389
*/
84-
override def stop(): Boolean = true
90+
override def stop(): Boolean = {
91+
sourceConnector.get.removeMessageReceivedListener(onMessageFn)
92+
sourceConnector.get.removeMessageUpdateListener(onMessageUpdateFn)
93+
sourceConnector.get.removeMessageDeleteListener(onMessageDeleteFn)
94+
sourceConnector.get.removeReactionAddEventListener(onReactionAddedFn)
95+
sourceConnector.get.removeReactionDelEventListener(onReactionRemovedFn)
96+
true
97+
}
8598

8699
/**
87100
* Listens for received messages, parses the data, adds them to the buffer and handles them over to the correct handler

src/main/scala/org/codeoverflow/chatoverflow/requirement/service/serial/SerialConnector.scala

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@ package org.codeoverflow.chatoverflow.requirement.service.serial
22

33
import java.io.{InputStream, PrintStream}
44

5-
import com.fazecast.jSerialComm.{SerialPort, SerialPortInvalidPortException}
5+
import com.fazecast.jSerialComm.{SerialPort, SerialPortEvent, SerialPortInvalidPortException}
66
import org.codeoverflow.chatoverflow.WithLogger
77
import org.codeoverflow.chatoverflow.connector.Connector
88

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

2326
/**
2427
* @throws java.lang.IllegalStateException if the serial port is not available yet
@@ -49,11 +52,20 @@ class SerialConnector(override val sourceIdentifier: String) extends Connector(s
4952
@throws(classOf[IllegalStateException])
5053
def addInputListener(listener: Array[Byte] => Unit): Unit = {
5154
if (serialPort.isEmpty) throw new IllegalStateException("Serial port is not available yet")
52-
serialPortInputListener.addDataAvailableListener(_ => {
55+
val l: SerialPortEvent => Unit = _ => {
5356
val buffer = new Array[Byte](serialPort.get.bytesAvailable())
5457
serialPort.get.readBytes(buffer, buffer.length)
5558
listener(buffer)
56-
})
59+
}
60+
inputListeners += (listener -> l)
61+
serialPortInputListener.addDataAvailableListener(l)
62+
}
63+
64+
def removeInputListener(listener: Array[Byte] => Unit): Unit = {
65+
inputListeners remove listener match {
66+
case Some(l) => serialPortInputListener.removeDataAvailableListener(l)
67+
case _ => //listener not found, do nothing
68+
}
5769
}
5870

5971
/**
@@ -93,6 +105,7 @@ class SerialConnector(override val sourceIdentifier: String) extends Connector(s
93105
* Closes the connection with the port
94106
*/
95107
override def stop(): Boolean = {
108+
96109
serialPort.foreach(_.closePort())
97110
true
98111
}

src/main/scala/org/codeoverflow/chatoverflow/requirement/service/serial/SerialPortInputListener.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,6 @@ class SerialPortInputListener extends SerialPortDataListener {
1717
}
1818

1919
def addDataAvailableListener(listener: SerialPortEvent => Unit): Unit = listeners += listener
20+
21+
def removeDataAvailableListener(listener: SerialPortEvent => Unit): Unit = listeners += listener
2022
}

src/main/scala/org/codeoverflow/chatoverflow/requirement/service/serial/impl/SerialInputImpl.scala

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,24 @@ import org.codeoverflow.chatoverflow.requirement.service.serial.SerialConnector
1212
@Impl(impl = classOf[SerialInput], connector = classOf[SerialConnector])
1313
class SerialInputImpl extends EventInputImpl[SerialEvent, SerialConnector] with SerialInput with WithLogger {
1414

15+
private val onInputFn = onInput _
16+
1517
override def start(): Boolean = {
16-
sourceConnector.get.addInputListener(bytes => call(new SerialDataAvailableEvent(bytes)))
18+
sourceConnector.get.addInputListener(onInputFn)
1719
true
1820
}
1921

22+
private def onInput(bytes: Array[Byte]): Unit = call(new SerialDataAvailableEvent(bytes))
23+
2024
override def getInputStream: InputStream = sourceConnector.get.getInputStream
2125

2226
/**
2327
* Stops the input, called before source connector will shutdown
2428
*
2529
* @return true if stopping was successful
2630
*/
27-
override def stop(): Boolean = true
31+
override def stop(): Boolean = {
32+
sourceConnector.get.removeInputListener(onInputFn)
33+
true
34+
}
2835
}

src/main/scala/org/codeoverflow/chatoverflow/requirement/service/tipeeestream/TipeeestreamConnector.scala

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,12 @@ class TipeeestreamConnector(override val sourceIdentifier: String) extends Conne
8686

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

89+
def removeSubscriptionEventListener(listener: JSONObject => Unit): Unit = tipeeeStreamListener.removeSubscriptionEventListener(listener)
90+
91+
def removeDonationEventListener(listener: JSONObject => Unit): Unit = tipeeeStreamListener.removeDonationEventListener(listener)
92+
93+
def removeFollowEventListener(listener: JSONObject => Unit): Unit = tipeeeStreamListener.removeFollowEventListener(listener)
94+
8995
override def stop(): Boolean = {
9096
socket.foreach(_.close())
9197
true

src/main/scala/org/codeoverflow/chatoverflow/requirement/service/tipeeestream/TipeeestreamListener.scala

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,18 @@ class TipeeestreamListener {
2323
followEventListeners += listener
2424
}
2525

26+
def removeSubscriptionEventListener(listener: JSONObject => Unit): Unit = {
27+
subscriptionEventListeners -= listener
28+
}
29+
30+
def removeDonationEventListener(listener: JSONObject => Unit): Unit = {
31+
donationEventListeners -= listener
32+
}
33+
34+
def removeFollowEventListener(listener: JSONObject => Unit): Unit = {
35+
followEventListeners -= listener
36+
}
37+
2638
def onSocketEvent(objects : Array[AnyRef]) : Unit = {
2739
val json: JSONObject = objects(0).asInstanceOf[JSONObject]
2840
val event: JSONObject = json.getJSONObject("event")

src/main/scala/org/codeoverflow/chatoverflow/requirement/service/tipeeestream/impl/TipeestreamEventInputImpl.scala

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,14 @@ class TipeestreamEventInputImpl extends EventInputImpl[TipeeestreamEvent, Tipeee
1919
private val DATE_FORMATTER = new DateTimeFormatterBuilder()
2020
.parseCaseInsensitive().append(DateTimeFormatter.ISO_LOCAL_DATE_TIME).appendOffset("+HHMM", "Z").toFormatter
2121

22+
private val onFollowFn = onFollow _
23+
private val onSubscriptionFn = onSubscription _
24+
private val onDonationFn = onDonation _
25+
2226
override def start(): Boolean = {
23-
sourceConnector.get.addFollowEventListener(onFollow)
24-
sourceConnector.get.addSubscriptionEventListener(onSubscription)
25-
sourceConnector.get.addDonationEventListener(onDonation)
27+
sourceConnector.get.addFollowEventListener(onFollowFn)
28+
sourceConnector.get.addSubscriptionEventListener(onSubscriptionFn)
29+
sourceConnector.get.addDonationEventListener(onDonationFn)
2630
true
2731
}
2832

@@ -83,5 +87,10 @@ class TipeestreamEventInputImpl extends EventInputImpl[TipeeestreamEvent, Tipeee
8387
}
8488
}
8589

86-
override def stop(): Boolean = true
90+
override def stop(): Boolean = {
91+
sourceConnector.get.removeFollowEventListener(onFollowFn)
92+
sourceConnector.get.removeSubscriptionEventListener(onSubscriptionFn)
93+
sourceConnector.get.removeDonationEventListener(onDonationFn)
94+
true
95+
}
8796
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package org.codeoverflow.chatoverflow.requirement.service.twitch.chat
2+
3+
import org.pircbotx.hooks.events.{ConnectAttemptFailedEvent, ConnectEvent, NoticeEvent}
4+
import org.pircbotx.hooks.{Event, ListenerAdapter}
5+
6+
/**
7+
* Handles connection events for the TwitchChatConnector.
8+
* Calls the callback function once the bot connected and reports connection errors.
9+
* @param fn the callback which will be called once suitable event has been received.
10+
* The first param informs whether the connection could be established successfully
11+
* and the second param includes a error description if something has gone wrong.
12+
*/
13+
class TwitchChatConnectListener(fn: (Boolean, String) => Unit) extends ListenerAdapter {
14+
override def onEvent(event: Event): Unit = {
15+
event match {
16+
case _: ConnectEvent => fn(true, "")
17+
case e: ConnectAttemptFailedEvent => fn(false, "couldn't connect to irc chat server")
18+
case e: NoticeEvent =>
19+
if (e.getNotice.contains("authentication failed")) {
20+
fn(false, "authentication failed")
21+
}
22+
case _ =>
23+
}
24+
}
25+
}

src/main/scala/org/codeoverflow/chatoverflow/requirement/service/twitch/chat/TwitchChatConnector.scala

Lines changed: 38 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,12 @@ import scala.collection.mutable.ListBuffer
1515
*/
1616
class TwitchChatConnector(override val sourceIdentifier: String) extends Connector(sourceIdentifier) with WithLogger {
1717
private val twitchChatListener = new TwitchChatListener
18+
private val connectionListener = new TwitchChatConnectListener(onConnect)
1819
private val oauthKey = "oauth"
1920
override protected var requiredCredentialKeys: List[String] = List(oauthKey)
2021
override protected var optionalCredentialKeys: List[String] = List()
2122
private var bot: PircBotX = _
23+
private var status: Option[(Boolean, String)] = None
2224
private val channels = ListBuffer[String]()
2325

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

34+
def removeMessageEventListener(listener: MessageEvent => Unit): Unit = {
35+
twitchChatListener.removeMessageEventListener(listener)
36+
}
37+
38+
def removeUnknownEventListener(listener: UnknownEvent => Unit): Unit = {
39+
twitchChatListener.removeUnknownEventListener(listener)
40+
}
41+
3242
def joinChannel(channel: String): Unit = {
3343
bot.send().joinChannel(channel)
3444
channels += channel
@@ -63,6 +73,7 @@ class TwitchChatConnector(override val sourceIdentifier: String) extends Connect
6373
.setName(credentials.get.credentialsIdentifier)
6474
.setServerPassword(password.getOrElse(""))
6575
.addListener(twitchChatListener)
76+
.addListener(connectionListener)
6677
.buildConfiguration()
6778
} else {
6879
logger error "No credentials set!"
@@ -71,33 +82,47 @@ class TwitchChatConnector(override val sourceIdentifier: String) extends Connect
7182

7283
}
7384

85+
/**
86+
* Gets called by the TwitchChatConnectListener when the bot has connected.
87+
* Saves the passed information into the status variable.
88+
*/
89+
private def onConnect(success: Boolean, msg: String): Unit = {
90+
status.synchronized {
91+
// tell the thread which starts the connector that the status has been reported
92+
status.notify()
93+
status = Some((success, msg))
94+
}
95+
}
96+
7497
/**
7598
* Starts the connector, e.g. creates a connection with its platform.
7699
*/
77100
override def start(): Boolean = {
78101
bot = new PircBotX(getConfig)
79102
startBot()
80-
true
81103
}
82104

83-
private def startBot(): Unit = {
84-
85-
var errorCount = 0
86-
105+
private def startBot(): Boolean = {
87106
new Thread(() => {
88107
bot.startBot()
89108
}).start()
90109

91-
while (bot.getState != PircBotX.State.CONNECTED && errorCount < 30) {
92-
logger info "Waiting while the bot is connecting..."
93-
Thread.sleep(100)
94-
errorCount += 1
110+
logger info "Waiting while the bot is connecting and logging in..."
111+
status.synchronized {
112+
status.wait(10000)
113+
}
114+
115+
if (status.isEmpty) {
116+
logger error "Bot couldn't connect within timeout of 10 seconds."
117+
return false
95118
}
96119

97-
if (errorCount >= 30) {
98-
logger error "Fatal. Unable to start bot."
120+
val (success, msg) = status.get
121+
if (!success) {
122+
logger error s"Bot couldn't connect. Reason: $msg."
99123
}
100124

125+
success
101126
}
102127

103128
/**
@@ -106,6 +131,8 @@ class TwitchChatConnector(override val sourceIdentifier: String) extends Connect
106131
override def stop(): Boolean = {
107132
bot.sendIRC().quitServer()
108133
bot.close()
134+
status = None
135+
channels.clear()
109136
true
110137
}
111138
}

src/main/scala/org/codeoverflow/chatoverflow/requirement/service/twitch/chat/TwitchChatListener.scala

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,12 @@ class TwitchChatListener extends ListenerAdapter {
2929
unknownEventListener += listener
3030
}
3131

32+
def removeMessageEventListener(listener: MessageEvent => Unit): Unit = {
33+
messageEventListener -= listener
34+
}
35+
36+
def removeUnknownEventListener(listener: UnknownEvent => Unit): Unit = {
37+
unknownEventListener -= listener
38+
}
39+
3240
}

0 commit comments

Comments
 (0)