Initial commit
This commit is contained in:
commit
e80c97e450
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
.gradle/
|
||||||
|
build/
|
||||||
|
kodeshare.log
|
32
build.gradle.kts
Normal file
32
build.gradle.kts
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
kotlin("jvm") version "1.3.50"
|
||||||
|
application
|
||||||
|
}
|
||||||
|
|
||||||
|
group = "moe.kageru"
|
||||||
|
version = "0.1.0"
|
||||||
|
|
||||||
|
val mainClass = "moe.kageru.kodeshare.KodeshareKt"
|
||||||
|
application {
|
||||||
|
mainClassName = mainClass
|
||||||
|
}
|
||||||
|
val ktorVersion = "1.2.4"
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
jcenter()
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation(kotlin("stdlib-jdk8"))
|
||||||
|
implementation("io.ktor:ktor-server-netty:$ktorVersion")
|
||||||
|
implementation("io.ktor:ktor-locations:$ktorVersion")
|
||||||
|
implementation("org.jetbrains.exposed:exposed:0.17.3")
|
||||||
|
implementation("org.mariadb.jdbc:mariadb-java-client:2.4.4")
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.withType<KotlinCompile> {
|
||||||
|
kotlinOptions.jvmTarget = "1.8"
|
||||||
|
}
|
1
gradle.properties
Normal file
1
gradle.properties
Normal file
@ -0,0 +1 @@
|
|||||||
|
kotlin.code.style=official
|
2
settings.gradle
Normal file
2
settings.gradle
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
rootProject.name = 'kodeshare'
|
||||||
|
|
22
src/main/kotlin/moe/kageru/kodeshare/Kodeshare.kt
Normal file
22
src/main/kotlin/moe/kageru/kodeshare/Kodeshare.kt
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
package moe.kageru.kodeshare
|
||||||
|
|
||||||
|
import io.ktor.application.install
|
||||||
|
import io.ktor.features.DefaultHeaders
|
||||||
|
import io.ktor.locations.Locations
|
||||||
|
import io.ktor.routing.routing
|
||||||
|
import io.ktor.server.engine.embeddedServer
|
||||||
|
import io.ktor.server.netty.Netty
|
||||||
|
import moe.kageru.kodeshare.Routes.createRoutes
|
||||||
|
|
||||||
|
@ExperimentalStdlibApi
|
||||||
|
fun main() {
|
||||||
|
embeddedServer(Netty, 9092) {
|
||||||
|
install(DefaultHeaders)
|
||||||
|
install(Locations)
|
||||||
|
routing {
|
||||||
|
createRoutes()
|
||||||
|
}
|
||||||
|
}.start(wait = true)
|
||||||
|
}
|
||||||
|
|
||||||
|
data class Paste(val content: String, val html: String?)
|
32
src/main/kotlin/moe/kageru/kodeshare/Log.kt
Normal file
32
src/main/kotlin/moe/kageru/kodeshare/Log.kt
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
package moe.kageru.kodeshare
|
||||||
|
|
||||||
|
import java.time.ZoneId
|
||||||
|
import java.time.format.DateTimeFormatter
|
||||||
|
import java.util.logging.FileHandler
|
||||||
|
import java.util.logging.Formatter
|
||||||
|
import java.util.logging.LogRecord
|
||||||
|
import java.util.logging.Logger
|
||||||
|
|
||||||
|
object Log {
|
||||||
|
private val log: Logger by lazy {
|
||||||
|
val log = Logger.getGlobal()
|
||||||
|
val fh = FileHandler("kodeshare.log", true)
|
||||||
|
val formatter = LogFormatter()
|
||||||
|
fh.formatter = formatter
|
||||||
|
log.addHandler(fh)
|
||||||
|
return@lazy log
|
||||||
|
}
|
||||||
|
|
||||||
|
fun info(message: String) {
|
||||||
|
log.info(message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class LogFormatter : Formatter() {
|
||||||
|
private val timeFormatter: DateTimeFormatter =
|
||||||
|
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").withZone(ZoneId.systemDefault())
|
||||||
|
|
||||||
|
override fun format(record: LogRecord): String {
|
||||||
|
return "[${record.level}] ${timeFormatter.format(record.instant)}: ${record.message}\n"
|
||||||
|
}
|
||||||
|
}
|
65
src/main/kotlin/moe/kageru/kodeshare/Routes.kt
Normal file
65
src/main/kotlin/moe/kageru/kodeshare/Routes.kt
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
package moe.kageru.kodeshare
|
||||||
|
|
||||||
|
import io.ktor.application.ApplicationCall
|
||||||
|
import io.ktor.application.call
|
||||||
|
import io.ktor.http.ContentType
|
||||||
|
import io.ktor.http.HttpStatusCode
|
||||||
|
import io.ktor.http.content.PartData
|
||||||
|
import io.ktor.http.content.forEachPart
|
||||||
|
import io.ktor.http.content.streamProvider
|
||||||
|
import io.ktor.locations.Location
|
||||||
|
import io.ktor.locations.get
|
||||||
|
import io.ktor.request.receiveMultipart
|
||||||
|
import io.ktor.response.respond
|
||||||
|
import io.ktor.response.respondText
|
||||||
|
import io.ktor.routing.Routing
|
||||||
|
import io.ktor.routing.get
|
||||||
|
import io.ktor.routing.post
|
||||||
|
import moe.kageru.kodeshare.persistence.PasteDao
|
||||||
|
|
||||||
|
@ExperimentalStdlibApi
|
||||||
|
object Routes {
|
||||||
|
fun Routing.createRoutes() {
|
||||||
|
get("/") {
|
||||||
|
call.respondText("Hello, world!", ContentType.Text.Html)
|
||||||
|
}
|
||||||
|
post("/") {
|
||||||
|
save(call)
|
||||||
|
}
|
||||||
|
get<PasteRequest> { req ->
|
||||||
|
respondGet(call, req)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ExperimentalStdlibApi
|
||||||
|
suspend fun save(call: ApplicationCall) {
|
||||||
|
call.receiveMultipart().forEachPart { part ->
|
||||||
|
when(part) {
|
||||||
|
is PartData.FileItem -> {
|
||||||
|
Log.info("new file")
|
||||||
|
val content = part.streamProvider().use { it.readAllBytes().decodeToString() }
|
||||||
|
val id = PasteDao.insert(Paste(content = content, html = null)).id
|
||||||
|
call.respond(HttpStatusCode.Created, "$id")
|
||||||
|
Log.info("Saving new paste with ID $id")
|
||||||
|
}
|
||||||
|
is PartData.FormItem -> {
|
||||||
|
Log.info("form item")
|
||||||
|
}
|
||||||
|
is PartData.BinaryItem -> {
|
||||||
|
Log.info("binary item")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun respondGet(call: ApplicationCall, req: PasteRequest) {
|
||||||
|
val id = req.id
|
||||||
|
Log.info("Retrieving paste $id")
|
||||||
|
PasteDao.select(id)?.data?.let { paste ->
|
||||||
|
call.respondText(paste.html ?: paste.content, ContentType.Text.Html)
|
||||||
|
} ?: call.respond(HttpStatusCode.NotFound, "nothing found for id $id")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Location("/{id}")
|
||||||
|
data class PasteRequest(val id: Long)
|
54
src/main/kotlin/moe/kageru/kodeshare/persistence/PasteDao.kt
Normal file
54
src/main/kotlin/moe/kageru/kodeshare/persistence/PasteDao.kt
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
package moe.kageru.kodeshare.persistence
|
||||||
|
|
||||||
|
import moe.kageru.kodeshare.Paste
|
||||||
|
import org.jetbrains.exposed.sql.*
|
||||||
|
import org.jetbrains.exposed.sql.transactions.transaction
|
||||||
|
import org.mariadb.jdbc.MariaDbDataSource
|
||||||
|
|
||||||
|
object PasteDao {
|
||||||
|
fun select(id: Long): Transient<Paste>? = transaction {
|
||||||
|
PasteTable.select { PasteTable.id.eq(id) }.firstOrNull()
|
||||||
|
}?.toPaste()
|
||||||
|
|
||||||
|
fun insert(paste: Paste): Transient<Paste> = transaction {
|
||||||
|
val id = PasteTable.insert {
|
||||||
|
it[content] = paste.content
|
||||||
|
it[html] = paste.html
|
||||||
|
}[PasteTable.id]
|
||||||
|
Transient(id, paste)
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
val source = MariaDbDataSource().apply {
|
||||||
|
userName = "kodepaste"
|
||||||
|
setPassword("12345")
|
||||||
|
databaseName = "kode"
|
||||||
|
}
|
||||||
|
Database.connect(source)
|
||||||
|
transaction {
|
||||||
|
SchemaUtils.drop(PasteTable)
|
||||||
|
SchemaUtils.create(PasteTable)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun ResultRow.toPaste() = Transient(
|
||||||
|
get(PasteTable.id),
|
||||||
|
Paste(
|
||||||
|
content = get(PasteTable.content),
|
||||||
|
html = get(PasteTable.html)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
private object PasteTable : Table() {
|
||||||
|
val id = long("id").primaryKey().autoIncrement()
|
||||||
|
val content = text("content")
|
||||||
|
val html = text("html").nullable()
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Better have that one generic class
|
||||||
|
* after deciding to make everything else
|
||||||
|
* not generic because it would be overkill
|
||||||
|
*/
|
||||||
|
data class Transient<DATA>(val id: Long, val data: DATA)
|
Loading…
Reference in New Issue
Block a user