summaryrefslogtreecommitdiff
path: root/crashbox-server/src/main/scala/io/crashbox/ci/HttpApi.scala
blob: c9e62c3ac1ca921e405c0ca822eb97f6190d63d6 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
package io.crashbox.ci

import java.net.URL
import java.util.UUID

import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport._
import akka.http.scaladsl.marshalling.{Marshaller, ToResponseMarshaller}
import akka.http.scaladsl.model.{ContentTypes, HttpEntity}
import akka.http.scaladsl.model.HttpEntity.ChunkStreamPart
import akka.http.scaladsl.model.HttpResponse
import akka.http.scaladsl.server._
import akka.http.scaladsl.server.Directives._
import akka.stream.scaladsl.{Source => Src}
import akka.stream.scaladsl.StreamConverters
import spray.json._

trait HttpApi { self: Core with Schedulers with Storage =>

  val endpoint = "api"

  case class Request(url: URL) {}

  object Protocol extends DefaultJsonProtocol {
    val urlReader = new JsonReader[URL] {
      override def read(js: JsValue) = js match {
        case JsString(str) => new URL(str)
        case _ => deserializationError("Expected valid url string")
      }
    }
    val urlWriter = new JsonWriter[URL] {
      override def write(url: URL) = JsString(url.toString())
    }
    implicit val urlFormat: JsonFormat[URL] = jsonFormat(urlReader, urlWriter)
    implicit val request = jsonFormat1(Request)
  }
  import Protocol._

  implicit val toResponseMarshaller: ToResponseMarshaller[Src[String, Any]] =
    Marshaller.opaque { items =>
      val data = items.map(item => ChunkStreamPart(item.toString + "\n"))
      HttpResponse(
        entity = HttpEntity.Chunked(ContentTypes.`text/plain(UTF-8)`, data))
    }

  def httpApi: Route = pathPrefix(endpoint) {
    path("submit") {
      post {
        entity(as[Request]) { req =>
          val scheduled = scheduleBuild(req.url).map(_.toString())
          complete(scheduled)
        }
      }
    } ~
      path(Segment / "cancel") { buildId =>
        post {
          cancelBuild(UUID.fromString(buildId))
          complete(204 -> None)
        }
      } ~
      path(Segment / "logs") { buildId =>
        get {
          val src = StreamConverters
            .fromInputStream(() => readLog(UUID.fromString(buildId), 0))
            .map { bs =>
              bs.utf8String
            }
          complete(src)
        }
      }
  }

}