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

io.hydrosphere.mist.master.HTTPService.scala Maven / Gradle / Ivy

package io.hydrosphere.mist.master

import akka.actor.ActorSystem
import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport
import akka.http.scaladsl.marshalling.ToResponseMarshallable
import akka.http.scaladsl.server.{Directives, Route}
import akka.stream.ActorMaterializer
import akka.pattern.{AskTimeoutException, ask}
import io.hydrosphere.mist.{Constants, Logger, MistConfig}
import spray.json.{DefaultJsonProtocol, JsArray, JsFalse, JsNumber, JsObject, JsString, JsTrue, JsValue, JsonFormat, deserializationError, serializationError}
import org.json4s.DefaultFormats
import org.json4s.native.Json
import io.hydrosphere.mist.jobs.{JobConfiguration, JobResult}

import scala.concurrent.ExecutionContext.Implicits.global
import scala.language.reflectiveCalls

private[mist] trait JsonFormatSupport extends DefaultJsonProtocol{
  /** We must implement json parse/serializer for [[Any]] type */
  implicit object AnyJsonFormat extends JsonFormat[Any] {
    def write(x: Any): JsValue = x match {
      case number: Int => JsNumber(number)
      case string: String => JsString(string)
      case sequence: Seq[_] => seqFormat[Any].write(sequence)
      case map: Map[String, _] => mapFormat[String, Any] write map
      case boolean: Boolean if boolean => JsTrue
      case boolean: Boolean if !boolean => JsFalse
      case unknown: Any => serializationError("Do not understand object of type " + unknown.getClass.getName)
    }
    def read(value: JsValue): Any = value match {
      case JsNumber(number) => number.toBigInt()
      case JsString(string) => string
      case array: JsArray => listFormat[Any].read(value)
      case jsObject: JsObject => mapFormat[String, Any].read(value)
      case JsTrue => true
      case JsFalse => false
      case unknown: Any => deserializationError("Do not understand how to deserialize " + unknown)
    }
  }

  // JSON to JobConfiguration mapper (6 fields)
  implicit val jobCreatingRequestFormat = jsonFormat6(JobConfiguration)
}
/** HTTP interface */
private[mist] trait HTTPService extends Directives with SprayJsonSupport with JsonFormatSupport with Logger{

  implicit val system: ActorSystem
  implicit val materializer: ActorMaterializer

  // /jobs
  def route : Route = path("jobs") {
    // POST /jobs
    post {
      // POST body must be JSON mapable into JobConfiguration
      entity(as[JobConfiguration]) { jobCreatingRequest =>
        complete {

          logger.info(jobCreatingRequest.parameters.toString)

          // Run job asynchronously
          val workerManagerActor = system.actorSelection(s"akka://mist/user/${Constants.Actors.workerManagerName}")

          val future = workerManagerActor.ask(jobCreatingRequest)(timeout = MistConfig.Contexts.timeout(jobCreatingRequest.name))

          future
            .recover {
              case error: AskTimeoutException => Right(Constants.Errors.jobTimeOutError)
              case error: Throwable => Right(error.toString)
            }
            .map[ToResponseMarshallable] {
              case result: Either[Map[String, Any], String] =>
                val jobResult: JobResult = result match {
                  case Left(jobResults: Map[String, Any]) =>
                    JobResult(success = true, payload = jobResults, request = jobCreatingRequest, errors = List.empty)
                  case Right(error: String) =>
                    JobResult(success = false, payload = Map.empty[String, Any], request = jobCreatingRequest, errors = List(error))
                }
                Json(DefaultFormats).write(jobResult)
            }
        }
      }
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy