From 4c28f7f9fbe289fcd2303a51b04ccb716a391a60 Mon Sep 17 00:00:00 2001 From: doomsdayrs Date: Sat, 19 Dec 2020 18:44:45 -0500 Subject: [PATCH] - Dropped klaxon, using kotlinx.serialization instead --- build.gradle.kts | 10 +- .../kotlin/app/shosetsu/lib/IExtension.kt | 23 +- src/main/kotlin/app/shosetsu/lib/Version.kt | 5 + .../app/shosetsu/lib/VersionSerializer.kt | 22 ++ .../kotlin/app/shosetsu/lib/json/RepoData.kt | 27 ++ .../kotlin/app/shosetsu/lib/json/RepoIndex.kt | 85 +------ .../app/shosetsu/lib/lua/LuaExtension.kt | 24 +- src/test/kotlin/app/shosetsu/lib/Test.kt | 231 +++++++++++------- 8 files changed, 235 insertions(+), 192 deletions(-) create mode 100644 src/main/kotlin/app/shosetsu/lib/VersionSerializer.kt diff --git a/build.gradle.kts b/build.gradle.kts index 08b8d60..d2dd649 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -8,6 +8,7 @@ description = "Kotlin library for shosetsu" plugins { kotlin("jvm") version "1.4.20" id("org.jetbrains.dokka") version "0.10.0" + kotlin("plugin.serialization") version "1.4.20" maven } tasks.withType { kotlinOptions.jvmTarget = "1.8" } @@ -20,7 +21,6 @@ tasks.dokka { val dokkaJar by tasks.creating(Jar::class) { group = JavaBasePlugin.DOCUMENTATION_GROUP description = "Assembles Kotlin docs with Dokka" - classifier = "javadoc" } repositories { @@ -33,13 +33,15 @@ dependencies { implementation(kotlin("stdlib")) implementation("org.jsoup:jsoup:1.12.1") implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.4.20") + + // java only implementation("org.luaj:luaj-jse:3.0.1") - implementation("com.beust:klaxon:5.0.1") implementation("com.squareup.okhttp3:okhttp:4.2.1") implementation("com.google.guava:guava:30.0-jre") - testImplementation("junit:junit:4.12") -// implementation("org.jetbrains.kolin:kotlin-test:v1.3.61") + // Cross platform confirmed + implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.0.1") + testImplementation("org.jetbrains.kotlin:kotlin-test:1.4.20") } val compileTestKotlin: KotlinCompile by tasks diff --git a/src/main/kotlin/app/shosetsu/lib/IExtension.kt b/src/main/kotlin/app/shosetsu/lib/IExtension.kt index b236c3e..8cdf34a 100644 --- a/src/main/kotlin/app/shosetsu/lib/IExtension.kt +++ b/src/main/kotlin/app/shosetsu/lib/IExtension.kt @@ -1,5 +1,9 @@ package app.shosetsu.lib +import app.shosetsu.lib.json.* +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + /* * This file is part of shosetsu-services. * shosetsu-services is free software: you can redistribute it and/or modify @@ -32,16 +36,27 @@ interface IExtension { } /** + * @param id ID * @param version 3 index array - * + * @param libVersion Version of the library this extension was made for + * @param author Author / Creator of this extension + * @param repo Repository URL that this extension is connected with + * @param dependencies */ + @Serializable data class ExMetaData( + @SerialName(J_ID) val id: Int, + @SerialName(J_VERSION) val version: Version, + @SerialName(J_LIB_VERSION) val libVersion: Version, - val author: String, - val repo: String, - val dependencies: Array> + @SerialName(J_AUTHOR) + val author: String = "", + @SerialName(J_REPO) + val repo: String = "", + @SerialName(J_DEP) + val dependencies: Map = mapOf() ) /** diff --git a/src/main/kotlin/app/shosetsu/lib/Version.kt b/src/main/kotlin/app/shosetsu/lib/Version.kt index 6008418..db021aa 100644 --- a/src/main/kotlin/app/shosetsu/lib/Version.kt +++ b/src/main/kotlin/app/shosetsu/lib/Version.kt @@ -1,5 +1,7 @@ package app.shosetsu.lib +import kotlinx.serialization.Serializable + /** * Version of the kotlin-lib shosetsu is currently using @@ -16,11 +18,14 @@ val KOTLIN_LIB_VERSION = Version(1, 0, 0) * @param minor Incremented with feature releases that don't destroy backwards compatibility * @param patch Incremented with bug fixes that don't destroy backwards compatibility */ +@Serializable(with = VersionSerializer::class) data class Version( val major: Int, val minor: Int, val patch: Int ) : Comparable { + + constructor(array: Array) : this(array[0], array[1], array[2]) constructor( diff --git a/src/main/kotlin/app/shosetsu/lib/VersionSerializer.kt b/src/main/kotlin/app/shosetsu/lib/VersionSerializer.kt new file mode 100644 index 0000000..e50aeb9 --- /dev/null +++ b/src/main/kotlin/app/shosetsu/lib/VersionSerializer.kt @@ -0,0 +1,22 @@ +package app.shosetsu.lib + +import app.shosetsu.lib.json.J_VERSION +import kotlinx.serialization.KSerializer +import kotlinx.serialization.descriptors.PrimitiveKind.STRING +import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.encoding.Decoder +import kotlinx.serialization.encoding.Encoder + +/** + * [KSerializer] for [Version], to convert it from and to string + */ +internal class VersionSerializer : KSerializer { + override fun deserialize(decoder: Decoder): Version = Version(decoder.decodeString()) + + override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor(J_VERSION, STRING) + + override fun serialize(encoder: Encoder, value: Version) { + encoder.encodeString(value.toString()) + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/shosetsu/lib/json/RepoData.kt b/src/main/kotlin/app/shosetsu/lib/json/RepoData.kt index 4fad1ca..59e3848 100644 --- a/src/main/kotlin/app/shosetsu/lib/json/RepoData.kt +++ b/src/main/kotlin/app/shosetsu/lib/json/RepoData.kt @@ -1,21 +1,41 @@ package app.shosetsu.lib.json import app.shosetsu.lib.Version +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable /** * 17 / 10 / 2020 * * Represents an extension on the repository, * listed as "scripts" in the index + * + * @param id Identification of this extension, this should always be unique + * @param name Name of the extension that is presentable to the user + * @param fileName FileName of the extension + * @param imageURL Image URL for this extension, for visual identification + * @param lang String identification of the language via (ISO 639-1) standard + * @param version Version of this extension + * @param libVersion Version the extension is compatible with + * @param md5 MD5 coding of the extension, for security checking */ +@Serializable data class RepoExtension internal constructor( + @SerialName(J_ID) val id: Int, + @SerialName(J_NAME) val name: String, + @SerialName(J_FILE_NAME) val fileName: String, + @SerialName(J_IMAGE_URL) val imageURL: String, + @SerialName(J_LANGUAGE) val lang: String, + @SerialName(J_VERSION) val version: Version, + @SerialName(J_LIB_VERSION) val libVersion: Version, + @SerialName(J_MD5) val md5: String ) @@ -24,8 +44,15 @@ data class RepoExtension internal constructor( * 17 / 10 / 2020 * * Represents a library listed in `libraries` within the repository index + * + * @param name Name of the library, this is always the same as the filename + * + * @param version Version of the library */ +@Serializable data class RepoLibrary internal constructor( + @SerialName(J_NAME) val name: String, + @SerialName(J_VERSION) val version: Version ) \ No newline at end of file diff --git a/src/main/kotlin/app/shosetsu/lib/json/RepoIndex.kt b/src/main/kotlin/app/shosetsu/lib/json/RepoIndex.kt index 65df87e..1ffd4f9 100644 --- a/src/main/kotlin/app/shosetsu/lib/json/RepoIndex.kt +++ b/src/main/kotlin/app/shosetsu/lib/json/RepoIndex.kt @@ -1,12 +1,10 @@ package app.shosetsu.lib.json -import app.shosetsu.lib.Version -import app.shosetsu.lib.exceptions.JsonMissingKeyException -import com.beust.klaxon.JsonObject -import com.beust.klaxon.Parser +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import kotlinx.serialization.decodeFromString +import kotlinx.serialization.json.Json import java.io.File -import java.io.FileReader -import java.io.StringReader /** * shosetsu-kotlin-lib @@ -14,81 +12,18 @@ import java.io.StringReader * @param libraries Libraries used by the repository * @param extensions Extensions listed in this repository */ +@Serializable data class RepoIndex internal constructor( + @SerialName(LIBS_KEY) val libraries: List, + + @SerialName(SCPS_KEY) val extensions: List ) { companion object { const val LIBS_KEY = "libraries" const val SCPS_KEY = "scripts" - } - - constructor(jsonFile: File) : this( - Parser.default().parse(FileReader(jsonFile)) as JsonObject - ) - constructor(jsonString: String) : this( - Parser.default().parse(StringReader(jsonString)) as JsonObject - ) - - // Using .toAndroid() to provide android compatiblity - internal constructor(json: JsonObject) : this( - json.array(LIBS_KEY)?.map { - RepoLibrary( - name = it.string(J_NAME) ?: throw JsonMissingKeyException( - LIBS_KEY, - J_NAME - ), - version = Version( - it.string(J_VERSION) ?: throw JsonMissingKeyException( - LIBS_KEY, - J_VERSION - ) - ) - ) - } ?: emptyList(), - json.array(SCPS_KEY)?.map { - RepoExtension( - id = it.int(J_ID) ?: throw JsonMissingKeyException( - SCPS_KEY, - J_ID - ), - name = it.string(J_NAME) ?: throw JsonMissingKeyException( - SCPS_KEY, - J_NAME - ), - fileName = it.string(J_FILE_NAME) - ?: throw JsonMissingKeyException( - SCPS_KEY, - J_FILE_NAME - ), - imageURL = it.string(J_IMAGE_URL) - ?: throw JsonMissingKeyException( - SCPS_KEY, - J_IMAGE_URL - ), - lang = it.string(J_LANGUAGE) ?: throw JsonMissingKeyException( - SCPS_KEY, - J_LANGUAGE - ), - version = Version( - it.string(J_VERSION) ?: throw JsonMissingKeyException( - SCPS_KEY, - J_VERSION - ) - ), - libVersion = Version( - it.string(J_LIB_VERSION) - ?: throw JsonMissingKeyException( - SCPS_KEY, - J_LIB_VERSION - ) - ), - md5 = it.string(J_MD5) ?: throw JsonMissingKeyException( - SCPS_KEY, - J_MD5 - ) - ) - } ?: emptyList() - ) + fun fromString(json: String): RepoIndex = Json.decodeFromString(json) + } } diff --git a/src/main/kotlin/app/shosetsu/lib/lua/LuaExtension.kt b/src/main/kotlin/app/shosetsu/lib/lua/LuaExtension.kt index 8f766e1..ab06a7c 100644 --- a/src/main/kotlin/app/shosetsu/lib/lua/LuaExtension.kt +++ b/src/main/kotlin/app/shosetsu/lib/lua/LuaExtension.kt @@ -3,9 +3,8 @@ package app.shosetsu.lib.lua import app.shosetsu.lib.* import app.shosetsu.lib.exceptions.InvalidFilterIDException import app.shosetsu.lib.exceptions.MissingOrInvalidKeysException -import app.shosetsu.lib.json.* -import com.beust.klaxon.JsonObject -import com.beust.klaxon.Parser +import kotlinx.serialization.decodeFromString +import kotlinx.serialization.json.Json import org.luaj.vm2.LuaString.EMPTYSTRING import org.luaj.vm2.LuaTable import org.luaj.vm2.LuaValue @@ -13,7 +12,6 @@ import org.luaj.vm2.LuaValue.* import org.luaj.vm2.lib.jse.CoerceJavaToLua.coerce import org.luaj.vm2.lib.jse.CoerceLuaToJava import java.io.File -import java.io.StringReader /* * This file is part of shosetsu-services. @@ -99,23 +97,7 @@ class LuaExtension( */ @Suppress("unused") override val exMetaData: IExtension.ExMetaData by lazy { - val metaString = content.lines().first() - .replace("--", "").trim() - val json = - Parser.default().parse(StringReader(metaString)) as JsonObject - IExtension.ExMetaData( - id = json.int(J_ID)!!, - version = Version(json.string(J_VERSION)!!), - libVersion = Version(json.string(J_LIB_VERSION)!!), - author = json.string(J_AUTHOR)!!, - repo = json.string(J_REPO) ?: "", - // Using .toAndroid() to provide android compatiblity - dependencies = json.array(J_DEP)?.map { - it.split(">=").let { split -> - split[0] to Version(split[1]) - } - }?.toTypedArray() ?: arrayOf() - ) + Json.decodeFromString(content.lines().first().replaceFirst("--", "").trim()) } private val source: LuaTable diff --git a/src/test/kotlin/app/shosetsu/lib/Test.kt b/src/test/kotlin/app/shosetsu/lib/Test.kt index 0d49182..c96692b 100644 --- a/src/test/kotlin/app/shosetsu/lib/Test.kt +++ b/src/test/kotlin/app/shosetsu/lib/Test.kt @@ -4,6 +4,8 @@ import app.shosetsu.lib.json.RepoIndex import app.shosetsu.lib.lua.LuaExtension import app.shosetsu.lib.lua.ShosetsuLuaLib import app.shosetsu.lib.lua.shosetsuGlobals +import kotlinx.serialization.encodeToString +import kotlinx.serialization.json.Json import okhttp3.OkHttpClient import org.luaj.vm2.LuaValue import java.io.File @@ -41,37 +43,43 @@ object Test { // CONFIG private const val SEARCH_VALUE = "world" - private const val PRINT_LISTINGS = true - private const val PRINT_LIST_STATS = true + private const val PRINT_LISTINGS = false + private const val PRINT_LIST_STATS = false private const val PRINT_NOVELS = false - private const val PRINT_NOVEL_STATS = true + private const val PRINT_NOVEL_STATS = false private const val PRINT_PASSAGES = false - private const val PRINT_REPO_INDEX = false - private const val PRINT_META_DATA = false + private const val PRINT_REPO_INDEX = true + private const val PRINT_META_DATA = true private const val REPEAT = false + /** Load only the [SPECIFIC_NOVEL_URL] to test */ + private const val SPECIFIC_NOVEL = false + + /** Novel to load via the extension, useful for novel cases */ + private const val SPECIFIC_NOVEL_URL = "/god-of-slaughter" + // END CONFIG private val SOURCES: List = arrayOf( - //"en/BestLightNovel", - //"en/BoxNovel", - //"en/CreativeNovels", - //"en/FastNovel", - //"en/Foxaholic", // TODO: Investigate - //"en/KissLightNovels", - //"en/MNovelFree", //Doesn't seem to be a novelfull - //"en/MTLNovel", - //"en/NovelFull", - //"en/NovelTrench", - //"en/ReadLightNovel", - //"en/ReadNovelFull", - //"en/VipNovel", - //"en/VolareNovels", - //"en/WuxiaWorld", - //"jp/Syosetsu", - //"pt/SaikaiScan", - //"zn/15doc", - //"zn/Tangsanshu" + //"en/BestLightNovel", + //"en/BoxNovel", + //"en/CreativeNovels", + //"en/FastNovel", + //"en/Foxaholic", // TODO: Investigate + //"en/KissLightNovels", + //"en/MNovelFree", //Doesn't seem to be a novelfull + //"en/MTLNovel", + //"en/NovelFull", + //"en/NovelTrench", + "en/ReadLightNovel", + //"en/ReadNovelFull", + //"en/VipNovel", + //"en/VolareNovels", + //"en/WuxiaWorld", + //"jp/Syosetsu", + //"pt/SaikaiScan", + //"zn/15doc", + //"zn/Tangsanshu" ).map { "src/main/resources/src/$it.lua" } private val globals = shosetsuGlobals() @@ -86,8 +94,8 @@ object Test { ShosetsuLuaLib.libLoader = { outputTimedValue("loadScript") { loadScript( - File("src/main/resources/lib/$it.lua"), - "lib" + File("src/main/resources/lib/$it.lua"), + "lib" ) } } @@ -109,6 +117,40 @@ object Test { return l.call()!! } + private fun showNovel(ext: IExtension, novelURL: String) { + val novel = outputTimedValue("ext.parseNovel") { + ext.parseNovel(novelURL, true) + } + + while (novel.chapters.isEmpty()) { + println("$CRED Chapters are empty $CRESET") + return + } + + if (PRINT_NOVELS) + println(novel) + + if (PRINT_NOVEL_STATS) + println("${novel.title} - ${novel.chapters.size} chapters.") + + println() + + + val passage = outputTimedValue("ext.getPassage") { + ext.getPassage(novel.chapters[0].link) + } + + + if (PRINT_PASSAGES) + println("Passage:\t$passage") + else + println(with(passage) { + if (length < 25) "Result: $this" + else "$length chars long result: " + + "${take(10)} [...] ${takeLast(10)}" + }) + } + @ExperimentalTime @Suppress("ConstantConditionIf") private fun showListing(ext: IExtension, novels: Array) { @@ -190,7 +232,7 @@ object Test { } is Filter.Group<*> -> { (filter.filters as Array>) - .printOut(indent + 1) + .printOut(indent + 1) } else -> { } @@ -222,117 +264,130 @@ object Test { try { if (PRINT_REPO_INDEX) println(outputTimedValue("RepoIndexLoad") { - RepoIndex( + Json { prettyPrint = true }.encodeToString( + RepoIndex.fromString( File("src/main/resources/index.json") - .readText() + .readText() + ) ) }) - for (extensionPath in SOURCES) { - println("\n\n========== $extensionPath ==========") + kotlin.run { + for (extensionPath in SOURCES) { + println("\n\n========== $extensionPath ==========") - val extension = outputTimedValue("LuaExtension") { - LuaExtension(File(extensionPath)) - } - val settingsModel: Map = + val extension = outputTimedValue("LuaExtension") { + LuaExtension(File(extensionPath)) + } + + if (SPECIFIC_NOVEL) { + showNovel(extension, SPECIFIC_NOVEL_URL) + return@run + } + + + val settingsModel: Map = extension.settingsModel.also { println("Settings model:") it.printOut() }.mapify() - val searchFiltersModel: Map = + val searchFiltersModel: Map = extension.searchFiltersModel.also { println("SearchFilters Model:") it.printOut() }.mapify() - println(CCYAN) - println("ID : ${extension.formatterID}") - println("Name : ${extension.name}") - println("BaseURL : ${extension.baseURL}") - println("Image : ${extension.imageURL}") - println("Settings : $settingsModel") - println("Filters : $searchFiltersModel") - if (PRINT_META_DATA) - println("MetaData : ${extension.exMetaData}") - println(CRESET) - - extension.listings.forEach { l -> - with(l) { - print("\n-------- Listing \"${name}\" ") - print(if (isIncrementing) "(incrementing)" else "") - println(" --------") - - var novels = getListing( + println(CCYAN) + println("ID : ${extension.formatterID}") + println("Name : ${extension.name}") + println("BaseURL : ${extension.baseURL}") + println("Image : ${extension.imageURL}") + println("Settings : $settingsModel") + println("Filters : $searchFiltersModel") + if (PRINT_META_DATA) + println("MetaData : ${Json { prettyPrint = true }.encodeToString(extension.exMetaData)}") + println(CRESET) + + extension.listings.forEach { l -> + with(l) { + print("\n-------- Listing \"${name}\" ") + print(if (isIncrementing) "(incrementing)" else "") + println(" --------") + + var novels = getListing( HashMap(searchFiltersModel).apply { this[PAGE_INDEX] = - if (isIncrementing) 1 else null + if (isIncrementing) 1 else null } - ) + ) - if (isIncrementing) - novels += getListing(HashMap(searchFiltersModel) + if (isIncrementing) + novels += getListing(HashMap(searchFiltersModel) .apply { this[PAGE_INDEX] = 2 }) - if (REPEAT) { - novels = getListing( + if (REPEAT) { + novels = getListing( HashMap(searchFiltersModel).apply { this[PAGE_INDEX] = - if (isIncrementing) 1 else null + if (isIncrementing) 1 else null } - ) + ) - if (isIncrementing) - novels += getListing(HashMap(searchFiltersModel) + if (isIncrementing) + novels += getListing(HashMap(searchFiltersModel) .apply { this[PAGE_INDEX] = 2 }) - } + } - showListing(extension, novels) - try { - MILLISECONDS.sleep(500) - } catch (e: InterruptedException) { - e.printStackTrace() + showListing(extension, novels) + try { + MILLISECONDS.sleep(500) + } catch (e: InterruptedException) { + e.printStackTrace() + } } } - } - if (extension.hasSearch) { - println("\n-------- Search --------") - showListing( + if (extension.hasSearch) { + println("\n-------- Search --------") + showListing( extension, outputTimedValue("ext.search") { extension.search( - HashMap(searchFiltersModel).apply { - set(QUERY_INDEX, SEARCH_VALUE) - set(PAGE_INDEX, 0) - } + HashMap(searchFiltersModel).apply { + set(QUERY_INDEX, SEARCH_VALUE) + set(PAGE_INDEX, 0) + } ) } - ) - if (extension.isSearchIncrementing) { - showListing( + ) + if (extension.isSearchIncrementing) { + showListing( extension, outputTimedValue("ext.search") { extension.search( - HashMap(searchFiltersModel).apply { - set(QUERY_INDEX, SEARCH_VALUE) - set(PAGE_INDEX, 2) - } + HashMap(searchFiltersModel).apply { + set(QUERY_INDEX, SEARCH_VALUE) + set(PAGE_INDEX, 2) + } ) } - ) + ) + } } - } - MILLISECONDS.sleep(500) + MILLISECONDS.sleep(500) + } } + + println("\n\tTESTS COMPLETE") } catch (e: Exception) { e.printStackTrace()