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

Commit fd63da1

Browse files
Renxiemsebinside
authored andcommitted
Cherry picked ClassLibrary Rework from Andre.
1 parent 4481cf1 commit fd63da1

File tree

5 files changed

+189
-0
lines changed

5 files changed

+189
-0
lines changed

build.sbt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,18 @@ libraryDependencies += "org.pircbotx" % "pircbotx" % "2.1"
4747
// Reflections API for annotation indexing
4848
libraryDependencies += "org.reflections" % "reflections" % "0.9.11"
4949

50+
// Akka Actors
51+
libraryDependencies ++= Seq(
52+
"com.typesafe.akka" %% "akka-actor" % "2.5.18",
53+
//"com.typesafe.akka" %% "akka-testkit" % "2.5.18" % Test
54+
)
55+
56+
// Akka Actors
57+
libraryDependencies ++= Seq(
58+
"com.typesafe.akka" %% "akka-actor" % "2.5.18",
59+
//"com.typesafe.akka" %% "akka-testkit" % "2.5.18" % Test
60+
)
61+
5062

5163
// ---------------------------------------------------------------------------------------------------------------------
5264
// PLUGIN FRAMEWORK DEFINITIONS
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package org.codeoverflow.chatoverflow.framework
2+
3+
import org.apache.http.client.methods.HttpGet
4+
import org.apache.http.impl.client.HttpClientBuilder
5+
6+
class HttpClientActor extends Actor {
7+
private val client = HttpClientBuilder.create.build
8+
9+
override def receive: Receive = {
10+
case httpGet: HttpGet => sender ! client.execute(httpGet).getEntity
11+
}
12+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package org.codeoverflow.chatoverflow.framework
2+
3+
case class Mapping(mapFunc: (String => Any), content: String)
4+
5+
class StringMappingActor extends Actor {
6+
7+
override def receive: Receive = {
8+
case m: Mapping => sender ! m.mapFunc(m.content)
9+
}
10+
}
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
package org.codeoverflow.chatoverflow.service.twitch
2+
3+
import org.apache.http.HttpEntity
4+
import org.apache.http.client.methods.HttpGet
5+
import org.apache.http.client.utils.URIBuilder
6+
import org.apache.http.util.EntityUtils
7+
import org.apache.log4j.Logger
8+
import org.codeoverflow.chatoverflow.configuration.Credentials
9+
import org.codeoverflow.chatoverflow.framework.HttpClientActor
10+
11+
import scala.concurrent.Await
12+
import scala.concurrent.duration._
13+
14+
/**
15+
* The twitch api connector
16+
*
17+
* @param sourceIdentifier the name to the twitch account
18+
* @param credentials the credentials to log into the twitch api
19+
*/
20+
class TwitchAPIConnector(override val sourceIdentifier: String, credentials: Credentials) extends Connector(sourceIdentifier, credentials) {
21+
private val logger = Logger.getLogger(this.getClass)
22+
private val API_FORMAT: String = "application/vnd.twitchtv.v5+json"
23+
private val BASE_URL: String = "https://api.twitch.tv/helix/"
24+
private val BASE_URL_v5: String = "https://api.twitch.tv/kraken/"
25+
private val actorSystem = ActorSystem("TwitchAPIActorSystem")
26+
private val actor: ActorRef = actorSystem.actorOf(Props[HttpClientActor])
27+
private var clientID = ""
28+
private var oauth = ""
29+
30+
override def getUniqueTypeString: String = this.getClass.getName
31+
32+
/**
33+
* Returns true, if the connector has been already instantiated and is running.
34+
*/
35+
override def isRunning: Boolean = true
36+
37+
/**
38+
* Initializes the connector, e.g. creates a connection with its platform.
39+
*/
40+
override def init(): Unit = {
41+
val oauth = credentials.getValue(TwitchAPIConnector.credentialsOauthKey)
42+
val clientID = credentials.getValue(TwitchAPIConnector.credentialsClientID)
43+
44+
if (clientID.isEmpty) {
45+
logger warn s"key '${TwitchAPIConnector.credentialsClientID}' not found in credentials for '$sourceIdentifier'."
46+
} else {
47+
this.clientID = clientID.get
48+
if (oauth.isEmpty) {
49+
logger warn s"key '${TwitchAPIConnector.credentialsOauthKey}' not found in credentials for '$sourceIdentifier'."
50+
} else {
51+
this.oauth = oauth.get
52+
}
53+
}
54+
}
55+
56+
def getSubscriptions(channelID: String, offset: Int = 0, newestFirst: Boolean = true) = {
57+
get("channels/" + channelID + "/subscriptions", true, true, Seq(("limit", "100"), ("offset", String.valueOf(offset)), ("direction", if (newestFirst) "desc" else "asc")))
58+
}
59+
60+
def getUser(userLogin: String) = {
61+
get("users", false, false, Seq(("login", userLogin)))
62+
}
63+
64+
def get(uri: String, auth: Boolean, oldAPI: Boolean, queryParams: Seq[(String, String)]) = {
65+
val httpGet = if (auth) getUrlAuth(uri, oldAPI) else getURL(uri, oldAPI)
66+
val urlBuilder = new URIBuilder(httpGet.getURI)
67+
queryParams.foreach(param => urlBuilder.addParameter(param._1, param._2))
68+
httpGet.setURI(urlBuilder.build())
69+
implicit val timeout: Timeout = Timeout(5 seconds)
70+
val entity = Await.result(actor ? httpGet, timeout.duration).asInstanceOf[HttpEntity]
71+
if (entity != null) {
72+
EntityUtils.toString(entity, "UTF-8");
73+
}
74+
else ""
75+
}
76+
77+
def getUrlAuth(uri: String, oldAPI: Boolean) = {
78+
val get = getURL(uri, oldAPI)
79+
get.setHeader("Authorization", oauth)
80+
get
81+
}
82+
83+
def getURL(uri: String, oldAPI: Boolean) = {
84+
val baseUrl = if (oldAPI) BASE_URL_v5 else BASE_URL
85+
new HttpGet(baseUrl + uri) {
86+
setHeader("Accept", API_FORMAT)
87+
setHeader("Client-ID", clientID)
88+
}
89+
}
90+
91+
def getFollowers(userID: String) = {
92+
get("users/follows", false, false, Seq(("to_id", userID)))
93+
}
94+
95+
/**
96+
* Shuts down the connector, closes its platform connection.
97+
*/
98+
override def shutdown(): Unit = ???
99+
}
100+
101+
object TwitchAPIConnector {
102+
val credentialsOauthKey = "oauth"
103+
val credentialsClientID = "clientid"
104+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package org.codeoverflow.chatoverflow.service.twitch.stat.impl
2+
3+
import com.fasterxml.jackson.databind.ObjectMapper
4+
import org.codeoverflow.chatoverflow.framework.{Mapping, StringMappingActor}
5+
import org.codeoverflow.chatoverflow.service.twitch.TwitchAPIConnector
6+
7+
import scala.concurrent.Await
8+
import scala.concurrent.duration._
9+
10+
case class UserResult(data: Seq[UserEntity])
11+
12+
case class UserEntity(id: String, login: String, display_name: String, `type`: String, broadcaster_type: String, description: String, profile_image_url: String, offline_image_url: String, view_count: Int)
13+
14+
class TwitchStatInputImpl extends Connection[TwitchAPIConnector] with TwitchStatInput {
15+
private val actorSystem = ActorSystem("TwitchAPIActorSystem")
16+
private val actor: ActorRef = actorSystem.actorOf(Props[StringMappingActor])
17+
implicit val timeout: Timeout = Timeout(5 seconds)
18+
19+
override def init(): Unit = {
20+
sourceConnector.init()
21+
}
22+
23+
override def getFollowers(userName: String): java.util.List[User] = {
24+
val userID = getUser(userName).getId
25+
val response = sourceConnector.getFollowers(userID)
26+
println(response)
27+
null
28+
}
29+
30+
override def getUser(userName: String): User = {
31+
val response = sourceConnector.getUser(userName)
32+
println(response)
33+
val result = Await.result(actor ? Mapping(map[UserResult], response), timeout.duration).asInstanceOf[UserResult]
34+
if (result.data.nonEmpty) {
35+
val user = result.data.head
36+
new User(user.id, user.display_name, user.description, user.profile_image_url, user.view_count)
37+
}
38+
else null
39+
}
40+
41+
def map[T: Manifest](content: String): Any = {
42+
val mapper = new ObjectMapper() with ScalaObjectMapper
43+
mapper.registerModule(DefaultScalaModule)
44+
mapper.readValue[T](content)
45+
}
46+
47+
override def getSubscribers(userName: String): String = {
48+
val userID = getUser(userName).getId
49+
sourceConnector.getSubscriptions(userID)
50+
}
51+
}

0 commit comments

Comments
 (0)