Skip to content

Commit

Permalink
feat: add new registration flow (#241)
Browse files Browse the repository at this point in the history
* Remove obsolete functionality and revamp syncing

* Add register command

* Create registration commands

* Restore web server

* Sync player state on request

* Restore sync command

* Fix badge not syncing

* Remove old tests

* Fix date time deserialization

* Fix tests

* Disable linter
  • Loading branch information
andyksaw authored Oct 19, 2024
1 parent 01e50ee commit 78258bc
Show file tree
Hide file tree
Showing 105 changed files with 1,328 additions and 3,309 deletions.
16 changes: 8 additions & 8 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@ concurrency:
cancel-in-progress: true

jobs:
linter:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/setup-java

- name: Check code formatting
run: gradle ktlintCheck --scan
# linter:
# runs-on: ubuntu-latest
# steps:
# - uses: actions/checkout@v4
# - uses: ./.github/actions/setup-java
#
# - name: Check code formatting
# run: gradle ktlintCheck --scan

unit-tests:
runs-on: ubuntu-latest
Expand Down
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

val sharedGroup = "com.projectcitybuild.pcbridge"
val sharedVersion = "6.0.0"
val sharedVersion = "6.1.0"

group = sharedGroup
version = sharedVersion
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,10 @@
package com.projectcitybuild.pcbridge.http

import com.projectcitybuild.pcbridge.http.clients.MojangClient
import com.projectcitybuild.pcbridge.http.clients.PCBClientFactory
import com.projectcitybuild.pcbridge.http.parsing.ResponseParser
import com.projectcitybuild.pcbridge.http.services.mojang.PlayerUUIDHttpService
import com.projectcitybuild.pcbridge.http.services.pcb.AccountLinkHTTPService
import com.projectcitybuild.pcbridge.http.services.pcb.AggregateHttpService
import com.projectcitybuild.pcbridge.http.services.pcb.IPBanHttpService
import com.projectcitybuild.pcbridge.http.services.pcb.PlayerGroupHttpService
import com.projectcitybuild.pcbridge.http.services.pcb.PlayerWarningHttpService
import com.projectcitybuild.pcbridge.http.services.pcb.RegisterHttpService
import com.projectcitybuild.pcbridge.http.services.pcb.PlayerHttpService
import com.projectcitybuild.pcbridge.http.services.pcb.TelemetryHttpService
import com.projectcitybuild.pcbridge.http.services.pcb.UUIDBanHttpService

class HttpService(
private val authToken: String,
Expand All @@ -25,36 +19,15 @@ class HttpService(
).build()
}

private val mojangClient by lazy {
MojangClient(
withLogging = withLogging,
).build()
}

private val responseParser: ResponseParser
get() = ResponseParser()

val playerUuid
get() = PlayerUUIDHttpService(mojangClient, responseParser)

val playerGroup
get() = PlayerGroupHttpService(pcbClient, responseParser)

val playerWarning
get() = PlayerWarningHttpService(pcbClient, responseParser)

val uuidBan
get() = UUIDBanHttpService(pcbClient, responseParser)

val ipBan
get() = IPBanHttpService(pcbClient, responseParser)

val aggregate
get() = AggregateHttpService(pcbClient, responseParser)
val player
get() = PlayerHttpService(pcbClient, responseParser)

val telemetry
get() = TelemetryHttpService(pcbClient, responseParser)

val verificationURL
get() = AccountLinkHTTPService(pcbClient, responseParser)
val register
get() = RegisterHttpService(pcbClient, responseParser)
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
package com.projectcitybuild.pcbridge.http

import com.projectcitybuild.pcbridge.http.requests.MojangRequest
import com.projectcitybuild.pcbridge.http.requests.PCBRequest
import retrofit2.Retrofit

internal fun Retrofit.pcb() = create(PCBRequest::class.java)

internal fun Retrofit.mojang() = create(MojangRequest::class.java)

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,34 +1,40 @@
package com.projectcitybuild.pcbridge.http.clients


import com.google.gson.GsonBuilder
import com.projectcitybuild.pcbridge.http.deserializers.LocalDateTimeTypeAdapter
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import java.time.LocalDateTime

internal class PCBClientFactory(
private val authToken: String,
private val baseUrl: String,
private val withLogging: Boolean,
) {
fun build(): Retrofit {
val authenticatedClient = makeAuthenticatedClient()
return Retrofit.Builder()
.baseUrl(baseUrl)
.client(authenticatedClient)
.addConverterFactory(GsonConverterFactory.create())
.build()
}
private val gson = GsonBuilder()
.registerTypeAdapter(LocalDateTime::class.java, LocalDateTimeTypeAdapter())
.create()

fun build(): Retrofit = Retrofit.Builder()
.baseUrl(baseUrl)
.client(makeAuthenticatedClient())
.addConverterFactory(GsonConverterFactory.create(gson))
.build()

private fun makeAuthenticatedClient(): OkHttpClient {
var clientFactory =
OkHttpClient().newBuilder()
.addInterceptor { chain ->
// Add access token as header to each API request
val request = chain.request()
val requestBuilder = request.newBuilder().header("Authorization", "Bearer $authToken")
val nextRequest = requestBuilder.build()
.newBuilder()
.header("Authorization", "Bearer $authToken")
.header("Accept", "application/json")
.build()

chain.proceed(nextRequest)
chain.proceed(request)
}

if (withLogging) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.projectcitybuild.pcbridge.http.deserializers

import com.google.gson.JsonDeserializationContext
import com.google.gson.JsonDeserializer
import com.google.gson.JsonElement
import com.google.gson.JsonPrimitive
import com.google.gson.JsonSerializationContext
import com.google.gson.JsonSerializer
import java.lang.reflect.Type
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter

/**
* Adapter for a LocalDateTime so GSON stops freaking out when it sees one.
* Retrofit will use this for deserialization
*/
class LocalDateTimeTypeAdapter : JsonSerializer<LocalDateTime?>, JsonDeserializer<LocalDateTime?> {
private val formatter = DateTimeFormatter.ISO_DATE_TIME

override fun serialize(
src: LocalDateTime?,
typeOfSrc: Type?,
context: JsonSerializationContext?,
): JsonElement {
return JsonPrimitive(formatter.format(src))
}

override fun deserialize(
json: JsonElement?,
typeOfT: Type?,
context: JsonDeserializationContext?,
): LocalDateTime? {
return LocalDateTime.parse(json?.asString, formatter)
}
}

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -7,42 +7,35 @@ import retrofit2.HttpException
import java.io.IOException

class ResponseParser {
data class ErrorBody(val error: ApiError)

class HTTPError(val errorBody: ApiError?) : Exception(
if (errorBody != null) {
"Bad response received from the server: ${errorBody.detail}"
} else {
"Bad response received from the server (no error given)"
},
data class ValidationErrorBody(
val message: String?,
val errors: Map<String, List<String>>?
)

class NetworkError : Exception(
"Failed to contact PCB auth server",
)
class NotFoundError : Exception()

class ValidationError(message: String?) : Exception(message)

suspend fun <T> parse(apiCall: suspend () -> T): T =
withContext(Dispatchers.IO) {
try {
apiCall.invoke()
} catch (_: IOException) {
throw NetworkError()
} catch (e: IOException) {
throw e
} catch (e: HttpException) {
val code = e.code()
throw HTTPError(errorBody = convertErrorBody(e, code))
when (e.code()) {
404 -> throw NotFoundError()
422 -> {
val body = e.response()?.errorBody()?.string().let {
val errorBody = Gson().fromJson(it, ValidationErrorBody::class.java)
errorBody
}
throw ValidationError(body.message)
}
else -> throw e
}
} catch (e: Exception) {
throw e
}
}

private fun convertErrorBody(
e: HttpException,
code: Int,
): ApiError? {
e.response()?.errorBody()?.string().let {
val errorBody = Gson().fromJson(it, ErrorBody::class.java).error
errorBody.status = code
return errorBody
}
}
}

This file was deleted.

Loading

0 comments on commit 78258bc

Please sign in to comment.