Skip to content

Commit 3a52e4d

Browse files
Merge pull request code-check#57 from code-check/transport
Add async-http-client 2.0 support
2 parents 3e83ad3 + e815f88 commit 3a52e4d

File tree

12 files changed

+190
-41
lines changed

12 files changed

+190
-41
lines changed

build.sbt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,14 @@ organization := "io.code-check"
22

33
name := """github-api"""
44

5-
version := "0.1.2-SNAPSHOT"
5+
version := "0.2.0-SNAPSHOT"
66

77
scalaVersion := "2.11.7"
88

99
// Change this to another test framework if you prefer
1010
libraryDependencies ++= Seq(
11-
"com.ning" % "async-http-client" % "1.9.21",
11+
"com.ning" % "async-http-client" % "1.9.21" % "provided",
12+
"org.asynchttpclient" % "async-http-client" % "2.0.15" % "provided",
1213
"org.json4s" %% "json4s-jackson" % "3.3.0",
1314
"org.json4s" %% "json4s-ext" % "3.3.0",
1415
"joda-time" % "joda-time" % "2.8.1",

project/build.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
#Activator-generated Properties
22
#Tue Apr 07 19:20:09 JST 2015
33
template.uuid=d9b4f0bf-a417-4065-80af-1184e996ed95
4-
sbt.version=0.13.7
4+
sbt.version=0.13.11

src/main/scala/codecheck/github/api/GitHubAPI.scala

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
package codecheck.github.api
22

3-
import com.ning.http.client.AsyncHttpClient
4-
import com.ning.http.client.AsyncCompletionHandler
5-
import com.ning.http.client.Response
63
import scala.concurrent.Promise
74
import scala.concurrent.Future
85
import scala.concurrent.Await
@@ -19,8 +16,9 @@ import codecheck.github.exceptions.UnauthorizedException
1916
import codecheck.github.exceptions.GitHubAPIException
2017
import codecheck.github.operations._
2118
import codecheck.github.models.User
19+
import codecheck.github.transport._
2220

23-
class GitHubAPI(token: String, client: AsyncHttpClient, tokenType: String = "token", debugHandler: DebugHandler = NoneHandler) extends UserOp
21+
class GitHubAPI(token: String, client: Transport, tokenType: String = "token", debugHandler: DebugHandler = NoneHandler) extends UserOp
2422
with OrganizationOp
2523
with RepositoryOp
2624
with LabelOp
@@ -61,10 +59,10 @@ class GitHubAPI(token: String, client: AsyncHttpClient, tokenType: String = "tok
6159
request
6260
.setHeader("Content-Length", "0")
6361
}
64-
request.execute(new AsyncCompletionHandler[Response]() {
62+
request.execute(new CompletionHandler() {
6563
def onCompleted(res: Response) = {
66-
debugHandler.onResponse(res.getStatusCode, Option(res.getResponseBody))
67-
val json = Option(res.getResponseBody).filter(_.length > 0).map(parseJson(_)).getOrElse(JNothing)
64+
debugHandler.onResponse(res.getStatusCode, res.getResponseBody)
65+
val json = res.getResponseBody.filter(_.length > 0).map(parseJson(_)).getOrElse(JNothing)
6866
res.getStatusCode match {
6967
case 401 =>
7068
deferred.failure(new UnauthorizedException(json))
@@ -78,11 +76,9 @@ class GitHubAPI(token: String, client: AsyncHttpClient, tokenType: String = "tok
7876
val result = APIResult(res.getStatusCode, json)
7977
deferred.success(result)
8078
}
81-
res
8279
}
83-
override def onThrowable(t: Throwable) {
80+
def onThrowable(t: Throwable) {
8481
deferred.failure(t)
85-
super.onThrowable(t)
8682
}
8783
})
8884
deferred.future
@@ -99,14 +95,9 @@ class GitHubAPI(token: String, client: AsyncHttpClient, tokenType: String = "tok
9995

10096
object GitHubAPI {
10197

102-
def fromEnv: GitHubAPI = {
103-
implicit val client = new AsyncHttpClient
104-
apply(sys.env("GITHUB_TOKEN"))
105-
}
106-
107-
def apply(token: String)(implicit client: AsyncHttpClient): GitHubAPI = new GitHubAPI(token, client)
98+
def apply(token: String)(implicit client: Transport): GitHubAPI = new GitHubAPI(token, client)
10899

109-
def apply(username: String, password: String)(implicit client: AsyncHttpClient): GitHubAPI = {
100+
def apply(username: String, password: String)(implicit client: Transport): GitHubAPI = {
110101
val token = Base64.getEncoder.encodeToString((username + ":" + password).getBytes("utf-8"))
111102
new GitHubAPI(token, client, "Basic")
112103
}

src/main/scala/codecheck/github/api/OAuthAPI.scala

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,5 @@
11
package codecheck.github.api
22

3-
import com.ning.http.client.AsyncHttpClient
4-
import com.ning.http.client.AsyncCompletionHandler
5-
import com.ning.http.client.Response
6-
import com.ning.http.client.RequestBuilder
73
import java.net.URLEncoder
84
import scala.concurrent.Promise
95
import scala.concurrent.Future
@@ -12,8 +8,9 @@ import org.json4s.DefaultFormats
128
import java.util.UUID
139
import codecheck.github.models.AccessToken
1410
import codecheck.github.exceptions.OAuthAPIException
11+
import codecheck.github.transport._
1512

16-
class OAuthAPI(clientId: String, clientSecret: String, redirectUri: String, client: AsyncHttpClient) {
13+
class OAuthAPI(clientId: String, clientSecret: String, redirectUri: String, client: Transport) {
1714
private implicit val format = DefaultFormats
1815

1916
private val accessRequestUri = "https://github.com/login/oauth/authorize"
@@ -38,33 +35,31 @@ class OAuthAPI(clientId: String, clientSecret: String, redirectUri: String, clie
3835
"code" -> code,
3936
"redirect_uri" -> redirectUri
4037
)
41-
val builder: RequestBuilder = new RequestBuilder("POST")
38+
val request = client.preparePost(tokenRequestUri)
4239
.setHeader("Content-Type", "application/x-www-form-urlencoded")
4340
.setHeader("Accept", "application/json")
44-
.setFollowRedirects(true)
45-
.setUrl(tokenRequestUri)
46-
params.foreach { case (k, v) => builder.addFormParam(k, v) }
41+
.setFollowRedirect(true)
42+
params.foreach { case (k, v) => request.addFormParam(k, v) }
4743

4844
val deferred = Promise[AccessToken]()
49-
client.prepareRequest(builder.build).execute(new AsyncCompletionHandler[Response]() {
45+
request.execute(new CompletionHandler() {
5046
def onCompleted(res: Response) = {
51-
val json = JsonMethods.parse(res.getResponseBody("utf-8"))
47+
val body = res.getResponseBody.getOrElse("{\"error\": \"No response\"}")
48+
val json = JsonMethods.parse(body)
5249
(json \ "error").toOption match {
5350
case Some(_) => deferred.failure(new OAuthAPIException(json))
5451
case None => deferred.success(AccessToken(json))
5552
}
56-
res
5753
}
58-
override def onThrowable(t: Throwable) {
54+
def onThrowable(t: Throwable) {
5955
deferred.failure(t)
60-
super.onThrowable(t)
6156
}
6257
})
6358
deferred.future
6459
}
6560
}
6661

6762
object OAuthAPI {
68-
def apply(clientId: String, clientSecret: String, redirectUri: String)(implicit client: AsyncHttpClient) = new OAuthAPI(clientId, clientSecret, redirectUri, client)
63+
def apply(clientId: String, clientSecret: String, redirectUri: String)(implicit client: Transport) = new OAuthAPI(clientId, clientSecret, redirectUri, client)
6964

7065
}

src/main/scala/codecheck/github/app/Main.scala

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import scala.concurrent.Future
55
import scala.concurrent.ExecutionContext.Implicits.global
66
import codecheck.github.api.GitHubAPI
77
import codecheck.github.exceptions.UnauthorizedException
8+
import codecheck.github.transport.asynchttp19.AsyncHttp19Transport
89
import com.ning.http.client.AsyncHttpClient
910
import scopt.OptionParser
1011

@@ -25,10 +26,10 @@ object Main {
2526
val parser = new OptionParser[Config](appName) {
2627
head(appName, "0.1.0")
2728
opt[String]('u', "user") action { (x, c) =>
28-
c.copy(user=x)
29+
c.copy(user=x)
2930
} text("username for GitHub")
3031
opt[String]('p', "password") action { (x, c) =>
31-
c.copy(pass=x)
32+
c.copy(pass=x)
3233
} text("password")
3334
note(s"""
3435
|Shell for GitHub
@@ -47,7 +48,7 @@ object Main {
4748
config.userToken.orElse {
4849
sys.env.get("GITHUB_TOKEN").map(s => (s, "token"))
4950
}.map { case (token, tokenType) =>
50-
val client = new AsyncHttpClient()
51+
val client = new AsyncHttp19Transport(new AsyncHttpClient())
5152
val api = new GitHubAPI(token, client, tokenType)
5253
try {
5354
api.user
@@ -72,4 +73,4 @@ object Main {
7273
}
7374
}
7475

75-
}
76+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package codecheck.github.transport
2+
3+
trait CompletionHandler {
4+
5+
def onCompleted(res: Response): Unit
6+
def onThrowable(t: Throwable): Unit
7+
8+
}
9+
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package codecheck.github.transport
2+
3+
trait Request {
4+
def setBody(body: String): Request
5+
def setHeader(name: String, value: String): Request
6+
def setFollowRedirect(b: Boolean): Request
7+
def addFormParam(name: String, value: String): Request
8+
9+
def execute(handler: CompletionHandler): Unit
10+
}
11+
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package codecheck.github.transport
2+
3+
trait Response {
4+
5+
def getResponseBody: Option[String]
6+
def getStatusCode: Int
7+
}
8+
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package codecheck.github.transport
2+
3+
trait Transport {
4+
5+
def prepareGet(url: String): Request
6+
def preparePost(url: String): Request
7+
def preparePut(url: String): Request
8+
def prepareDelete(url: String): Request
9+
10+
def close: Unit
11+
}
12+
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package codecheck.github.transport.asynchttp19
2+
3+
import com.ning.http.client.{AsyncHttpClient, Response => AsyncHttpResponse, AsyncCompletionHandler}
4+
5+
import codecheck.github.transport.{Transport, Request, Response, CompletionHandler}
6+
7+
class AsyncHttp19Transport(client: AsyncHttpClient) extends Transport{
8+
9+
def prepareGet(url: String): Request = new AsyncHttp19Request(client.prepareGet(url))
10+
def preparePost(url: String): Request = new AsyncHttp19Request(client.preparePost(url))
11+
def preparePut(url: String): Request = new AsyncHttp19Request(client.preparePut(url))
12+
def prepareDelete(url: String): Request = new AsyncHttp19Request(client.prepareDelete(url))
13+
14+
def close: Unit = client.close()
15+
16+
}
17+
18+
class AsyncHttp19Request(request: AsyncHttpClient#BoundRequestBuilder) extends Request {
19+
20+
def setBody(body: String): Request = {
21+
request.setBody(body)
22+
this
23+
}
24+
25+
def setHeader(name: String, value: String): Request = {
26+
request.setHeader(name, value)
27+
this
28+
}
29+
30+
def setFollowRedirect(b: Boolean): Request = {
31+
request.setFollowRedirects(b)
32+
this
33+
}
34+
35+
def addFormParam(name: String, value: String): Request = {
36+
request.addFormParam(name, value)
37+
this
38+
}
39+
40+
def execute(handler: CompletionHandler): Unit = {
41+
request.execute(new AsyncCompletionHandler[AsyncHttpResponse]() {
42+
def onCompleted(res: AsyncHttpResponse) = {
43+
handler.onCompleted(new AsyncHttp19Response(res))
44+
res
45+
}
46+
override def onThrowable(t: Throwable) {
47+
handler.onThrowable(t)
48+
super.onThrowable(t)
49+
}
50+
})
51+
}
52+
}
53+
54+
class AsyncHttp19Response(response: AsyncHttpResponse) extends Response {
55+
56+
def getResponseBody: Option[String] = Option(response.getResponseBody())
57+
def getStatusCode: Int = response.getStatusCode
58+
}
59+
60+

0 commit comments

Comments
 (0)