From 73eb30dbf9a6d4de8487be1e026f02f91b7f947e Mon Sep 17 00:00:00 2001 From: Graham Date: Thu, 3 Mar 2022 19:06:30 +0000 Subject: [PATCH] Add game, environment, language, build and timestamp to file names Signed-off-by: Graham --- .../openrs2/archive/cache/CacheExporter.kt | 57 +++++++++++++++++++ .../openrs2/archive/web/CachesController.kt | 50 +++++++++++++++- 2 files changed, 104 insertions(+), 3 deletions(-) diff --git a/archive/src/main/kotlin/org/openrs2/archive/cache/CacheExporter.kt b/archive/src/main/kotlin/org/openrs2/archive/cache/CacheExporter.kt index a4f8d4d5..d18db8ab 100644 --- a/archive/src/main/kotlin/org/openrs2/archive/cache/CacheExporter.kt +++ b/archive/src/main/kotlin/org/openrs2/archive/cache/CacheExporter.kt @@ -18,6 +18,8 @@ import org.openrs2.db.Database import org.postgresql.util.PGobject import java.sql.Connection import java.time.Instant +import java.time.ZoneOffset +import java.time.format.DateTimeFormatter import java.util.SortedSet import javax.inject.Inject import javax.inject.Singleton @@ -370,6 +372,61 @@ public class CacheExporter @Inject constructor( } } + public suspend fun getFileName(id: Int): String? { + return database.execute { connection -> + // TODO(gpe): what if a cache is from multiple games? + connection.prepareStatement(""" + SELECT + g.name AS game, + e.name AS environment, + l.iso_code AS language, + array_remove(array_agg(DISTINCT ROW(s.build_major, s.build_minor)::build ORDER BY ROW(s.build_major, s.build_minor)::build ASC), NULL) builds, + MIN(s.timestamp) AS timestamp + FROM sources s + JOIN game_variants v ON v.id = s.game_id + JOIN games g ON g.id = v.game_id + JOIN environments e ON e.id = v.environment_id + JOIN languages l ON l.id = v.language_id + WHERE s.cache_id = ? + GROUP BY g.name, e.name, l.iso_code + LIMIT 1 + """.trimIndent()).use { stmt -> + stmt.setInt(1, id) + + stmt.executeQuery().use { rows -> + if (!rows.next()) { + return@execute null + } + + val game = rows.getString(1) + val environment = rows.getString(2) + val language = rows.getString(3) + + val name = StringBuilder("$game-$environment-$language") + + val builds = rows.getArray(4).array as Array<*> + for (build in builds.mapNotNull { o -> Build.fromPgObject(o as PGobject) }.toSortedSet()) { + name.append("-b") + name.append(build) + } + + val timestamp = rows.getTimestamp(5) + if (!rows.wasNull()) { + name.append('-') + name.append(timestamp.toInstant() + .atOffset(ZoneOffset.UTC) + .format(DateTimeFormatter.ofPattern("yyyy-MM-dd-HH-mm-ss"))) + } + + name.append("-openrs2#") + name.append(id) + + name.toString() + } + } + } + } + public fun export(id: Int, storeFactory: (Boolean) -> Store) { database.executeOnce { connection -> val legacy = connection.prepareStatement( diff --git a/archive/src/main/kotlin/org/openrs2/archive/web/CachesController.kt b/archive/src/main/kotlin/org/openrs2/archive/web/CachesController.kt index fc647d9d..18dd71bc 100644 --- a/archive/src/main/kotlin/org/openrs2/archive/web/CachesController.kt +++ b/archive/src/main/kotlin/org/openrs2/archive/web/CachesController.kt @@ -68,10 +68,16 @@ public class CachesController @Inject constructor( return } + val name = exporter.getFileName(id) + if (name == null) { + call.respond(HttpStatusCode.NotFound) + return + } + call.response.header( HttpHeaders.ContentDisposition, ContentDisposition.Attachment - .withParameter(ContentDisposition.Parameters.FileName, "cache.zip") + .withParameter(ContentDisposition.Parameters.FileName, "cache-$name.zip") .toString() ) @@ -89,10 +95,16 @@ public class CachesController @Inject constructor( return } + val name = exporter.getFileName(id) + if (name == null) { + call.respond(HttpStatusCode.NotFound) + return + } + call.response.header( HttpHeaders.ContentDisposition, ContentDisposition.Attachment - .withParameter(ContentDisposition.Parameters.FileName, "cache.tar.gz") + .withParameter(ContentDisposition.Parameters.FileName, "cache-$name.tar.gz") .toString() ) @@ -110,6 +122,19 @@ public class CachesController @Inject constructor( return } + val name = exporter.getFileName(id) + if (name == null) { + call.respond(HttpStatusCode.NotFound) + return + } + + call.response.header( + HttpHeaders.ContentDisposition, + ContentDisposition.Inline + .withParameter(ContentDisposition.Parameters.FileName, "keys-$name.json") + .toString() + ) + call.respond(exporter.exportKeys(id)) } @@ -120,10 +145,16 @@ public class CachesController @Inject constructor( return } + val name = exporter.getFileName(id) + if (name == null) { + call.respond(HttpStatusCode.NotFound) + return + } + call.response.header( HttpHeaders.ContentDisposition, ContentDisposition.Attachment - .withParameter(ContentDisposition.Parameters.FileName, "keys.zip") + .withParameter(ContentDisposition.Parameters.FileName, "keys-$name.zip") .toString() ) @@ -172,6 +203,19 @@ public class CachesController @Inject constructor( return } + val name = exporter.getFileName(id) + if (name == null) { + call.respond(HttpStatusCode.NotFound) + return + } + + call.response.header( + HttpHeaders.ContentDisposition, + ContentDisposition.Inline + .withParameter(ContentDisposition.Parameters.FileName, "map-$name.png") + .toString() + ) + /* * The temporary BufferedImages used by the MapRenderer use a large * amount of heap space. We limit the number of renders that can be