All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.soundcloud.twinagle.Server.scala Maven / Gradle / Ivy

The newest version!
package com.soundcloud.twinagle

import com.twitter.finagle.Service
import com.twitter.finagle.http._
import com.twitter.finagle.stats.CancelledCategorizer
import com.twitter.util.Future

/** A Twirp-compatible HTTP server/router.
  * TwinagleExceptions are returned as conformant JSON responses, other exceptions are mapped
  * to twirp internal errors.
  *
  * @param endpoints list of protobuf RPCs to expose
  */
private[twinagle] class Server(endpoints: Seq[ProtoRpc], prefix: String) extends Service[Request, Response] {
  private val servicesByPath =
    endpoints.map(rpc => s"$prefix/${rpc.metadata.service}/${rpc.metadata.rpc}" -> rpc.svc).toMap

  override def apply(request: Request): Future[Response] =
    request.method match {
      case Method.Post =>
        servicesByPath.get(request.path) match {
          case Some(service) =>
            service(request).handle {
              case e: TwinagleException => errorResponse(e)
              case CancelledCategorizer(_) =>
                errorResponse(TwinagleException(ErrorCode.Canceled, "Request canceled by client"))
              case e => errorResponse(new TwinagleException(e))
            }
          case None =>
            Future.value(
              errorResponse(
                TwinagleException(
                  ErrorCode.BadRoute,
                  s"unknown path: ${request.path}"
                )
              )
            )
        }
      case method =>
        Future.value(
          errorResponse(
            TwinagleException(
              ErrorCode.BadRoute,
              s"unsupported method $method (only POST is allowed)"
            )
          )
        )
    }

  private def errorResponse(twex: TwinagleException): Response = {
    import ErrorCode._
    val resp = Response(twex.code match {
      case Canceled | DeadlineExceeded   => Status.RequestTimeout
      case NotFound | BadRoute           => Status.NotFound
      case PermissionDenied              => Status.Forbidden
      case ResourceExhausted             => Status.TooManyRequests
      case Unauthenticated               => Status.Unauthorized
      case FailedPrecondition            => Status.PreconditionFailed
      case AlreadyExists | Aborted       => Status.Conflict
      case InvalidArgument | OutOfRange  => Status.BadRequest
      case Unimplemented                 => Status.NotImplemented
      case Unknown | Internal | Dataloss => Status.InternalServerError
      case Unavailable                   => Status.ServiceUnavailable
    })
    resp.contentType = MediaType.Json
    resp.contentString = JsonError.toString(
      JsonError(
        code = twex.code.desc,
        msg = twex.msg,
        meta = if (twex.meta.nonEmpty) Some(twex.meta) else None
      )
    )
    resp
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy