Move all tracker code to its own package and switch to Netty Engine instead of embeddedServer

This commit is contained in:
ProtoByter 2022-12-05 15:59:35 +00:00
parent 2c5adf86a1
commit 55587fa9a5
11 changed files with 64 additions and 85 deletions

View File

@ -5,10 +5,12 @@ import kotlinx.coroutines.*
import org.bitlet.weupnp.GatewayDevice
import org.bitlet.weupnp.GatewayDiscover
data class MappedPort(val port: Int, val protocol: String)
object UPnPManager {
var gateway: GatewayDevice? = null
val mappedPorts = mutableMapOf<Int, Int>()
var discoveryJob: Job = Job()
private var gateway: GatewayDevice? = null
private val mappedPorts = mutableMapOf<Int, MappedPort>()
private var discoveryJob: Job = Job()
init {
runBlocking {
@ -23,7 +25,8 @@ object UPnPManager {
for (i in 0..9) {
Logging.info("Searching for UPnP gateway... (Attempt ${i + 1})")
gatewayDiscoverer.discover()
if (gatewayDiscoverer.getValidGateway() != null) {
gateway = GatewayDevice()
if (gatewayDiscoverer.validGateway != null) {
gateway = gatewayDiscoverer.validGateway
break
}
@ -38,29 +41,29 @@ object UPnPManager {
mappedPorts.clear()
ports.map {
mapPort(it.key, it.value)
mapPort(it.key, it.value.port, it.value.protocol)
}
}
}
fun mapPort(port: Int) {
mapPort(port, port)
fun mapPort(port: Int, protocol: String = "TCP") {
mapPort(port, port, protocol)
}
fun mapPort(internalPort: Int, externalPort: Int) {
fun mapPort(internalPort: Int, externalPort: Int, protocol: String = "TCP") {
if (gateway == null) {
mappedPorts.put(internalPort, externalPort)
mappedPorts[internalPort] = MappedPort(externalPort, protocol)
}
val succeeded = gateway?.addPortMapping(externalPort, internalPort, gateway!!.localAddress.hostAddress, "TCP", "OpenProximityChat mapped port")
if (succeeded == true) {
mappedPorts.put(internalPort, externalPort)
mappedPorts[internalPort] = MappedPort(externalPort, protocol)
}
}
fun unMapAll() {
mappedPorts.map {
gateway?.deletePortMapping(it.value, "UDP")
gateway?.deletePortMapping(it.value.port, it.value.protocol)
}
}
}

View File

@ -18,7 +18,7 @@ group = "org.muellerssoftware.openproximitychat"
version = "0.0.1"
application {
mainClass.set("org.muellerssoftware.openproximitychat.ApplicationKt")
mainClass.set("io.ktor.server.netty.EngineMain")
val isDevelopment: Boolean = project.ext.has("development")
applicationDefaultJvmArgs = listOf("-Dio.ktor.development=$isDevelopment")
@ -32,6 +32,7 @@ dependencies {
// JUnit
testImplementation(platform("org.junit:junit-bom:$junit_version"))
testImplementation("org.junit.jupiter:junit-jupiter")
testImplementation("org.jetbrains.kotlin:kotlin-test-junit:$kotlin_version")
// Ktor
implementation("io.ktor:ktor-server-core-jvm:$ktor_version")
@ -41,12 +42,11 @@ dependencies {
implementation("io.ktor:ktor-serialization-kotlinx-json-jvm:$ktor_version")
implementation("io.ktor:ktor-server-auth-jvm:$ktor_version")
implementation("io.ktor:ktor-server-netty-jvm:$ktor_version")
implementation("ch.qos.logback:logback-classic:$logback_version")
implementation("io.ktor:ktor-server-config-yaml:$ktor_version")
testImplementation("io.ktor:ktor-server-tests-jvm:$ktor_version")
testImplementation("org.jetbrains.kotlin:kotlin-test-junit:$kotlin_version")
// UPNP
implementation("org.bitlet:weupnp:$weupnp_version")
// Logging
implementation("ch.qos.logback:logback-classic:$logback_version")
// Jetbrains Exposed
implementation("org.jetbrains.exposed:exposed-core:$exposed_version")
@ -56,6 +56,9 @@ dependencies {
// H2
implementation("com.h2database:h2:$db_version")
// Common Kotlin
implementation(project(":common"))
}
tasks {

View File

@ -1,26 +1,34 @@
package org.muellerssoftware.openproximitychat
package org.muellerssoftware.openproximitychat.tracker
import io.ktor.http.*
import io.ktor.serialization.kotlinx.json.*
import io.ktor.server.application.*
import io.ktor.server.auth.*
import io.ktor.server.engine.*
import io.ktor.server.netty.*
import io.ktor.server.plugins.*
import io.ktor.server.plugins.contentnegotiation.*
import io.ktor.server.request.*
import io.ktor.server.response.*
import io.ktor.server.routing.*
import org.muellerssoftware.openproximitychat.common.Logging
import org.muellerssoftware.openproximitychat.common.UPnPManager
import java.util.*
fun main() {
embeddedServer(Netty, port = 8080, host = "0.0.0.0", module = Application::module)
.start(wait = true)
}
fun main(args: Array<String>): Unit = io.ktor.server.netty.EngineMain.main(args)
fun Application.module() {
Logging.logger = log
environment.monitor.subscribe(ApplicationStarted) {
log.info("Application started")
UPnPManager.mapPort(this.environment.config.port, "TCP")
}
environment.monitor.subscribe(ApplicationStopping) {
log.info("Application stopping")
UPnPManager.unMapAll()
}
authentication {
basic("auth") {
basic("basicAuth") {
realm = "OpenProximityChat"
validate { credentials ->
val id = UUID.fromString(credentials.name)
@ -33,6 +41,10 @@ fun Application.module() {
}
}
install(ContentNegotiation) {
json()
}
routing {
get("/info") {
call.respondText("""
@ -78,12 +90,17 @@ fun Application.module() {
if (client != null) {
call.respond(HttpStatusCode.BadRequest, "Invalid request")
} else {
val id = DatabaseHandler.addClient(request.id, request.name,this.call.request.origin.remoteHost+":${this.call.request.origin.port}", request.sampledClients)
val id = DatabaseHandler.addClient(
request.id,
request.name,
this.call.request.origin.remoteHost + ":${this.call.request.origin.port}",
request.sampledClients
)
call.respond(HttpStatusCode.OK, RegisterResponse(id))
}
}
authenticate("auth") {
authenticate("basicAuth") {
post("/protected/heartbeat") {
try {
val password = DatabaseHandler.doHeartbeat(call.principal<ClientPrincipal>()!!.uuid)
@ -124,8 +141,4 @@ fun Application.module() {
}
}
}
install(ContentNegotiation) {
json()
}
}

View File

@ -1,6 +1,6 @@
@file:UseSerializers(UUIDAsStringSerializer::class, InstantAsStringSerializer::class)
package org.muellerssoftware.openproximitychat
package org.muellerssoftware.openproximitychat.tracker
import kotlinx.serialization.Serializable
import kotlinx.serialization.UseSerializers

View File

@ -1,4 +1,4 @@
package org.muellerssoftware.openproximitychat
package org.muellerssoftware.openproximitychat.tracker
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.KSerializer

View File

@ -1,6 +1,6 @@
@file:UseSerializers(UUIDAsStringSerializer::class)
package org.muellerssoftware.openproximitychat
package org.muellerssoftware.openproximitychat.tracker
import io.ktor.server.auth.*
import kotlinx.serialization.Serializable

View File

@ -1,4 +1,4 @@
package org.muellerssoftware.openproximitychat
package org.muellerssoftware.openproximitychat.tracker
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.KSerializer

View File

@ -1,4 +1,4 @@
package org.muellerssoftware.openproximitychat
package org.muellerssoftware.openproximitychat.tracker
import io.ktor.server.application.*

View File

@ -0,0 +1,6 @@
ktor:
deployment:
port: 0
application:
modules:
- org.muellerssoftware.openproximitychat.tracker.ApplicationKt.module

View File

@ -1,4 +1,4 @@
package org.muellerssoftware.openproximitychat
package org.muellerssoftware.openproximitychat.tracker
import io.ktor.client.call.*
import io.ktor.client.plugins.contentnegotiation.*
@ -12,7 +12,8 @@ import kotlin.test.Test
import kotlin.test.assertEquals
class ApplicationKtTest {
val sampledClientsTestVal = listOf(UUID.randomUUID(), UUID.randomUUID(), UUID.randomUUID(), UUID.randomUUID(), UUID.randomUUID(), UUID.randomUUID(), UUID.randomUUID(), UUID.randomUUID())
private val sampledClientsTestVal = listOf(UUID.randomUUID(), UUID.randomUUID(), UUID.randomUUID(), UUID.randomUUID(), UUID.randomUUID(), UUID.randomUUID(), UUID.randomUUID(), UUID.randomUUID())
@Before
fun addTestData() {
DatabaseHandler.clear()
@ -27,10 +28,6 @@ class ApplicationKtTest {
}
}
application {
module()
}
addTestData()
val pw_hash = DatabaseHandler.getClient("TestClient1")!!.passwordHash
@ -49,10 +46,6 @@ class ApplicationKtTest {
}
}
application {
module()
}
addTestData()
client.post("/protected/exit") {
@ -71,10 +64,6 @@ class ApplicationKtTest {
}
}
application {
module()
}
addTestData()
val pw_hash = DatabaseHandler.getClient("TestClient1")!!.passwordHash
@ -88,10 +77,6 @@ class ApplicationKtTest {
@Test
fun testPostExitNoBody() = testApplication {
application {
module()
}
client.post("/protected/exit").apply {
assertEquals(401, this.status.value)
}
@ -99,10 +84,6 @@ class ApplicationKtTest {
@Test
fun testHeartbeatRequestNoBody() = testApplication {
application {
module()
}
client.post("/protected/heartbeat").apply {
assertEquals(401, this.status.value)
}
@ -120,10 +101,6 @@ class ApplicationKtTest {
val pw_hash = DatabaseHandler.getClient("TestClient1")!!.passwordHash
application {
module()
}
client.post("/protected/heartbeat") {
basicAuth("00000000-0000-0000-0000-000000000001", pw_hash)
}.apply {
@ -140,10 +117,6 @@ class ApplicationKtTest {
}
}
application {
module()
}
addTestData()
client.post("/protected/heartbeat") {
@ -155,10 +128,6 @@ class ApplicationKtTest {
@Test
fun testRegisterRequestNoBody() = testApplication {
application {
module()
}
client.post("/register").apply {
assertEquals(400, this.status.value)
}
@ -172,10 +141,6 @@ class ApplicationKtTest {
}
}
application {
module()
}
client.post("/register") {
contentType(ContentType.Application.Json)
setBody(
@ -201,10 +166,6 @@ class ApplicationKtTest {
}
}
application {
module()
}
client.post("/register") {
contentType(ContentType.Application.Json)
setBody(
@ -224,9 +185,6 @@ class ApplicationKtTest {
@Test
fun testSearchRequestNoBody() = testApplication {
application {
module()
}
client.get("/protected/search").apply {
assertEquals(401, this.status.value)
@ -241,10 +199,6 @@ class ApplicationKtTest {
}
}
application {
module()
}
addTestData()
val pw_hash = DatabaseHandler.getClient("TestClient1")!!.passwordHash

View File

@ -1,4 +1,4 @@
package org.muellerssoftware.openproximitychat
package org.muellerssoftware.openproximitychat.tracker
import org.h2.security.SHA3
import org.junit.Before