Initial commit

Cette révision appartient à :
kageru 2019-09-19 22:04:23 +02:00
révision e80c97e450
Signé par: kageru
ID de la clé GPG: 8282A2BEA4ADA3D2
8 fichiers modifiés avec 211 ajouts et 0 suppressions

3
.gitignore externe Fichier normal
Voir le fichier

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

32
build.gradle.kts Fichier normal
Voir le fichier

@ -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 Fichier normal
Voir le fichier

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

2
settings.gradle Fichier normal
Voir le fichier

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

Voir le fichier

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

Voir le fichier

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

Voir le fichier

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

Voir le fichier

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