SNRK-69: added web interface

This commit is contained in:
Anton Belyi 2023-05-01 19:19:17 +03:00
parent e9eaa0f8c2
commit b4423e8bba
3 changed files with 121 additions and 0 deletions

View File

@ -12,6 +12,8 @@ dependencies {
api("io.ktor:ktor-server-core:$ktorVersion") api("io.ktor:ktor-server-core:$ktorVersion")
api("io.ktor:ktor-server-html-builder:$ktorVersion") api("io.ktor:ktor-server-html-builder:$ktorVersion")
api("io.ktor:ktor-server-host-common:$ktorVersion") api("io.ktor:ktor-server-host-common:$ktorVersion")
implementation("io.ktor:ktor-server-netty:2.3.0")
implementation(project(mapOf("path" to ":snark-storage-driver")))
testApi("io.ktor:ktor-server-tests:$ktorVersion") testApi("io.ktor:ktor-server-tests:$ktorVersion")
} }

12
snark-ktor/snark-ktor.iml Normal file
View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src/main/kotlin" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="KotlinJavaRuntime" level="project" />
</component>
</module>

View File

@ -0,0 +1,107 @@
package space.kscience.snark.ktor
import io.ktor.http.*
import io.ktor.http.content.*
import io.ktor.server.engine.*
import io.ktor.server.netty.*
import io.ktor.server.application.*
import io.ktor.server.html.*
import io.ktor.server.request.*
import io.ktor.server.response.*
import io.ktor.server.http.content.*
import kotlinx.html.*
import io.ktor.server.routing.*
import java.nio.file.Path
import space.kscience.snark.storage.Directory
import space.kscience.snark.storage.local.localStorage
import kotlin.io.path.createTempDirectory
import kotlin.io.path.isDirectory
import kotlin.io.path.listDirectoryEntries
import kotlin.io.path.name
import space.kscience.snark.storage.unzip.unzip
public interface DataHolder {
fun init() : Directory
fun represent(): String
}
class LocalDataHolder: DataHolder {
private var source: Path? = null
private var response: String = ""
override fun init(): Directory {
source = createTempDirectory()
return localStorage(source!!)
}
private fun buildResponse(path: Path) {
for (entry in path.listDirectoryEntries()) {
if (entry.isDirectory()) {
buildResponse(entry)
} else {
response += source!!.relativize(entry).toString() + "\n"
}
}
}
override fun represent() : String =
if (source == null) {
"No data was loaded!"
} else {
response = "List of files:\n"
buildResponse(source!!)
response
}
}
fun main() {
val dataHolder: DataHolder = LocalDataHolder()
embeddedServer(Netty, 9090) {
routing {
get("/") {
call.respondHtml(HttpStatusCode.OK) {
head {
title {
+"SNARK"
}
}
body {
h1 {
+"SNARK"
}
}
body {
postForm (action = "/upload", encType = FormEncType.multipartFormData) {
label {
+"Choose zip archive: "
}
input (name = "file", type = InputType.file) {}
button {
+"Upload file"
}
}
a("/data") {
+"Show data\n"
}
}
}
}
post("/upload") {
val multipartData = call.receiveMultipart()
val tmp = createTempFile(suffix=".zip")
multipartData.forEachPart { part ->
when (part) {
is PartData.FileItem -> {
val fileBytes = part.streamProvider().readBytes()
tmp.writeBytes(fileBytes)
}
else -> {
}
}
part.dispose()
}
unzip(tmp.toPath().toString(), dataHolder.init())
call.respondText("File is successfully uploaded")
}
get("/data") {
call.respondText(dataHolder.represent())
}
}
}.start(wait = true)
}