Skip to content

Commit

Permalink
render an image of the stats for embedding
Browse files Browse the repository at this point in the history
  • Loading branch information
pschichtel committed Oct 8, 2024
1 parent 0f16a50 commit 89fe5b4
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 3 deletions.
38 changes: 36 additions & 2 deletions app/controllers/Ld56C2Controller.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,14 @@ import play.api.libs.json.*
import play.api.libs.streams.ActorFlow
import play.api.mvc.{AbstractController, ControllerComponents, WebSocket}

import java.awt.{Color, Graphics2D}
import java.awt.image.BufferedImage
import java.io.ByteArrayOutputStream
import java.net.InetAddress
import java.time.{Duration, Instant}
import java.util.UUID
import java.util.concurrent.{ConcurrentHashMap, ConcurrentMap}
import javax.imageio.ImageIO
import scala.collection.mutable.ArrayBuffer
import scala.concurrent.Future
import scala.jdk.CollectionConverters.CollectionHasAsScala
Expand Down Expand Up @@ -82,15 +86,45 @@ class Ld56C2Controller(cc: ControllerComponents)(implicit system: ActorSystem, m
private val hosts = ConcurrentHashMap[UUID, GameHost]()
private var lastJoinTime: Instant = _

def stats() = Action.async { request =>
private def gatherStats(): StatsResponse = {
val now = Instant.now()
hosts.entrySet().removeIf(entry => entry.getValue.isStale(now))
val gameHosts = hosts.values().asScala.toVector
val latestHost =
if (hosts.isEmpty) None
else Some(gameHosts.map(_.inceptionTime).max)
StatsResponse(gameHosts.length, latestHost, gameHosts.map(_.playerCount).sum, Option(lastJoinTime))
}

def stats() = Action.async { request =>

Future.successful(Ok(Json.toJson(gatherStats())))
}

Future.successful(Ok(Json.toJson(StatsResponse(gameHosts.length, latestHost, gameHosts.map(_.playerCount).sum, Option(lastJoinTime)))))
def statsPicture() = Action.async { request =>
logger.info(s"${request.connection.remoteAddress} requested stats as image")
val stats = gatherStats()

val w = 100
val h = 50
val image = BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB)
val graphics = image.getGraphics.asInstanceOf[Graphics2D]
graphics.setColor(Color.BLACK)
graphics.drawString(s"Servers: ${stats.servers}", 5, 15)
graphics.drawString(s"Players: ${stats.players}", 5, 35)
graphics.dispose()
val output = ByteArrayOutputStream()
ImageIO.write(image, "png", output)

val cacheHeaders = Seq(
"Pragma-directive" -> "no-cache",
"Cache-directive" -> "no-cache",
"Cache-control" -> "no-cache",
"Pragma" -> "no-cache",
"Expires" -> "0",
)

Future.successful(Ok(output.toByteArray).as("image/png").withHeaders(cacheHeaders*))
}

def signalHost(id: String) = WebSocket.accept[String, String] { request =>
Expand Down
3 changes: 2 additions & 1 deletion conf/routes
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,5 @@ GET /dev controllers.MainController.dev()

GET /ld56/signal/:id/host controllers.Ld56C2Controller.signalHost(id)
GET /ld56/signal/:id/join controllers.Ld56C2Controller.signalJoin(id)
GET /ld56/stats controllers.Ld56C2Controller.stats()
GET /ld56/stats controllers.Ld56C2Controller.stats()
GET /ld56/stats/image controllers.Ld56C2Controller.statsPicture()

0 comments on commit 89fe5b4

Please sign in to comment.