forked from openrs2/openrs2
parent
6e9ba80d0c
commit
47127113f4
@ -0,0 +1,41 @@ |
||||
package org.openrs2.archive.web |
||||
|
||||
import io.ktor.application.ApplicationCall |
||||
import io.ktor.http.ContentType |
||||
import io.ktor.http.HttpStatusCode |
||||
import io.ktor.response.header |
||||
import io.ktor.response.respond |
||||
import io.ktor.response.respondOutputStream |
||||
import io.ktor.thymeleaf.ThymeleafContent |
||||
import io.netty.buffer.ByteBufAllocator |
||||
import org.openrs2.archive.cache.CacheExporter |
||||
import org.openrs2.cache.DiskStoreZipWriter |
||||
import java.util.zip.ZipOutputStream |
||||
import javax.inject.Inject |
||||
import javax.inject.Singleton |
||||
|
||||
@Singleton |
||||
public class CachesController @Inject constructor( |
||||
private val exporter: CacheExporter, |
||||
private val alloc: ByteBufAllocator |
||||
) { |
||||
public suspend fun index(call: ApplicationCall) { |
||||
val caches = exporter.list() |
||||
call.respond(ThymeleafContent("caches/index.html", mapOf("caches" to caches))) |
||||
} |
||||
|
||||
public suspend fun export(call: ApplicationCall) { |
||||
val id = call.parameters["id"]?.toLongOrNull() |
||||
if (id == null) { |
||||
call.respond(HttpStatusCode.NotFound) |
||||
return |
||||
} |
||||
|
||||
call.response.header("Content-Disposition", "attachment; filename=\"cache.zip\"") |
||||
call.respondOutputStream(contentType = ContentType.Application.Zip) { |
||||
DiskStoreZipWriter(ZipOutputStream(this), alloc = alloc).use { store -> |
||||
exporter.export(id, store) |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,29 @@ |
||||
package org.openrs2.archive.web |
||||
|
||||
import io.ktor.application.ApplicationCall |
||||
import io.ktor.http.HttpStatusCode |
||||
import io.ktor.response.respond |
||||
import org.openrs2.archive.key.KeyImporter |
||||
import org.openrs2.crypto.XteaKey |
||||
import javax.inject.Inject |
||||
import javax.inject.Singleton |
||||
|
||||
@Singleton |
||||
public class KeysController @Inject constructor( |
||||
private val importer: KeyImporter |
||||
) { |
||||
public suspend fun create(call: ApplicationCall) { |
||||
val k0 = call.request.queryParameters["key1"]?.toIntOrNull() |
||||
val k1 = call.request.queryParameters["key2"]?.toIntOrNull() |
||||
val k2 = call.request.queryParameters["key3"]?.toIntOrNull() |
||||
val k3 = call.request.queryParameters["key4"]?.toIntOrNull() |
||||
|
||||
if (k0 == null || k1 == null || k2 == null || k3 == null) { |
||||
call.respond(HttpStatusCode.BadRequest) |
||||
return |
||||
} |
||||
|
||||
importer.import(listOf(XteaKey(k0, k1, k2, k3))) |
||||
call.respond(HttpStatusCode.NoContent) |
||||
} |
||||
} |
@ -0,0 +1,13 @@ |
||||
package org.openrs2.archive.web |
||||
|
||||
import com.github.ajalt.clikt.core.CliktCommand |
||||
import com.google.inject.Guice |
||||
import org.openrs2.archive.ArchiveModule |
||||
|
||||
public class WebCommand : CliktCommand(name = "web") { |
||||
override fun run() { |
||||
val injector = Guice.createInjector(ArchiveModule) |
||||
val server = injector.getInstance(WebServer::class.java) |
||||
server.start() |
||||
} |
||||
} |
@ -0,0 +1,41 @@ |
||||
package org.openrs2.archive.web |
||||
|
||||
import io.ktor.application.call |
||||
import io.ktor.application.install |
||||
import io.ktor.routing.get |
||||
import io.ktor.routing.routing |
||||
import io.ktor.server.engine.embeddedServer |
||||
import io.ktor.server.netty.Netty |
||||
import io.ktor.thymeleaf.Thymeleaf |
||||
import org.thymeleaf.extras.java8time.dialect.Java8TimeDialect |
||||
import org.thymeleaf.templatemode.TemplateMode |
||||
import org.thymeleaf.templateresolver.ClassLoaderTemplateResolver |
||||
import javax.inject.Inject |
||||
import javax.inject.Singleton |
||||
|
||||
@Singleton |
||||
public class WebServer @Inject constructor( |
||||
private val cachesController: CachesController, |
||||
private val keysController: KeysController |
||||
) { |
||||
public fun start() { |
||||
embeddedServer(Netty, port = 8000) { |
||||
install(Thymeleaf) { |
||||
addDialect(Java8TimeDialect()) |
||||
|
||||
setTemplateResolver(ClassLoaderTemplateResolver().apply { |
||||
prefix = "/org/openrs2/archive/templates/" |
||||
templateMode = TemplateMode.HTML |
||||
}) |
||||
} |
||||
|
||||
routing { |
||||
get("/caches") { cachesController.index(call) } |
||||
get("/caches/{id}.zip") { cachesController.export(call) } |
||||
|
||||
// ideally we'd use POST /keys here, but I want to be compatible with the RuneLite/OpenOSRS API |
||||
get("/keys/submit") { keysController.create(call) } |
||||
} |
||||
}.start(wait = true) |
||||
} |
||||
} |
@ -0,0 +1,29 @@ |
||||
<!DOCTYPE html> |
||||
<html xmlns:th="http://www.thymeleaf.org" lang="en"> |
||||
<body> |
||||
<table> |
||||
<thead> |
||||
<tr> |
||||
<th>Master Index Digest</th> |
||||
<th>Game</th> |
||||
<th>Build</th> |
||||
<th>Timestamp</th> |
||||
<th></th> |
||||
</tr> |
||||
</thead> |
||||
<tbody> |
||||
<!--/*@thymesVar id="caches" type="java.util.List<org.openrs2.archive.cache.CacheExporter.Cache>"*/--> |
||||
<tr th:each="cache : ${caches}"> |
||||
<td th:text="${@io.netty.buffer.ByteBufUtil@hexDump(cache.whirlpool).substring(0, 8)}">00000000</td> |
||||
<td th:text="${cache.game}">runescape</td> |
||||
<td th:text="${cache.build}">550</td> |
||||
<td th:text="${#temporals.formatISO(cache.timestamp)}"></td> |
||||
<td> |
||||
<a th:href="${'/caches/' + cache.id + '.zip'}">Download</a> |
||||
</td> |
||||
</tr> |
||||
</tbody> |
||||
</table> |
||||
</body> |
||||
</html> |
||||
|
Loading…
Reference in new issue