Verified Commit b24e9394 authored by Konstantin Kopper's avatar Konstantin Kopper
Browse files

Use kotlinx.serialization for pseuCo.com API calls

parent 0558f5e3
Pipeline #7536 passed with stages
in 6 minutes and 40 seconds
......@@ -8,6 +8,7 @@ if (!JavaVersion.current().isJava8Compatible)
plugins {
kotlin("jvm") version "1.3.31"
id("kotlinx-serialization") version "1.3.31"
id("org.jetbrains.dokka") version "0.9.18"
}
......@@ -30,6 +31,9 @@ dependencies {
// Coroutines
implementation("org.jetbrains.kotlinx", "kotlinx-coroutines-core", "1.2.1")
// Kotlin serialization
runtimeOnly("org.jetbrains.kotlinx", "kotlinx-serialization-runtime", "0.11.0")
// OpenJFX
if (JavaVersion.current().isJava11Compatible) {
for (pkg in listOf("base", "controls", "fxml", "graphics"))
......
......@@ -2,3 +2,13 @@ rootProject.name = "pseuco-ide"
include("pseuco-java-compiler")
project(":pseuco-java-compiler").projectDir = file("lib/pseuco-java-compiler")
pluginManagement {
resolutionStrategy {
eachPlugin {
if (requested.id.id == "kotlinx-serialization") {
useModule("org.jetbrains.kotlin:kotlin-serialization:${requested.version}")
}
}
}
}
package com.pseuco
import com.google.gson.annotations.SerializedName
import kotlinx.serialization.Required
import kotlinx.serialization.Serializable
import kotlinx.serialization.internal.CommonEnumSerializer
/**
* Class representing sharable pseuCo.com files.
......@@ -11,11 +14,13 @@ import com.google.gson.annotations.SerializedName
* @property content The actual body of the file.
* @property type The file type.
*/
data class PseuCoComFile(val name: String, val content: String, val type: Type = Type.PSEUCO) {
@Serializable
data class PseuCoComFile(val name: String, val content: String, @Required val type: Type = Type.PSEUCO) {
/**
* Enum representing the file types supported by the sharing API.
*/
@Serializable(with = Type.Companion::class)
enum class Type {
/**
......@@ -34,6 +39,15 @@ data class PseuCoComFile(val name: String, val content: String, val type: Type =
* A LTS file.
*/
@SerializedName("lts")
LTS,
LTS;
/**
* Serializer converting enum values to lower case strings.
*
* @author Konstantin Kopper
* @since 2.0.4
*/
companion object : CommonEnumSerializer<Type>("PseuCoComFile.Type", values(),
values().map { it.name.toLowerCase() }.toTypedArray())
}
}
package com.pseuco.api
import com.pseuco.PseuCoComFile
import kotlinx.serialization.CompositeDecoder
import kotlinx.serialization.Decoder
import kotlinx.serialization.Encoder
import kotlinx.serialization.KSerializer
import kotlinx.serialization.SerialDescriptor
import kotlinx.serialization.Serializable
import kotlinx.serialization.internal.SerialClassDescImpl
/**
* Class mimicking the JSON object format used by the [pseuCo.com](https://pseuco.com) sharing API.
......@@ -12,6 +19,7 @@ import com.pseuco.PseuCoComFile
* @property sharingAgreementVersion The version of the accepted sharing agreement. Required if [temporary] is `false`.
* @constructor Creates a new file exchange wrapper.
*/
@Serializable(PseuCoComExchange.Companion::class)
data class PseuCoComExchange(val file: PseuCoComFile, val temporary: Boolean, val sharingAgreementVersion: Int?) {
/**
......@@ -26,4 +34,52 @@ data class PseuCoComExchange(val file: PseuCoComFile, val temporary: Boolean, va
* Creates a new wrapper for a file to be stored permanently.
*/
constructor(file: PseuCoComFile, sharingAgreementVersion: Int) : this(file, false, sharingAgreementVersion)
/**
* Serializer for [PseuCoComExchange] objects.
*
* @author Konstantin Kopper
* @since 2.0.4
*/
companion object : KSerializer<PseuCoComExchange> {
override val descriptor: SerialDescriptor = object : SerialClassDescImpl("PseuCoComExchange") {
init {
addElement("file")
addElement("temporary")
addElement("sharingAgreementVersion")
}
}
override fun deserialize(decoder: Decoder): PseuCoComExchange {
val structure = decoder.beginStructure(descriptor)
lateinit var file: PseuCoComFile
var temporary = true
var sharingAgreementVersion: Int? = null
tailrec fun decodeAttributes(): PseuCoComExchange {
when (structure.decodeElementIndex(descriptor)) {
CompositeDecoder.READ_DONE -> {
structure.endStructure(descriptor)
return PseuCoComExchange(file, temporary, sharingAgreementVersion)
}
0 -> file = decoder.decodeSerializableValue(PseuCoComFile.serializer())
1 -> temporary = decoder.decodeBoolean()
2 -> sharingAgreementVersion = decoder.decodeInt()
}
return decodeAttributes()
}
return decodeAttributes()
}
override fun serialize(encoder: Encoder, obj: PseuCoComExchange) {
val structure = encoder.beginStructure(descriptor)
structure.encodeSerializableElement(descriptor, 0, PseuCoComFile.serializer(), obj.file)
structure.encodeBooleanElement(descriptor, 1, obj.temporary)
if (!obj.temporary)
structure.encodeIntElement(descriptor, 2, obj.sharingAgreementVersion!!)
structure.endStructure(descriptor)
}
}
}
package com.pseuco.api
import com.google.gson.Gson
import com.google.gson.JsonParseException
import com.google.gson.JsonParser
import com.pseuco.FileSharer
import com.pseuco.PseuCoComFile
import io.ktor.client.HttpClient
......@@ -11,14 +8,16 @@ import io.ktor.client.request.accept
import io.ktor.client.request.get
import io.ktor.client.request.post
import io.ktor.client.response.HttpResponse
import io.ktor.content.TextContent
import io.ktor.http.ContentType
import io.ktor.http.HttpStatusCode
import io.ktor.http.URLProtocol
import io.ktor.http.contentType
import io.ktor.http.withCharset
import kotlinx.coroutines.io.jvm.javaio.toInputStream
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonElementTypeMismatchException
import kotlinx.serialization.json.JsonException
import java.awt.Desktop
import java.io.InputStreamReader
import java.net.URI
import java.net.URISyntaxException
......@@ -39,14 +38,6 @@ object PseuCoShare : FileSharer {
*/
private val client = HttpClient(Apache)
/**
* Instance of the Gson library used to handle JSON in the sharing process.
*
* @author Konstantin Kopper
* @since 2.0.0
*/
private val jsonBuilder = Gson()
/**
* Upload a file to the [pseuCo.com](https://pseuco.com) sharing API.
* The file is only kept temporary.
......@@ -79,8 +70,9 @@ object PseuCoShare : FileSharer {
path("api", "paste", "add")
}
accept(ContentType.Application.Json.withCharset(Charsets.UTF_8))
contentType(ContentType.Application.Json)
body = jsonBuilder.toJson(if (temporary) PseuCoComExchange(file) else PseuCoComExchange(file, 1))
body = TextContent(Json.stringify(PseuCoComExchange.serializer(),
if (temporary) PseuCoComExchange(file) else PseuCoComExchange(file, 1)),
contentType = ContentType.Application.Json)
}
if (c.status != HttpStatusCode.OK)
......@@ -89,13 +81,11 @@ object PseuCoShare : FileSharer {
?.let { IllegalStateException("Response body: $it") })
return try {
URI(JsonParser().parse(InputStreamReader(c.content.toInputStream())).asJsonObject["url"].asString)
} catch (e: JsonParseException) {
throw PseuCoShareException("Parsing the API response failed.", e)
} catch (e: IllegalStateException) {
throw PseuCoShareException("Response had invalid format.", e)
} catch (e: ClassCastException) {
URI(Json.plain.parseJson(c.content.toInputStream().reader().use { it.readText() }).jsonObject["url"]!!.primitive.content)
} catch (e: JsonElementTypeMismatchException) {
throw PseuCoShareException("Response had invalid format.", e)
} catch (e: JsonException) {
throw PseuCoShareException("Parsing the API response failed.", e)
} catch (e: URISyntaxException) {
throw PseuCoShareException("Malformed URL.", e)
}
......@@ -129,8 +119,8 @@ object PseuCoShare : FileSharer {
?.let { IllegalStateException("Response body: $it") })
return try {
jsonBuilder.fromJson(InputStreamReader(c.content.toInputStream()), PseuCoComExchange::class.java).file
} catch (e: JsonParseException) {
Json.parse(PseuCoComExchange.serializer(), c.content.toInputStream().reader().use { it.readText() }).file
} catch (e: JsonException) {
throw PseuCoShareException("Parsing the API response failed.", e)
}
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment