Init empty project
This commit is contained in:
19
src/main/kotlin/io/github/flecomte/Application.kt
Normal file
19
src/main/kotlin/io/github/flecomte/Application.kt
Normal file
@@ -0,0 +1,19 @@
|
||||
package io.github.flecomte
|
||||
|
||||
import io.github.flecomte.plugins.*
|
||||
import io.ktor.server.application.*
|
||||
import io.ktor.server.engine.*
|
||||
import io.ktor.server.netty.*
|
||||
|
||||
fun main() {
|
||||
embeddedServer(Netty, port = 8080, host = "0.0.0.0", module = Application::module)
|
||||
.start(wait = true)
|
||||
}
|
||||
|
||||
fun Application.module() {
|
||||
configureSecurity()
|
||||
configureSerialization()
|
||||
configureSockets()
|
||||
configureHTTP()
|
||||
configureRouting()
|
||||
}
|
||||
17
src/main/kotlin/io/github/flecomte/plugins/HTTP.kt
Normal file
17
src/main/kotlin/io/github/flecomte/plugins/HTTP.kt
Normal file
@@ -0,0 +1,17 @@
|
||||
package io.github.flecomte.plugins
|
||||
|
||||
import io.ktor.http.*
|
||||
import io.ktor.server.application.*
|
||||
import io.ktor.server.plugins.cors.routing.*
|
||||
|
||||
fun Application.configureHTTP() {
|
||||
install(CORS) {
|
||||
allowMethod(HttpMethod.Options)
|
||||
allowMethod(HttpMethod.Put)
|
||||
allowMethod(HttpMethod.Delete)
|
||||
allowMethod(HttpMethod.Patch)
|
||||
allowHeader(HttpHeaders.Authorization)
|
||||
allowHeader("MyCustomHeader")
|
||||
anyHost() // @TODO: Don't do this in production if possible. Try to limit it.
|
||||
}
|
||||
}
|
||||
35
src/main/kotlin/io/github/flecomte/plugins/Routing.kt
Normal file
35
src/main/kotlin/io/github/flecomte/plugins/Routing.kt
Normal file
@@ -0,0 +1,35 @@
|
||||
package io.github.flecomte.plugins
|
||||
|
||||
import io.ktor.http.*
|
||||
import io.ktor.resources.*
|
||||
import io.ktor.server.application.*
|
||||
import io.ktor.server.plugins.autohead.*
|
||||
import io.ktor.server.plugins.statuspages.*
|
||||
import io.ktor.server.resources.*
|
||||
import io.ktor.server.resources.Resources
|
||||
import io.ktor.server.response.*
|
||||
import io.ktor.server.routing.*
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
fun Application.configureRouting() {
|
||||
install(AutoHeadResponse)
|
||||
install(Resources)
|
||||
install(StatusPages) {
|
||||
exception<Throwable> { call, cause ->
|
||||
call.respondText(text = "500: $cause", status = HttpStatusCode.InternalServerError)
|
||||
}
|
||||
}
|
||||
routing {
|
||||
get("/") {
|
||||
call.respondText("Hello World!")
|
||||
}
|
||||
get<Articles> { article ->
|
||||
// Get all articles ...
|
||||
call.respond("List of articles sorted starting from ${article.sort}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
@Resource("/articles")
|
||||
class Articles(val sort: String? = "new")
|
||||
66
src/main/kotlin/io/github/flecomte/plugins/Security.kt
Normal file
66
src/main/kotlin/io/github/flecomte/plugins/Security.kt
Normal file
@@ -0,0 +1,66 @@
|
||||
package io.github.flecomte.plugins
|
||||
|
||||
import com.auth0.jwt.JWT
|
||||
import com.auth0.jwt.algorithms.Algorithm
|
||||
import io.ktor.server.application.*
|
||||
import io.ktor.server.auth.*
|
||||
import io.ktor.server.auth.jwt.*
|
||||
import io.ktor.server.response.*
|
||||
import io.ktor.server.routing.*
|
||||
|
||||
fun Application.configureSecurity() {
|
||||
// Please read the jwt property from the config file if you are using EngineMain
|
||||
val jwtAudience = "jwt-audience"
|
||||
val jwtDomain = "https://jwt-provider-domain/"
|
||||
val jwtRealm = "ktor sample app"
|
||||
val jwtSecret = "secret"
|
||||
authentication {
|
||||
jwt {
|
||||
realm = jwtRealm
|
||||
verifier(
|
||||
JWT
|
||||
.require(Algorithm.HMAC256(jwtSecret))
|
||||
.withAudience(jwtAudience)
|
||||
.withIssuer(jwtDomain)
|
||||
.build()
|
||||
)
|
||||
validate { credential ->
|
||||
if (credential.payload.audience.contains(jwtAudience)) JWTPrincipal(credential.payload) else null
|
||||
}
|
||||
}
|
||||
}
|
||||
authentication {
|
||||
basic(name = "myauth1") {
|
||||
realm = "Ktor Server"
|
||||
validate { credentials ->
|
||||
if (credentials.name == credentials.password) {
|
||||
UserIdPrincipal(credentials.name)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
form(name = "myauth2") {
|
||||
userParamName = "user"
|
||||
passwordParamName = "password"
|
||||
challenge {
|
||||
/**/
|
||||
}
|
||||
}
|
||||
}
|
||||
routing {
|
||||
authenticate("myauth1") {
|
||||
get("/protected/route/basic") {
|
||||
val principal = call.principal<UserIdPrincipal>()!!
|
||||
call.respondText("Hello ${principal.name}")
|
||||
}
|
||||
}
|
||||
authenticate("myauth2") {
|
||||
get("/protected/route/form") {
|
||||
val principal = call.principal<UserIdPrincipal>()!!
|
||||
call.respondText("Hello ${principal.name}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
18
src/main/kotlin/io/github/flecomte/plugins/Serialization.kt
Normal file
18
src/main/kotlin/io/github/flecomte/plugins/Serialization.kt
Normal file
@@ -0,0 +1,18 @@
|
||||
package io.github.flecomte.plugins
|
||||
|
||||
import io.ktor.serialization.kotlinx.json.*
|
||||
import io.ktor.server.application.*
|
||||
import io.ktor.server.plugins.contentnegotiation.*
|
||||
import io.ktor.server.response.*
|
||||
import io.ktor.server.routing.*
|
||||
|
||||
fun Application.configureSerialization() {
|
||||
install(ContentNegotiation) {
|
||||
json()
|
||||
}
|
||||
routing {
|
||||
get("/json/kotlinx-serialization") {
|
||||
call.respond(mapOf("hello" to "world"))
|
||||
}
|
||||
}
|
||||
}
|
||||
29
src/main/kotlin/io/github/flecomte/plugins/Sockets.kt
Normal file
29
src/main/kotlin/io/github/flecomte/plugins/Sockets.kt
Normal file
@@ -0,0 +1,29 @@
|
||||
package io.github.flecomte.plugins
|
||||
|
||||
import io.ktor.server.application.*
|
||||
import io.ktor.server.routing.*
|
||||
import io.ktor.server.websocket.*
|
||||
import io.ktor.websocket.*
|
||||
import java.time.Duration
|
||||
|
||||
fun Application.configureSockets() {
|
||||
install(WebSockets) {
|
||||
pingPeriod = Duration.ofSeconds(15)
|
||||
timeout = Duration.ofSeconds(15)
|
||||
maxFrameSize = Long.MAX_VALUE
|
||||
masking = false
|
||||
}
|
||||
routing {
|
||||
webSocket("/ws") { // websocketSession
|
||||
for (frame in incoming) {
|
||||
if (frame is Frame.Text) {
|
||||
val text = frame.readText()
|
||||
outgoing.send(Frame.Text("YOU SAID: $text"))
|
||||
if (text.equals("bye", ignoreCase = true)) {
|
||||
close(CloseReason(CloseReason.Codes.NORMAL, "Client said BYE"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
12
src/main/resources/logback.xml
Normal file
12
src/main/resources/logback.xml
Normal file
@@ -0,0 +1,12 @@
|
||||
<configuration>
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>%d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
<root level="trace">
|
||||
<appender-ref ref="STDOUT"/>
|
||||
</root>
|
||||
<logger name="org.eclipse.jetty" level="INFO"/>
|
||||
<logger name="io.netty" level="INFO"/>
|
||||
</configuration>
|
||||
21
src/test/kotlin/io/github/flecomte/ApplicationTest.kt
Normal file
21
src/test/kotlin/io/github/flecomte/ApplicationTest.kt
Normal file
@@ -0,0 +1,21 @@
|
||||
package io.github.flecomte
|
||||
|
||||
import io.github.flecomte.plugins.*
|
||||
import io.ktor.client.request.*
|
||||
import io.ktor.client.statement.*
|
||||
import io.ktor.http.*
|
||||
import io.ktor.server.testing.*
|
||||
import kotlin.test.*
|
||||
|
||||
class ApplicationTest {
|
||||
@Test
|
||||
fun testRoot() = testApplication {
|
||||
application {
|
||||
configureRouting()
|
||||
}
|
||||
client.get("/").apply {
|
||||
assertEquals(HttpStatusCode.OK, status)
|
||||
assertEquals("Hello World!", bodyAsText())
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user