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

Commit c17b66b

Browse files
committed
Merged branch master.
2 parents 8c4e81f + 4fbb87a commit c17b66b

25 files changed

+868
-152
lines changed

.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,7 @@ project/plugins/project/
3333
/bin/
3434
/lib/
3535
/deploy/
36-
/wiki/
36+
/wiki/
37+
38+
# Plugin Data
39+
data/

build.sbt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,12 @@ libraryDependencies ++= Seq(
5757
// Google GSON
5858
libraryDependencies += "com.google.code.gson" % "gson" % "2.8.5"
5959

60+
// JDA
61+
resolvers += "jcenter-bintray" at "http://jcenter.bintray.com"
62+
libraryDependencies += "net.dv8tion" % "JDA" % "4.ALPHA.0_82"
63+
64+
//Serial Communication
65+
libraryDependencies += "com.fazecast" % "jSerialComm" % "[2.0.0,3.0.0)"
6066

6167
// ---------------------------------------------------------------------------------------------------------------------
6268
// PLUGIN FRAMEWORK DEFINITIONS

src/main/scala/org/codeoverflow/chatoverflow/configuration/ConfigurationService.scala

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package org.codeoverflow.chatoverflow.configuration
22

3-
import java.io.File
3+
import java.io.{File, PrintWriter}
44

55
import org.codeoverflow.chatoverflow.WithLogger
66
import org.codeoverflow.chatoverflow.api.io
@@ -10,7 +10,7 @@ import org.codeoverflow.chatoverflow.framework.PluginFramework
1010
import org.codeoverflow.chatoverflow.instance.PluginInstanceRegistry
1111
import org.codeoverflow.chatoverflow.registry.TypeRegistry
1212

13-
import scala.xml.{Elem, Node}
13+
import scala.xml.{Elem, Node, PrettyPrinter}
1414

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

src/main/scala/org/codeoverflow/chatoverflow/connector/Connector.scala

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
package org.codeoverflow.chatoverflow.connector
22

3+
34
import akka.actor.{Actor, ActorRef, ActorSystem, Props}
45
import akka.pattern.ask
56
import akka.util.Timeout
67
import org.codeoverflow.chatoverflow.WithLogger
78
import org.codeoverflow.chatoverflow.configuration.Credentials
9+
import org.codeoverflow.chatoverflow.connector.actor.ActorMessage
810

911
import scala.concurrent.duration._
1012
import scala.concurrent.{Await, TimeoutException}
@@ -16,7 +18,7 @@ import scala.reflect.ClassTag
1618
* @param sourceIdentifier the unique source identifier (e.g. a login name), the connector should work with
1719
*/
1820
abstract class Connector(val sourceIdentifier: String) extends WithLogger {
19-
private[this] val actorSystem = ActorSystem(s"${getUniqueTypeString.replace('.', '-')}")
21+
private[this] val actorSystem: ActorSystem = ActorSystem(s"${getUniqueTypeString.replace('.', '-')}")
2022
private val connectorSourceAndType = s"connector '$sourceIdentifier' of type '$getUniqueTypeString'"
2123
protected var credentials: Option[Credentials] = None
2224
protected var requiredCredentialKeys: List[String]
@@ -68,8 +70,8 @@ abstract class Connector(val sourceIdentifier: String) extends WithLogger {
6870

6971
// Check if running
7072
if (running) {
71-
logger warn s"Unable to start $connectorSourceAndType. Already running!"
72-
false
73+
logger info s"Unable to start $connectorSourceAndType. Already running!"
74+
true
7375
} else {
7476

7577
// Check if credentials object exists
@@ -94,6 +96,7 @@ abstract class Connector(val sourceIdentifier: String) extends WithLogger {
9496

9597
if (start()) {
9698
logger info s"Started $connectorSourceAndType."
99+
running = true
97100
true
98101
} else {
99102
logger warn s"Failed starting $connectorSourceAndType."
@@ -149,7 +152,7 @@ abstract class Connector(val sourceIdentifier: String) extends WithLogger {
149152
* @tparam T result type of the actor answer
150153
* @return the answer of the actor if he answers in time. else: None
151154
*/
152-
def askActor[T](actor: ActorRef, timeOutInSeconds: Int, message: Any): Option[T] = {
155+
def askActor[T](actor: ActorRef, timeOutInSeconds: Int, message: ActorMessage): Option[T] = {
153156
implicit val timeout: Timeout = Timeout(timeOutInSeconds seconds)
154157
val future = actor ? message
155158
try {
@@ -167,4 +170,25 @@ abstract class Connector(val sourceIdentifier: String) extends WithLogger {
167170
*/
168171
protected def createActor[T <: Actor : ClassTag](): ActorRef =
169172
actorSystem.actorOf(Props(implicitly[ClassTag[T]].runtimeClass))
173+
174+
implicit def toRichActorRef(actorRef: ActorRef): RichActorRef = new RichActorRef(actorRef)
175+
176+
class RichActorRef(actorRef: ActorRef) {
177+
178+
/**
179+
* Syntactic sugar for the askActor()-function. Works like this:
180+
* <code>anActor.??[String](5) {
181+
* // message goes here
182+
* }</code>
183+
*
184+
* @param timeOutInSeconds the timeout to calculate, request, ... for the actor
185+
* @param message some message to pass to the actor. Can be anything.
186+
* @tparam T result type of the actor answer
187+
* @return the answer of the actor if he answers in time. else: None
188+
*/
189+
def ??[T](timeOutInSeconds: Int)(message: ActorMessage): Option[T] = {
190+
askActor[T](actorRef, timeOutInSeconds, message)
191+
}
192+
}
193+
170194
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
package org.codeoverflow.chatoverflow.connector.actor
2+
3+
trait ActorMessage
Lines changed: 42 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
package org.codeoverflow.chatoverflow.connector.actor
22

3-
import java.io.PrintWriter
3+
import java.io.{File, PrintWriter}
44
import java.nio.file.Paths
55

66
import akka.actor.Actor
7+
import org.codeoverflow.chatoverflow.connector.actor.FileSystemActor.{CreateDirectory, LoadFile, SaveFile}
78

89
import scala.io.Source
910

@@ -12,8 +13,14 @@ import scala.io.Source
1213
*/
1314
class FileSystemActor extends Actor {
1415

15-
// TODO: Subject of change?
16-
private val resourceFilePath = "src/main/resources"
16+
// TODO: Should be an startup option in the CLI
17+
private val dataFilePath = "data"
18+
19+
// Create data folder if non existent
20+
private val dataFolder = new File(dataFilePath)
21+
if (!dataFolder.exists()) {
22+
dataFolder.mkdir()
23+
}
1724

1825
/**
1926
* Receives either LoadFile or SaveFile object, acts accordingly.
@@ -23,19 +30,25 @@ class FileSystemActor extends Actor {
2330
override def receive: Receive = {
2431
case LoadFile(pathInResources) =>
2532
try {
26-
sender ! Some(Source.fromFile(s"$resourceFilePath${fixPath(pathInResources)}").mkString)
33+
sender ! Some(Source.fromFile(s"$dataFilePath${fixPath(pathInResources)}").mkString)
2734
} catch {
2835
case _: Exception => None
2936
}
3037
case SaveFile(pathInResources, content) =>
3138
try {
32-
val writer = new PrintWriter(s"$resourceFilePath${fixPath(pathInResources)}")
39+
val writer = new PrintWriter(s"$dataFilePath${fixPath(pathInResources)}")
3340
writer.write(content)
3441
writer.close()
3542
sender ! true
3643
} catch {
3744
case _: Exception => sender ! false
3845
}
46+
case CreateDirectory(folderName) =>
47+
try {
48+
sender ! new File(s"$dataFilePath${fixPath(folderName)}").mkdir()
49+
} catch {
50+
case _: Exception => sender ! false
51+
}
3952
}
4053

4154
private def fixPath(path: String): String = {
@@ -44,17 +57,28 @@ class FileSystemActor extends Actor {
4457
}
4558
}
4659

47-
/**
48-
* Send a LoadFile-object to the FileSystemActor to load a specific file.
49-
*
50-
* @param pathInResources the relative Path in the resource folder
51-
*/
52-
case class LoadFile(pathInResources: String)
60+
object FileSystemActor {
5361

54-
/**
55-
* Send a SaveFile-object to the FileSystemActor to save a file with given content.
56-
*
57-
* @param pathInResources the relative Path in the resource folder
58-
* @param content the content to save
59-
*/
60-
case class SaveFile(pathInResources: String, content: String)
62+
/**
63+
* Send a LoadFile-object to the FileSystemActor to load a specific file.
64+
*
65+
* @param pathInResources the relative Path in the resource folder
66+
*/
67+
case class LoadFile(pathInResources: String) extends ActorMessage
68+
69+
/**
70+
* Send a SaveFile-object to the FileSystemActor to save a file with given content.
71+
*
72+
* @param pathInResources the relative Path in the resource folder
73+
* @param content the content to save
74+
*/
75+
case class SaveFile(pathInResources: String, content: String) extends ActorMessage
76+
77+
/**
78+
* Send a CreateDirectory-object to the FileSystemActor to create a new sub directory.
79+
*
80+
* @param folderName the folder name. Note: Parent folder has to exist!
81+
*/
82+
case class CreateDirectory(folderName: String) extends ActorMessage
83+
84+
}

src/main/scala/org/codeoverflow/chatoverflow/connector/actor/HttpActor.scala

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import org.apache.http.client.methods.HttpGet
55
import org.apache.http.client.utils.URIBuilder
66
import org.apache.http.impl.client.HttpClientBuilder
77
import org.apache.http.util.EntityUtils
8+
import org.codeoverflow.chatoverflow.connector.actor.HttpActor.GetRequest
89

910
/**
1011
* The HttpActor can be used to handle http requests.
@@ -39,13 +40,17 @@ class HttpActor extends Actor {
3940
}
4041
}
4142

42-
/**
43-
* A get request consists of a URI at least. Http (e.g. header) settings and query parameters are optional.
44-
*
45-
* @param uri the web address incl. the protocol you want to request
46-
* @param settings a function manipulating the generated HttpGet-Element, e.g. by adding header-entries
47-
* @param queryParams the query params as sequence of key-value-tuple
48-
*/
49-
case class GetRequest(uri: String,
50-
settings: HttpGet => HttpGet = httpGet => httpGet,
51-
queryParams: Seq[(String, String)] = Seq[(String, String)]())
43+
object HttpActor {
44+
45+
/**
46+
* A get request consists of a URI at least. Http (e.g. header) settings and query parameters are optional.
47+
*
48+
* @param uri the web address incl. the protocol you want to request
49+
* @param settings a function manipulating the generated HttpGet-Element, e.g. by adding header-entries
50+
* @param queryParams the query params as sequence of key-value-tuple
51+
*/
52+
case class GetRequest(uri: String,
53+
settings: HttpGet => HttpGet = httpGet => httpGet,
54+
queryParams: Seq[(String, String)] = Seq[(String, String)]()) extends ActorMessage
55+
56+
}
Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,38 @@
11
package org.codeoverflow.chatoverflow.connector.actor
22

33
import akka.actor.Actor
4-
import com.google.gson.{JsonObject, JsonParser}
4+
import org.codeoverflow.chatoverflow.connector.actor.JsonActor.ParseJSON
5+
import org.json4s._
6+
import org.json4s.jackson.JsonMethods._
57

68
/**
7-
* The JSON Actor uses Google GSON to parse serialized json and enable traversing.
9+
* The JSON Actor uses json4s to parse serialized json and enable traversing.
810
*/
911
class JsonActor extends Actor {
10-
val parser = new JsonParser
12+
13+
// TODO: Implement proper functionality with json4s. This is not more than a proof of concept
14+
// TODO: Test, when reflection kicks in to allow the most functionality without an actor call
1115

1216
/**
1317
* Receives a ParseJSON Object to start parsing.
1418
*
1519
* @return the desired values, can be any type
1620
*/
1721
override def receive: Receive = {
18-
case ParseJSON(json, parse) =>
19-
val rootObject = parser.parse(json).getAsJsonObject
20-
parse(rootObject)
22+
case ParseJSON(json, parseMethod) =>
23+
val rootObject = parse(json)
24+
sender ! parseMethod(rootObject)
2125
}
2226
}
2327

24-
/**
25-
* Send a ParseJSON-object to start parsing. The traversal is custom.
26-
*
27-
* @param json the serialized json string
28-
* @param parse a function what should happen with the parsed json. Return type is any
29-
*/
30-
case class ParseJSON(json: String, parse: JsonObject => Any)
28+
object JsonActor {
29+
30+
/**
31+
* Send a ParseJSON-object to start parsing. The traversal is custom.
32+
*
33+
* @param json the serialized json string
34+
* @param parseMethod a function what should happen with the parsed json. Return type is any
35+
*/
36+
case class ParseJSON(json: String, parseMethod: JValue => Any) extends ActorMessage
37+
38+
}

src/main/scala/org/codeoverflow/chatoverflow/connector/actor/PrivilegedActor.scala

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package org.codeoverflow.chatoverflow.connector.actor
22

33
import akka.actor.Actor
4+
import org.codeoverflow.chatoverflow.connector.actor.PrivilegedActor.Privileged
45

56
/**
67
* The privileged actor is the most general idea of an actor to handle privileged actions.
@@ -18,10 +19,14 @@ class PrivilegedActor extends Actor {
1819
}
1920
}
2021

21-
/**
22-
* Send a Privileged-ojbect to the PrivilegedActor to get the function executed with the given args.
23-
*
24-
* @param function a function of type T => Any
25-
* @param args the args for the function of type T
26-
*/
27-
case class Privileged(function: Any => Any, args: Any)
22+
object PrivilegedActor {
23+
24+
/**
25+
* Send a Privileged-ojbect to the PrivilegedActor to get the function executed with the given args.
26+
*
27+
* @param function a function of type T => Any
28+
* @param args the args for the function of type T
29+
*/
30+
case class Privileged(function: Any => Any, args: Any) extends ActorMessage
31+
32+
}

0 commit comments

Comments
 (0)