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

Commit

Permalink
Rework inputs & outputs / prettify xml output
Browse files Browse the repository at this point in the history
  • Loading branch information
J0B10 committed May 18, 2019
1 parent 26ee071 commit 6d96407
Show file tree
Hide file tree
Showing 8 changed files with 117 additions and 101 deletions.
@@ -1,6 +1,6 @@
package org.codeoverflow.chatoverflow.configuration

import java.io.File
import java.io.{File, PrintWriter}

import org.codeoverflow.chatoverflow.WithLogger
import org.codeoverflow.chatoverflow.api.io
Expand All @@ -10,7 +10,7 @@ import org.codeoverflow.chatoverflow.framework.PluginFramework
import org.codeoverflow.chatoverflow.instance.PluginInstanceRegistry
import org.codeoverflow.chatoverflow.registry.TypeRegistry

import scala.xml.{Elem, Node}
import scala.xml.{Elem, Node, PrettyPrinter}

/**
* The configuration service provides methods to work with serialized state information.
Expand Down Expand Up @@ -153,7 +153,9 @@ class ConfigurationService(val configFilePath: String) extends WithLogger {
* Saves the xml content to the config xml.
*/
private def saveXML(xmlContent: Node): Unit = {
xml.XML.save(configFilePath, xmlContent)
val writer = new PrintWriter(configFilePath)
writer.print(new PrettyPrinter(120,2).format(xmlContent))
writer.close()
logger info "Saved config file."
}

Expand Down
Expand Up @@ -4,9 +4,9 @@ import org.codeoverflow.chatoverflow.WithLogger
import org.codeoverflow.chatoverflow.api.io.input.Input
import org.codeoverflow.chatoverflow.connector.Connector

import scala.collection.mutable
import scala.reflect.ClassTag

