Add API for downloading individual groups

Signed-off-by: Graham <gpe@openrs2.org>
Graham 3 years ago
parent e5512cbdf6
commit c94678c7c5
  1. 34
      archive/src/main/kotlin/org/openrs2/archive/cache/CacheExporter.kt
  2. 26
      archive/src/main/kotlin/org/openrs2/archive/web/CachesController.kt
  3. 1
      archive/src/main/kotlin/org/openrs2/archive/web/WebServer.kt

@ -3,6 +3,7 @@ package org.openrs2.archive.cache
import com.fasterxml.jackson.annotation.JsonIgnore import com.fasterxml.jackson.annotation.JsonIgnore
import com.fasterxml.jackson.annotation.JsonProperty import com.fasterxml.jackson.annotation.JsonProperty
import com.fasterxml.jackson.annotation.JsonUnwrapped import com.fasterxml.jackson.annotation.JsonUnwrapped
import io.netty.buffer.ByteBuf
import io.netty.buffer.ByteBufAllocator import io.netty.buffer.ByteBufAllocator
import io.netty.buffer.Unpooled import io.netty.buffer.Unpooled
import org.openrs2.buffer.use import org.openrs2.buffer.use
@ -443,6 +444,39 @@ public class CacheExporter @Inject constructor(
} }
} }
public suspend fun exportGroup(scope: String, id: Int, archive: Int, group: Int): ByteBuf? {
return database.execute { connection ->
connection.prepareStatement("""
SELECT g.data
FROM resolved_groups g
JOIN scopes s ON s.id = g.scope_id
WHERE s.name = ? AND g.master_index_id = ? AND g.archive_id = ? AND g.group_id = ?
UNION ALL
SELECT f.data
FROM resolved_files f
WHERE f.crc_table_id = ? AND f.index_id = ? AND f.file_id = ?
""".trimIndent()).use { stmt ->
stmt.setString(1, scope)
stmt.setInt(2, id)
stmt.setInt(3, archive)
stmt.setInt(4, group)
stmt.setInt(5, id)
stmt.setInt(6, archive)
stmt.setInt(7, group)
stmt.executeQuery().use { rows ->
if (!rows.next()) {
return@execute null
}
val data = rows.getBytes(1)
return@execute Unpooled.wrappedBuffer(data)
}
}
}
}
public fun export(scope: String, id: Int, storeFactory: (Boolean) -> Store) { public fun export(scope: String, id: Int, storeFactory: (Boolean) -> Store) {
database.executeOnce { connection -> database.executeOnce { connection ->
val legacy = connection.prepareStatement( val legacy = connection.prepareStatement(

@ -7,14 +7,18 @@ import io.ktor.http.HttpHeaders
import io.ktor.http.HttpStatusCode import io.ktor.http.HttpStatusCode
import io.ktor.response.header import io.ktor.response.header
import io.ktor.response.respond import io.ktor.response.respond
import io.ktor.response.respondBytes
import io.ktor.response.respondBytesWriter
import io.ktor.response.respondOutputStream import io.ktor.response.respondOutputStream
import io.ktor.thymeleaf.ThymeleafContent import io.ktor.thymeleaf.ThymeleafContent
import io.netty.buffer.ByteBufAllocator import io.netty.buffer.ByteBufAllocator
import io.netty.buffer.ByteBufUtil
import kotlinx.coroutines.sync.Semaphore import kotlinx.coroutines.sync.Semaphore
import kotlinx.coroutines.sync.withPermit import kotlinx.coroutines.sync.withPermit
import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream
import org.openrs2.archive.cache.CacheExporter import org.openrs2.archive.cache.CacheExporter
import org.openrs2.archive.map.MapRenderer import org.openrs2.archive.map.MapRenderer
import org.openrs2.buffer.use
import org.openrs2.cache.DiskStoreZipWriter import org.openrs2.cache.DiskStoreZipWriter
import org.openrs2.cache.FlatFileStoreTarWriter import org.openrs2.cache.FlatFileStoreTarWriter
import org.openrs2.compress.gzip.GzipLevelOutputStream import org.openrs2.compress.gzip.GzipLevelOutputStream
@ -69,6 +73,28 @@ public class CachesController @Inject constructor(
) )
} }
public suspend fun exportGroup(call: ApplicationCall) {
val scope = call.parameters["scope"]!!
val id = call.parameters["id"]?.toIntOrNull()
val archiveId = call.parameters["archive"]?.toIntOrNull()
val groupId = call.parameters["group"]?.toIntOrNull()
if (id == null || archiveId == null || groupId == null) {
call.respond(HttpStatusCode.NotFound)
return
}
exporter.exportGroup(scope, id, archiveId, groupId).use { buf ->
if (buf == null) {
call.respond(HttpStatusCode.NotFound)
return
}
val bytes = ByteBufUtil.getBytes(buf, 0, buf.readableBytes(), false)
call.respondBytes(bytes, contentType = ContentType.Application.OctetStream)
}
}
public suspend fun exportDisk(call: ApplicationCall) { public suspend fun exportDisk(call: ApplicationCall) {
val scope = call.parameters["scope"]!! val scope = call.parameters["scope"]!!
val id = call.parameters["id"]?.toIntOrNull() val id = call.parameters["id"]?.toIntOrNull()

@ -57,6 +57,7 @@ public class WebServer @Inject constructor(
get("/caches") { cachesController.index(call) } get("/caches") { cachesController.index(call) }
get("/caches.json") { cachesController.indexJson(call) } get("/caches.json") { cachesController.indexJson(call) }
get("/caches/{scope}/{id}") { cachesController.show(call) } get("/caches/{scope}/{id}") { cachesController.show(call) }
get("/caches/{scope}/{id}/archives/{archive}/groups/{group}.dat") { cachesController.exportGroup(call) }
get("/caches/{scope}/{id}/disk.zip") { cachesController.exportDisk(call) } get("/caches/{scope}/{id}/disk.zip") { cachesController.exportDisk(call) }
get("/caches/{scope}/{id}/flat-file.tar.gz") { cachesController.exportFlatFile(call) } get("/caches/{scope}/{id}/flat-file.tar.gz") { cachesController.exportFlatFile(call) }
get("/caches/{scope}/{id}/keys.json") { cachesController.exportKeysJson(call) } get("/caches/{scope}/{id}/keys.json") { cachesController.exportKeysJson(call) }

Loading…
Cancel
Save