Skip to content

Instantly share code, notes, and snippets.

@tototoshi
Created May 19, 2012 04:11
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save tototoshi/2729029 to your computer and use it in GitHub Desktop.
Save tototoshi/2729029 to your computer and use it in GitHub Desktop.
finagle-http で Hello, world.
package com.github.tototoshi.finagle_hack
import java.net.InetSocketAddress
import com.twitter.finagle.{Service, SimpleFilter}
import com.twitter.util.Future
import com.twitter.finagle.builder.{Server, ServerBuilder}
import com.twitter.finagle.http._
import com.twitter.finagle.http.path._
object HTTPServer {
def main(args: Array[String]) = {
val service = new Service[Request, Response] {
def apply(request: Request) = {
val response = Response()
Path(request.path) match {
case Root / "name" / name =>
response.setContentString("Hello, %s!".format(name))
case _ =>
response.setContentString("Hello, world!")
}
Future.value(response)
}
}
val server: Server = {
val port = 8080
val _server = ServerBuilder()
.codec(RichHttp[Request](Http()))
.bindTo(new InetSocketAddress(port))
.name("Finagle hack!")
.build(service)
println("Server start up! port: %d".format(port))
_server
}
}
}
/*
$ curl localhost:8080
Hello, world!
$ curl localhost:8080/name/toshi
Hello, toshi!%
*/
package com.github.tototoshi.finagle_hack
import java.net.{ InetSocketAddress, URL }
import java.util.concurrent.ScheduledThreadPoolExecutor
import com.twitter.finagle.{Service, SimpleFilter}
import com.twitter.util.{ Future, FuturePool }
import com.twitter.finagle.builder.{Server, ServerBuilder}
import com.twitter.finagle.builder._
import com.twitter.finagle.http._
import com.twitter.finagle.http.path._
import com.twitter.finagle.http.service._
import org.jboss.netty.buffer.ChannelBuffers._
import scalax.io._
import com.github.tototoshi.selector.Selector
object GreetService extends Service[Request, Response] {
val futurePool = FuturePool(new ScheduledThreadPoolExecutor(3))
def apply(request: Request) = {
futurePool {
val response = Response()
Path(request.path) match {
case Root / "name" / name => response.setContentString("Hello, %s!".format(name))
case _ => response.setStatusCode(500)
}
response
}
}
}
object defaultService extends Service[Request, Response] {
val futurePool = FuturePool(new ScheduledThreadPoolExecutor(3))
def apply(request: Request) = {
futurePool {
val response = Response()
response.setContentString("Hello, world!")
response
}
}
}
object jigokuService extends Service[Request, Response] with ResponseTransformer {
def apply(request: Request): Future[Response] = {
val id = Path(request.path) match {
case Root / "jigoku" / id => id.toInt //TODO
case _ => throw new IllegalStateException
}
for {
img <- JigokunoClient.get(id)
} yield {
val res = Response()
res.setContent(copiedBuffer(responseToByteArray(img)))
res
}
}
}
object HTTPServer extends ResponseTransformer {
def main(args: Array[String]) = {
val router = RoutingService.byPathObject {
case Root / "name" / name => GreetService
case Root / "jigoku" / id => jigokuService
case _ => defaultService
}
val server: Server = {
val port = 8080
val _server = ServerBuilder()
.codec(RichHttp[Request](Http()))
.bindTo(new InetSocketAddress(port))
.name("Finagle hack!")
.build(router)
println("Server start up! port: %d".format(port))
_server
}
}
}
object SimpleHttpClient {
private def clientWithoutErrorHandling(host: String): Service[Request, Response] = ClientBuilder()
.codec(RichHttp[Request](Http()))
.hosts(new InetSocketAddress(host, 80))
.hostConnectionLimit(1)
.build()
private def requestGet(url: String) = Request(
RequestBuilder().url(new URL(url)).buildGet()
)
def GET(url: String): Future[Response] = {
val reg = """http://(.+?)/.*""".r
url match {
case reg(host) => clientWithoutErrorHandling(host)(requestGet(url))
case _ => throw new Exception
}
}
}
object JigokunoClient extends ResponseTransformer {
def get(i: Int): Future[Response] = {
for {
res1 <- SimpleHttpClient.GET("http://jigokuno.com/?cid=" + i)
imgUrl = HtmlParser.parse(responseToString(res1))
res2 <- SimpleHttpClient.GET(imgUrl)
} yield {
res2
}
}
}
// utilities
class HtmlParseException(message: String) extends Exception(message)
object HtmlParser {
import net.liftweb.util.Html5
def parse(html: String): String = {
val xml = Html5.parse(html).open_! //TODO
val $ = new Selector(xml)
if (($("div.entry img") \\ "@src").isEmpty) {
throw new HtmlParseException("Parse failed")
} else {
($("div.entry img") \\ "@src" ).head.text
}
}
}
trait ResponseTransformer {
def responseToByteArray(response: Response): Array[Byte] =
Resource.fromInputStream(response.getInputStream).byteArray
def responseToString(response: Response): String =
Resource.fromInputStream(response.getInputStream).slurpString
}
object SimpleHttpClient {
private val clientWithoutErrorHandling: Service[Request, Response] = ClientBuilder()
.codec(RichHttp[Request](Http()))
.hosts(new InetSocketAddress(80))
.hostConnectionLimit(1)
.build()
private def requestGet(url: String) = Request(
RequestBuilder().url(new URL(url)).buildGet()
)
def GET(url: String): Future[Response] = clientWithoutErrorHandling(requestGet(url))
}
package com.github.tototoshi.finagle_hack
import java.net.InetSocketAddress
import com.twitter.finagle.{Service, SimpleFilter}
import com.twitter.util.Future
import com.twitter.finagle.builder.{Server, ServerBuilder}
import com.twitter.finagle.http._
import com.twitter.finagle.http.path._
import com.twitter.finagle.http.service._
object HTTPServer {
def main(args: Array[String]) = {
val nameService = new Service[Request, Response] {
def apply(request: Request) = {
val response = Response()
Path(request.path) match {
case Root / "name" / name =>
response.setContentString("Hello, %s!".format(name))
case _ => response.setContentString("Oops!")
}
Future.value(response)
}
}
val defaultService = new Service[Request, Response] {
def apply(request: Request) = {
val response = Response()
Path(request.path) match {
case _ => response.setContentString("Hello, world!")
}
Future.value(response)
}
}
val router = RoutingService.byPath {
case path if path.startsWith("/name") => nameService
case _ => defaultService
}
val server: Server = {
val port = 8080
val _server = ServerBuilder()
.codec(RichHttp[Request](Http()))
.bindTo(new InetSocketAddress(port))
.name("Finagle hack!")
.build(router)
println("Server start up! port: %d".format(port))
_server
}
}
}
/*
$ curl localhost:8080
Hello, world!
$ curl localhost:8080/name/toshi
Hello, toshi!%
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment