forked from ing-bank/baker
-
Notifications
You must be signed in to change notification settings - Fork 0
/
WebShopService.scala
130 lines (100 loc) · 4.16 KB
/
WebShopService.scala
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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
package webshop.webservice
import java.io.File
import java.util.UUID
import java.util.concurrent.Executors
import cats.data.Kleisli
import cats.effect.concurrent.Ref
import cats.effect.{Blocker, ContextShift, IO, Timer}
import cats.implicits._
import fs2.io.file
import io.circe.generic.auto._
import io.circe.syntax._
import org.http4s._
import org.http4s.circe._
import org.http4s.dsl.io._
import org.http4s.implicits._
import org.http4s.server.Router
import scala.concurrent.ExecutionContext
object WebShopService {
case class PlaceOrderRequest(items: List[String])
case class PlaceOrderResponse(orderId: String)
case class AddAddressRequest(address: String)
case class AddPaymentRequest(payment: String)
case class PollPaymentStatusResponse(status: String)
}
class WebShopService(webshop: WebShop, memoryDumpPath: String)(implicit timer: Timer[IO], cs: ContextShift[IO]) {
import WebShopService._
implicit val placeOrderRequestDecoder: EntityDecoder[IO, PlaceOrderRequest] =
jsonOf[IO, PlaceOrderRequest]
implicit val addAddressRequestDecoder: EntityDecoder[IO, AddAddressRequest] =
jsonOf[IO, AddAddressRequest]
implicit val addPaymentRequestDecoder: EntityDecoder[IO, AddPaymentRequest] =
jsonOf[IO, AddPaymentRequest]
val blockingEc = ExecutionContext.fromExecutorService(Executors.newFixedThreadPool(4))
def buildHttpService(shuttingDown: Ref[IO, Boolean]): Kleisli[IO, Request[IO], Response[IO]] =
(Router("/" -> HttpRoutes.of[IO] {
case GET -> Root => Ok("Ok")
case HEAD -> Root =>
shuttingDown.get.flatMap {
case true => NotFound()
case false => Ok()
}
}) <+>
Router("/admin" -> HttpRoutes.of[IO] {
case GET -> Root / "shutdown" =>
println(Console.GREEN + "SHUTTING DOWN" + Console.RESET)
println(Console.GREEN + "====================" + Console.RESET)
for {
_ <- shuttingDown.modify(_ => (true, ()))
_ <- webshop.gracefulShutdown
response <- Ok("down")
} yield response
case GET -> Root / "memdump.hprof" =>
val path = memoryDumpPath + "-" + UUID.randomUUID().toString + ".hprof"
dumpHeap(path, live = true).as(
Response[IO](
Status.Ok,
body = file.readAll[IO](
path = java.nio.file.Paths.get(path),
blocker = Blocker.liftExecutionContext(blockingEc),
chunkSize = 4096),
headers = Headers(headers.`Content-Type`(MediaType.application.`octet-stream`, Charset.`UTF-8`).pure[List]))
)
}) <+>
Router("/api" -> HttpRoutes.of[IO] {
case GET -> Root =>
Ok("Ok")
case req@POST -> Root / "order" =>
for {
request <- req.as[PlaceOrderRequest]
orderId <- webshop.createCheckoutOrder(request.items)
response <- Ok(PlaceOrderResponse(orderId).asJson)
} yield response
case req@PUT -> Root / "order" / orderId / "address" =>
for {
request <- req.as[AddAddressRequest]
_ <- webshop.addCheckoutAddressInfo(orderId, request.address)
response <- Ok()
} yield response
case req@PUT -> Root / "order" / orderId / "payment" =>
for {
request <- req.as[AddPaymentRequest]
_ <- webshop.addCheckoutPaymentInfo(orderId, request.payment)
response <- Ok()
} yield response
case GET -> Root / "order" / orderId =>
for {
status <- webshop.pollOrderStatus(orderId)
response <- Ok(PollPaymentStatusResponse(status.toString).asJson)
} yield response
})).orNotFound
import java.lang.management.ManagementFactory
import com.sun.management.HotSpotDiagnosticMXBean
def dumpHeap(filePath: String, live: Boolean): IO[Unit] = IO {
val file = new File(filePath)
if (file.exists()) file.delete()
val server = ManagementFactory.getPlatformMBeanServer
val mxBean = ManagementFactory.newPlatformMXBeanProxy(server, "com.sun.management:type=HotSpotDiagnostic", classOf[HotSpotDiagnosticMXBean])
mxBean.dumpHeap(filePath, live)
}
}