Merge SNARK-MR-12: SNRK-69: added web interface
This commit is contained in:
commit
7d681549b7
@ -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
12
snark-ktor/snark-ktor.iml
Normal 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>
|
@ -0,0 +1,121 @@
|
|||||||
|
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 kotlinx.css.html
|
||||||
|
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
|
||||||
|
//will be HTML later
|
||||||
|
}
|
||||||
|
class LocalDataHolder: DataHolder {
|
||||||
|
private var source: Path? = null
|
||||||
|
private var response: String = ""
|
||||||
|
override fun init(): Directory {
|
||||||
|
source?.toFile()?.deleteRecursively()
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SNARKServer(val dataHolder: DataHolder, val port: Int): Runnable {
|
||||||
|
private suspend fun renderGet(call: ApplicationCall) {
|
||||||
|
call.respondText(dataHolder.represent())
|
||||||
|
}
|
||||||
|
private suspend fun renderUpload(call: ApplicationCall) {
|
||||||
|
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")
|
||||||
|
}
|
||||||
|
private suspend fun renderMainPage(call: ApplicationCall) {
|
||||||
|
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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
override fun run() {
|
||||||
|
embeddedServer(Netty, port) {
|
||||||
|
routing {
|
||||||
|
get("/") {
|
||||||
|
renderMainPage(call)
|
||||||
|
}
|
||||||
|
post("/upload") {
|
||||||
|
renderUpload(call)
|
||||||
|
}
|
||||||
|
get("/data") {
|
||||||
|
renderGet(call)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.start(wait = true)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
package space.kscience.snark.ktor
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
SNARKServer(LocalDataHolder(), 9090).run()
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user