abstract class InputImpl[C <: Connector] extends Connection[C] with Input with WithLogger {
abstract class InputImpl[C <: Connector](implicit ct: ClassTag[C]) extends Connection[C] with Input with WithLogger {

/**
* Inits this connection, checks if teh source connector is defined, and can be inited, then calls start
Expand Down
Expand Up @@ -4,9 +4,9 @@ import org.codeoverflow.chatoverflow.WithLogger
import org.codeoverflow.chatoverflow.api.io.output.Output
import org.codeoverflow.chatoverflow.connector.Connector

import scala.collection.mutable
import scala.reflect.ClassTag

abstract class OutputImpl[C <: Connector] extends Connection[C] with Output with WithLogger {
abstract class OutputImpl[C <: Connector](implicit ct: ClassTag[C]) extends Connection[C] with Output with WithLogger {

/**
* Inits this connection, checks if teh source connector is defined, and can be inited, then calls start
Expand Down
Expand Up @@ -22,7 +22,7 @@ import scala.collection.mutable.ListBuffer
@Impl(impl = classOf[DiscordChatInput], connector = classOf[DiscordChatConnector])
class DiscordChatInputImpl extends InputImpl[DiscordChatConnector] with DiscordChatInput with WithLogger {

private var channelId = getSourceIdentifier
private var channelId: Option[String] = None
private val messages: ListBuffer[DiscordChatMessage] = ListBuffer[DiscordChatMessage]()
private val privateMessages: ListBuffer[DiscordChatMessage] = ListBuffer[DiscordChatMessage]()
private val messageHandler = ListBuffer[Consumer[DiscordChatMessage]]()
Expand All @@ -33,7 +33,6 @@ class DiscordChatInputImpl extends InputImpl[DiscordChatConnector] with DiscordC
private val privateMessageDeleteHandler = ListBuffer[Consumer[DiscordChatMessage]]()

override def start(): Boolean = {
setChannel(getSourceIdentifier)
sourceConnector.get.addMessageReceivedListener(onMessage)
sourceConnector.get.addMessageUpdateListener(onMessageUpdate)
sourceConnector.get.addMessageDeleteListener(onMessageDelete)
Expand All @@ -47,15 +46,17 @@ class DiscordChatInputImpl extends InputImpl[DiscordChatConnector] with DiscordC
*/
private def onMessage(event: MessageReceivedEvent): Unit = {
if (event.getMessage.getType == MessageType.DEFAULT) {
val message = DiscordChatInputImpl.parse(event.getMessage)
event.getChannelType match {
case ChannelType.TEXT if event.getTextChannel.getId == channelId =>
messageHandler.foreach(_.accept(message))
messages += message
case ChannelType.PRIVATE =>
privateMessageHandler.foreach(_.accept(message))
privateMessages += message
case _ => //Unknown channel, do nothing
if (channelId.isDefined) {
val message = DiscordChatInputImpl.parse(event.getMessage)
event.getChannelType match {
case ChannelType.TEXT if event.getTextChannel.getId == channelId.get =>
messageHandler.foreach(_.accept(message))
messages += message
case ChannelType.PRIVATE =>
privateMessageHandler.foreach(_.accept(message))
privateMessages += message
case _ => //Unknown channel, do nothing
}
}
}
}
Expand Down Expand Up @@ -94,20 +95,22 @@ class DiscordChatInputImpl extends InputImpl[DiscordChatConnector] with DiscordC
* @param event a event with an deleted message
*/
private def onMessageDelete(event: MessageDeleteEvent): Unit = {
val id = event.getMessageId
event.getChannelType match {
case ChannelType.TEXT if event.getTextChannel.getId == channelId =>
val i = messages.indexWhere(_.getId == id)
if (i != -1) {
val oldMessage = messages.remove(i)
messageDeleteHandler.foreach(_.accept(oldMessage))
}
case ChannelType.PRIVATE =>
val i = privateMessages.indexWhere(_.getId == id)
if (i != -1) {
val oldMessage = privateMessages.remove(i)
privateMessageDeleteHandler.foreach(_.accept(oldMessage))
}
if (channelId.isDefined) {
val id = event.getMessageId
event.getChannelType match {
case ChannelType.TEXT if event.getTextChannel.getId == channelId.get =>
val i = messages.indexWhere(_.getId == id)
if (i != -1) {
val oldMessage = messages.remove(i)
messageDeleteHandler.foreach(_.accept(oldMessage))
}
case ChannelType.PRIVATE =>
val i = privateMessages.indexWhere(_.getId == id)
if (i != -1) {
val oldMessage = privateMessages.remove(i)
privateMessageDeleteHandler.foreach(_.accept(oldMessage))
}
}
}
}

Expand All @@ -122,26 +125,35 @@ class DiscordChatInputImpl extends InputImpl[DiscordChatConnector] with DiscordC

privateMessages.filter(_.getTimestamp > currentTime - lastMilliseconds).toList.asJava
}
override def registerMessageHandler(handler: Consumer[DiscordChatMessage]): Unit = messageHandler += handler
override def registerMessageHandler(handler: Consumer[DiscordChatMessage]): Unit = {
if (channelId.isEmpty) throw new IllegalStateException("first set the channel for this input")
messageHandler += handler
}

override def registerPrivateMessageHandler(handler : Consumer[DiscordChatMessage]): Unit = privateMessageHandler += handler

override def registerMessageEditHandler(handler: BiConsumer[DiscordChatMessage, DiscordChatMessage]): Unit = messageEditHandler += handler
override def registerMessageEditHandler(handler: BiConsumer[DiscordChatMessage, DiscordChatMessage]): Unit = {
if (channelId.isEmpty) throw new IllegalStateException("first set the channel for this input")
messageEditHandler += handler
}

override def registerPrivateMessageEditHandler(handler: BiConsumer[DiscordChatMessage, DiscordChatMessage]): Unit = privateMessageEditHandler += handler

override def registerMessageDeleteHandler(handler: Consumer[DiscordChatMessage]): Unit = messageDeleteHandler += handler
override def registerMessageDeleteHandler(handler: Consumer[DiscordChatMessage]): Unit = {
if (channelId.isEmpty) throw new IllegalStateException("first set the channel for this input")
messageDeleteHandler += handler
}

override def registerPrivateMessageDeleteHandler(handler: Consumer[DiscordChatMessage]): Unit = privateMessageDeleteHandler += handler

override def setChannel(channelId: String): Unit = {
sourceConnector.get.getTextChannel(channelId) match {
case Some(_) => this.channelId = channelId
case Some(_) => this.channelId = Some(channelId.trim)
case None => throw new IllegalArgumentException("Channel with that id doesn't exist")
}
}

override def getChannelId: String = channelId
override def getChannelId: String = channelId.get

override def getMessage(messageId: String): DiscordChatMessage =
messages.find(_.getId == messageId).getOrElse(privateMessages.find(_.getId == messageId).orNull)
Expand Down
Expand Up @@ -3,44 +3,30 @@ package org.codeoverflow.chatoverflow.requirement.service.discord.impl
import org.codeoverflow.chatoverflow.WithLogger
import org.codeoverflow.chatoverflow.api.io.output.chat.DiscordChatOutput
import org.codeoverflow.chatoverflow.registry.Impl
import org.codeoverflow.chatoverflow.requirement.Connection
import org.codeoverflow.chatoverflow.requirement.OutputImpl
import org.codeoverflow.chatoverflow.requirement.service.discord.DiscordChatConnector

/**
* This is the implementation of the discord chat output, using the discord connector.
*/
@Impl(impl = classOf[DiscordChatOutput], connector = classOf[DiscordChatConnector])
class DiscordChatOutputImpl extends Connection[DiscordChatConnector] with DiscordChatOutput with WithLogger {
class DiscordChatOutputImpl extends OutputImpl[DiscordChatConnector] with DiscordChatOutput with WithLogger {

private var channelId: String = _
private var channelId: Option[String] = None

override def start(): Boolean = true

override def setChannel(channelId: String): Unit = {
sourceConnector.get.getTextChannel(channelId) match {
case Some(_) => this.channelId = channelId
case Some(_) => this.channelId = Some(channelId.trim)
case None => throw new IllegalArgumentException("Channel with that id doesn't exist")
}
}

override def getChannelId: String = channelId
override def getChannelId: String = channelId.get

override def init(): Boolean = {
if (sourceConnector.isDefined) {
if (sourceConnector.get.isRunning || sourceConnector.get.init()) {
setChannel(getSourceIdentifier)
true
} else false
} else {
logger warn "Source Connector not set."
false
}
}

override def sendChatMessage(message: String): Unit = sourceConnector.get.sendChatMessage(channelId, message)

override def serialize(): String = getSourceIdentifier

override def deserialize(value: String): Unit = {
setSourceConnector(value)
override def sendChatMessage(message: String): Unit = {
val channel = channelId.getOrElse(throw new IllegalStateException("first set the channel for this output"))
sourceConnector.get.sendChatMessage(channel, message)
}
}
Expand Up @@ -6,6 +6,8 @@ import org.pircbotx.cap.EnableCapHandler
import org.pircbotx.hooks.events.{MessageEvent, UnknownEvent}
import org.pircbotx.{Configuration, PircBotX}

import scala.collection.mutable.ListBuffer

/**
* The twitch connector connects to the irc service to work with chat messages.
*
Expand All @@ -17,7 +19,7 @@ class TwitchChatConnector(override val sourceIdentifier: String) extends Connect
override protected var requiredCredentialKeys: List[String] = List(oauthKey)
override protected var optionalCredentialKeys: List[String] = List()
private var bot: PircBotX = _
private var currentChannel: String = _
private val channels = ListBuffer[String]()

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

def setChannel(channel: String): Unit = {
// Todo: Leave channel
setCurrentChannel(channel)
bot.send().joinChannel(currentChannel)
// TODO: TEST!
def joinChannel(channel: String): Unit = {
bot.send().joinChannel(channel)
channels += channel
}

private def setCurrentChannel(channel: String): Unit = {
if (channel.startsWith("#")) {
currentChannel = channel.toLowerCase
} else {
currentChannel = "#" + channel.toLowerCase
}
}
def isJoined(channel: String): Boolean = channels.contains(channel)

override def getUniqueTypeString: String = this.getClass.getName

def sendChatMessage(chatMessage: String): Unit = bot.send().message(currentChannel, chatMessage)
def sendChatMessage(channel: String, chatMessage: String): Unit = {
if (!isJoined(channel)) throw new IllegalArgumentException(s"you must join the '$channel' channel, before you can send messages to it")
bot.send().message(channel, chatMessage)
}

private def getConfig: Configuration = {

Expand All @@ -56,8 +53,6 @@ class TwitchChatConnector(override val sourceIdentifier: String) extends Connect
logger warn s"key '$oauthKey' not found in credentials for '$sourceIdentifier'."
}

setCurrentChannel(sourceIdentifier)

new Configuration.Builder()
.setAutoNickChange(false)
.setOnJoinWhoEnabled(false)
Expand All @@ -67,7 +62,6 @@ class TwitchChatConnector(override val sourceIdentifier: String) extends Connect
.addServer("irc.chat.twitch.tv")
.setName(credentials.get.credentialsIdentifier)
.setServerPassword(password.getOrElse(""))
.addAutoJoinChannel(currentChannel)
.addListener(twitchChatListener)
.buildConfiguration()
} else {
Expand Down
Expand Up @@ -30,35 +30,39 @@ class TwitchChatInputImpl extends InputImpl[chat.TwitchChatConnector] with Twitc
private val messageHandler = ListBuffer[Consumer[TwitchChatMessage]]()
private val privateMessageHandler = ListBuffer[Consumer[TwitchChatMessage]]()

private var currentChannel: Option[String] = None

override def start(): Boolean = {
sourceConnector.get.addMessageEventListener(onMessage)
sourceConnector.get.addUnknownEventListener(onUnknown)
true
}

private def onMessage(event: MessageEvent): Unit = {
val message = event.getMessage
val color = if (event.getV3Tags.get("color").contains("#")) event.getV3Tags.get("color") else ""
val subscriber = event.getV3Tags.get("subscriber") == "1"
val moderator = event.getV3Tags.get("mod") == "1"
val broadcaster = event.getV3Tags.get("badges").contains("broadcaster/1")
val turbo = event.getV3Tags.get("badges").contains("turbo/1")
val author = new TwitchChatMessageAuthor(event.getUser.getNick,color, broadcaster, moderator, subscriber, turbo)
val channel = new Channel(event.getChannelSource)
val emoticons = new java.util.ArrayList[ChatEmoticon]()
wholeEmoticonRegex.findAllMatchIn(event.getV3Tags.get("emotes")).foreach(matchedElement => {
val id = matchedElement.group(1)
emoticonRegex.findAllMatchIn(matchedElement.group(2)).foreach(matchedElement => {
val index = matchedElement.group(1).toInt
val regex = message.substring(index, matchedElement.group(2).toInt + 1)
val emoticon = new TwitchChatEmoticon(regex, id, index)
emoticons.add(emoticon)
if (currentChannel.isDefined && event.getChannelSource == currentChannel.get) {
val message = event.getMessage
val color = if (event.getV3Tags.get("color").contains("#")) event.getV3Tags.get("color") else ""
val subscriber = event.getV3Tags.get("subscriber") == "1"
val moderator = event.getV3Tags.get("mod") == "1"
val broadcaster = event.getV3Tags.get("badges").contains("broadcaster/1")
val turbo = event.getV3Tags.get("badges").contains("turbo/1")
val author = new TwitchChatMessageAuthor(event.getUser.getNick, color, broadcaster, moderator, subscriber, turbo)
val channel = new Channel(event.getChannelSource)
val emoticons = new java.util.ArrayList[ChatEmoticon]()
wholeEmoticonRegex.findAllMatchIn(event.getV3Tags.get("emotes")).foreach(matchedElement => {
val id = matchedElement.group(1)
emoticonRegex.findAllMatchIn(matchedElement.group(2)).foreach(matchedElement => {
val index = matchedElement.group(1).toInt
val regex = message.substring(index, matchedElement.group(2).toInt + 1)
val emoticon = new TwitchChatEmoticon(regex, id, index)
emoticons.add(emoticon)
})
})
})
val msg = new TwitchChatMessage(author, message, event.getTimestamp, channel, emoticons)
val msg = new TwitchChatMessage(author, message, event.getTimestamp, channel, emoticons)

messageHandler.foreach(consumer => consumer.accept(msg))
messages += msg
messageHandler.foreach(consumer => consumer.accept(msg))
messages += msg
}
}

private def onUnknown(event: UnknownEvent): Unit = {
Expand All @@ -76,6 +80,7 @@ class TwitchChatInputImpl extends InputImpl[chat.TwitchChatConnector] with Twitc
}

override def getLastMessages(lastMilliseconds: Long): java.util.List[TwitchChatMessage] = {
if (currentChannel.isEmpty) throw new IllegalStateException("first set the channel for this input")
val currentTime = Calendar.getInstance.getTimeInMillis

messages.filter(_.getTimestamp > currentTime - lastMilliseconds).toList.asJava
Expand All @@ -88,10 +93,15 @@ class TwitchChatInputImpl extends InputImpl[chat.TwitchChatConnector] with Twitc
privateMessages.filter(_.getTimestamp > currentTime - lastMilliseconds).toList.asJava
}

override def registerMessageHandler(handler: Consumer[TwitchChatMessage]): Unit = messageHandler += handler
override def registerMessageHandler(handler: Consumer[TwitchChatMessage]): Unit = {
if (currentChannel.isEmpty) throw new IllegalStateException("first set the channel for this input")
messageHandler += handler
}

override def registerPrivateMessageHandler(handler: Consumer[TwitchChatMessage]): Unit = privateMessageHandler += handler

override def setChannel(channel: String): Unit = sourceConnector.get.setChannel(channel)

override def setChannel(channel: String): Unit = {
currentChannel = Some(channel.trim)
if (!sourceConnector.get.isJoined(channel.trim)) sourceConnector.get.joinChannel(channel.trim)
}
}

0 comments on commit 6d96407

Please sign in to comment.