Initial commit

这个提交包含在:
kageru 2019-09-19 22:04:23 +02:00
当前提交 e80c97e450
签署人:: kageru
GPG 密钥 ID: 8282A2BEA4ADA3D2
共有 8 个文件被更改,包括 211 次插入0 次删除

3
.gitignore vendored 普通文件
查看文件

@ -0,0 +1,3 @@
.gradle/
build/
kodeshare.log

32
build.gradle.kts 普通文件
查看文件

@ -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 普通文件
查看文件

@ -0,0 +1 @@
kotlin.code.style=official

2
settings.gradle 普通文件
查看文件

@ -0,0 +1,2 @@
rootProject.name = 'kodeshare'

查看文件

@ -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?)

查看文件

@ -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"
}
}

查看文件

@ -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)

查看文件

@ -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)