Skip to content

Commit

Permalink
SubCut usage example
Browse files Browse the repository at this point in the history
  • Loading branch information
afiskon committed Aug 13, 2015
1 parent 1fc79e7 commit 08b2998
Show file tree
Hide file tree
Showing 6 changed files with 108 additions and 24 deletions.
1 change: 1 addition & 0 deletions build.sbt
Expand Up @@ -8,6 +8,7 @@ libraryDependencies ++= Seq(
"com.twitter" %% "finagle-http" % "6.27.0",
"ch.qos.logback" % "logback-classic" % "1.1.3",
"com.typesafe.scala-logging" %% "scala-logging" % "3.1.0",
"com.escalatesoft.subcut" %% "subcut" % "2.1",
"org.scalatest" %% "scalatest" % "2.2.4" % "test",
"org.pegdown" % "pegdown" % "1.5.0" % "test" // for scalatest html reports
)
Expand Down
8 changes: 8 additions & 0 deletions src/main/scala/me/eax/finagle_example/FinagleExample.scala
@@ -1,10 +1,18 @@
package me.eax.finagle_example

import com.escalatesoft.subcut.inject.NewBindingModule._
import com.twitter.finagle._
import com.twitter.finagle.http.{Http => _}
import com.twitter.util._
import me.eax.finagle_example.services._

object FinagleExample extends App {
implicit val bindings = newBindingModule { module =>
import module._

bind[KeyValueStorage] toSingle new KeyValueStorageImpl
}

val service = new FinagleServiceExample
val server = Http.serve(":8080", service)
Await.ready(server)
Expand Down
58 changes: 34 additions & 24 deletions src/main/scala/me/eax/finagle_example/FinagleServiceExample.scala
@@ -1,48 +1,58 @@
package me.eax.finagle_example

import me.eax.finagle_example.services._
import me.eax.finagle_example.utils._

import com.escalatesoft.subcut.inject.{Injectable, BindingModule}
import com.twitter.finagle.Service
import com.twitter.finagle.http.Response
import com.twitter.util.Future
import com.twitter.util.{Future => TwitterFuture}
import org.jboss.netty.handler.codec.http._
import org.jboss.netty.util.CharsetUtil

import com.typesafe.scalalogging._
import org.slf4j.LoggerFactory

import scala.collection.concurrent.TrieMap
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global

class FinagleServiceExample(implicit val bindingModule: BindingModule)
extends Service[HttpRequest, HttpResponse] with Injectable {

class FinagleServiceExample extends Service[HttpRequest, HttpResponse] {
private val kv = TrieMap.empty[String, String]
private val kv = inject[KeyValueStorage]
private val logger = Logger(LoggerFactory.getLogger(this.getClass))

logger.info(s"service started")

def apply(req: HttpRequest): Future[HttpResponse] = {
Future {
val resp = Response(req.getProtocolVersion, HttpResponseStatus.OK)
val key = req.getUri
def apply(req: HttpRequest): TwitterFuture[HttpResponse] = {
val resp = Response(req.getProtocolVersion, HttpResponseStatus.OK)
val key = req.getUri

req.getMethod match {
case HttpMethod.GET =>
logger.debug(s"reading $key")
kv.get(key) match {
req.getMethod match {
case HttpMethod.GET =>
logger.debug(s"reading $key")
for {
optValue <- kv.get(key)
} yield {
optValue match {
case None =>
resp.setStatus(HttpResponseStatus.NOT_FOUND)
case Some(value) =>
resp.setContentString(value)
}
case HttpMethod.POST =>
logger.debug(s"writing $key")
val value = req.getContent.toString(CharsetUtil.UTF_8)
kv.update(key, value)
case HttpMethod.DELETE =>
logger.debug(s"deleting $key")
kv.remove(key)
case _ =>
logger.error(s"bad request: $req")
resp.setStatus(HttpResponseStatus.BAD_REQUEST)
}
resp
resp
}
case HttpMethod.POST =>
logger.debug(s"writing $key")
val value = req.getContent.toString(CharsetUtil.UTF_8)
kv.update(key, value).map(_ => resp)
case HttpMethod.DELETE =>
logger.debug(s"deleting $key")
kv.remove(key).map(_ => resp)
case _ =>
logger.error(s"bad request: $req")
resp.setStatus(HttpResponseStatus.BAD_REQUEST)
Future.successful(resp)
}
}
}
@@ -0,0 +1,29 @@
package me.eax.finagle_example.services

import scala.collection.concurrent.TrieMap
import scala.concurrent._

trait KeyValueStorage {
def get(key: String): Future[Option[String]]
def update(key: String, value: String): Future[Unit]
def remove(key: String): Future[Unit]
}

class KeyValueStorageImpl extends KeyValueStorage {
private val kv = TrieMap.empty[String, String]

def get(key: String): Future[Option[String]] = {
val result = kv.get(key)
Future.successful(result)
}

def update(key: String, value: String): Future[Unit] = {
val result = kv.update(key, value)
Future.successful(result)
}

def remove(key: String): Future[Unit] = {
kv.remove(key)
Future.successful({})
}
}
28 changes: 28 additions & 0 deletions src/main/scala/me/eax/finagle_example/utils/package.scala
@@ -0,0 +1,28 @@
package me.eax.finagle_example

import scala.util._
import scala.concurrent._

package object utils {
implicit def scalaToTwitterTry[T](t: Try[T]): com.twitter.util.Try[T] = t match {
case Success(r) => com.twitter.util.Return(r)
case Failure(ex) => com.twitter.util.Throw(ex)
}

implicit def twitterToScalaTry[T](t: com.twitter.util.Try[T]): Try[T] = t match {
case com.twitter.util.Return(r) => Success(r)
case com.twitter.util.Throw(ex) => Failure(ex)
}

implicit def scalaToTwitterFuture[T](f: Future[T])(implicit ec: ExecutionContext): com.twitter.util.Future[T] = {
val promise = com.twitter.util.Promise[T]()
f.onComplete(promise update _)
promise
}

implicit def twitterToScalaFuture[T](f: com.twitter.util.Future[T]): Future[T] = {
val promise = Promise[T]()
f.respond(promise complete _)
promise.future
}
}
8 changes: 8 additions & 0 deletions src/test/scala/me/eax/finagle_example/tests/RestSpec.scala
@@ -1,14 +1,22 @@
package me.eax.finagle_example.tests

import com.escalatesoft.subcut.inject.NewBindingModule._
import com.twitter.finagle.{Http, Service}
import com.twitter.util.Await
import me.eax.finagle_example.FinagleServiceExample
import me.eax.finagle_example.services.{KeyValueStorageImpl, KeyValueStorage}
import org.jboss.netty.buffer.ChannelBuffers
import org.jboss.netty.handler.codec.http._
import org.jboss.netty.util.CharsetUtil
import org.scalatest._

class RestSpec extends FunSpec with Matchers {
implicit val bindings = newBindingModule { module =>
import module._

bind[KeyValueStorage] toSingle new KeyValueStorageImpl
}

val service = new FinagleServiceExample
val server = Http.serve(":8080", service)
val client: Service[HttpRequest, HttpResponse] = Http.newService("localhost:8080")
Expand Down

0 comments on commit 08b2998

Please sign in to comment.