Skip to content
This repository was archived by the owner on Nov 13, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/docs.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Deploy dokka to Github Pages
name: Deploy docs

on:
push:
Expand Down
16 changes: 13 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,19 @@
![Kotlin Version](https://img.shields.io/badge/Kotlin-2.1.0-green?style=flat-square&logo=kotlin)
![Status](https://img.shields.io/badge/Status-Beta-yellowgreen?style=flat-square)

[![Gradle](https://img.shields.io/badge/Gradle-8.11.1-informational?style=flat-square&logo=gradle)](https://github.com/gradle/gradle)
[![Gradle](https://img.shields.io/badge/Gradle-8.12.0-informational?style=flat-square&logo=gradle)](https://github.com/gradle/gradle)
[![Ktlint](https://img.shields.io/badge/Ktlint-1.5.0-informational?style=flat-square)](https://github.com/pinterest/ktlint)

[![Github - Version](https://img.shields.io/github/v/tag/Buried-In-Code/Kraken?logo=Github&label=Version&style=flat-square)](https://github.com/Buried-In-Code/Kraken/tags)
[![Github - License](https://img.shields.io/github/license/Buried-In-Code/Kraken?logo=Github&label=License&style=flat-square)](https://opensource.org/licenses/MIT)
[![Github - Contributors](https://img.shields.io/github/contributors/Buried-In-Code/Kraken?logo=Github&label=Contributors&style=flat-square)](https://github.com/Buried-In-Code/Kraken/graphs/contributors)

[![Github Action - Testing](https://img.shields.io/github/actions/workflow/status/Buried-In-Code/Kraken/testing.yaml?branch=main&logo=githubactions&label=Testing&style=flat-square)](https://github.com/Buried-In-Code/Kraken/actions/workflows/testing.yaml)
[![Github Action - Documentation](https://img.shields.io/github/actions/workflow/status/Buried-In-Code/Kraken/docs.yaml?branch=main&logo=githubactions&label=Documentation&style=flat-square)](https://github.com/Buried-In-Code/Kraken/actions/workflows/docs.yaml)

A Java/Kotlin wrapper for the [Metron](https://metron.cloud) API.

## Getting started
## Installation

To get started with Kraken, add the [JitPack](https://jitpack.io) repository to your `build.gradle.kts`.

Expand All @@ -33,7 +34,7 @@ dependencies {
}
```

### Usage
### Example Usage

```kt
import github.buriedincode.kraken.Metron
Expand Down Expand Up @@ -69,6 +70,15 @@ fun main() {
}
```

## Documentation

- [Kraken](https://buried-in-code.github.io/Kraken)
- [Metron API](https://metron.cloud/docs/)

## Bugs/Requests

Please use the [GitHub issue tracker](https://github.com/Buried-In-Code/Kraken/issues) to submit bugs or request features.

## Socials

[![Social - Fosstodon](https://img.shields.io/badge/%40BuriedInCode-teal?label=Fosstodon&logo=mastodon&style=for-the-badge)](https://fosstodon.org/@BuriedInCode)\
Expand Down
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ println("Java v${System.getProperty("java.version")}")
println("Arch: ${System.getProperty("os.arch")}")

group = "github.buriedincode"
version = "0.2.3"
version = "0.3.0"

repositories {
mavenCentral()
Expand Down
20 changes: 20 additions & 0 deletions src/main/kotlin/github/buriedincode/kraken/Exceptions.kt
Original file line number Diff line number Diff line change
@@ -1,7 +1,27 @@
package github.buriedincode.kraken

/**
* A generic exception representing any error in Kraken or the Metron service.
*
* This exception serves as the base class for all service-related exceptions within the Kraken library.
*
* @param message An optional message describing the exception.
* @param cause An optional cause that triggered this exception.
*/
open class ServiceException(message: String? = null, cause: Throwable? = null) : Exception(message, cause)

/**
* An exception indicating an authentication failure with the Metron API.
*
* @param message An optional message describing the exception.
* @param cause An optional cause that triggered this exception.
*/
class AuthenticationException(message: String? = null, cause: Throwable? = null) : ServiceException(message, cause)

/**
* An exception indicating that the Metron API rate limit has been exceeded.
*
* @param message An optional message describing the exception.
* @param cause An optional cause that triggered this exception.
*/
class RateLimitException(message: String? = null, cause: Throwable? = null) : ServiceException(message, cause)
269 changes: 231 additions & 38 deletions src/main/kotlin/github/buriedincode/kraken/Metron.kt

Large diffs are not rendered by default.

38 changes: 38 additions & 0 deletions src/main/kotlin/github/buriedincode/kraken/SQLiteCache.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,15 @@ import java.sql.Date
import java.sql.DriverManager
import java.time.LocalDate

/**
* A simple SQLite-based caching mechanism for storing and retrieving HTTP query results.
*
* The `SQLiteCache` class provides methods to persist query results, retrieve them later, and automatically clean up expired entries based on a configurable expiry period.
*
* @property path The file path to the SQLite database file.
* @property expiry The number of days before cached entries expire. If `null`, entries will not expire.
* @constructor Initializes the SQLite cache, creating the necessary table and performing cleanup for expired entries.
*/
data class SQLiteCache(val path: Path, val expiry: Int? = null) {
private val databaseUrl: String = "jdbc:sqlite:$path"

Expand All @@ -13,6 +22,9 @@ data class SQLiteCache(val path: Path, val expiry: Int? = null) {
this.cleanup()
}

/**
* Creates the `queries` table in the SQLite database if it does not already exist.
*/
private fun createTable() {
val query = "CREATE TABLE IF NOT EXISTS queries (url, response, query_date);"
DriverManager.getConnection(this.databaseUrl).use {
Expand All @@ -22,6 +34,14 @@ data class SQLiteCache(val path: Path, val expiry: Int? = null) {
}
}

/**
* Selects a cached response for a given URL.
*
* If an expiry is set, only entries that have not expired will be retrieved.
*
* @param url The URL whose cached response is to be retrieved.
* @return The cached response as a string, or `null` if no valid entry exists.
*/
fun select(url: String): String? {
val query = if (this.expiry == null) {
"SELECT * FROM queries WHERE url = ?;"
Expand All @@ -41,6 +61,14 @@ data class SQLiteCache(val path: Path, val expiry: Int? = null) {
}
}

/**
* Inserts a new cached response for a given URL.
*
* If an entry for the URL already exists, the method does nothing.
*
* @param url The URL whose response is to be cached.
* @param response The response to cache as a string.
*/
fun insert(url: String, response: String) {
if (this.select(url = url) != null) {
return
Expand All @@ -56,6 +84,11 @@ data class SQLiteCache(val path: Path, val expiry: Int? = null) {
}
}

/**
* Deletes a cached response for a given URL.
*
* @param url The URL whose cached response is to be deleted.
*/
fun delete(url: String) {
val query = "DELETE FROM queries WHERE url = ?;"
DriverManager.getConnection(this.databaseUrl).use {
Expand All @@ -66,6 +99,11 @@ data class SQLiteCache(val path: Path, val expiry: Int? = null) {
}
}

/**
* Cleans up expired entries in the cache.
*
* If an expiry is set, this method removes all entries with a `query_date` older than the expiry period.
*/
fun cleanup() {
if (this.expiry == null) {
return
Expand Down
14 changes: 13 additions & 1 deletion src/main/kotlin/github/buriedincode/kraken/Utils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,15 @@ package github.buriedincode.kraken
import io.github.oshai.kotlinlogging.KLogger
import io.github.oshai.kotlinlogging.Level

/**
* Logs a message at a specified logging level using the [KLogger].
*
* This utility function provides a consistent way to log messages across different levels (e.g., TRACE, DEBUG, INFO, WARN, ERROR) by delegating to the corresponding logging method of the [KLogger].
*
* @receiver [KLogger] The logger instance to log the message.
* @param level The logging level at which the message should be logged.
* @param message A lambda function that produces the log message.
*/
internal fun KLogger.log(level: Level, message: () -> Any?) {
when (level) {
Level.TRACE -> this.trace(message)
Expand All @@ -14,4 +23,7 @@ internal fun KLogger.log(level: Level, message: () -> Any?) {
}
}

internal const val VERSION = "0.2.3"
/**
* The version of the Kraken library.
*/
internal const val VERSION = "0.3.0"
12 changes: 12 additions & 0 deletions src/main/kotlin/github/buriedincode/kraken/schemas/Arc.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,18 @@ import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.JsonNames

/**
* A data model representing an arc.
*
* @property comicvineId The Comic Vine ID of the arc.
* @property description The description of the arc.
* @property grandComicsDatabaseId The Grand Comics Database ID of the arc.
* @property id The unique identifier of the resource.
* @property image The image URL of the arc.
* @property modified The date and time when the resource was last modified.
* @property name The name of the resource.
* @property resourceUrl The URL of the arc resource.
*/
@OptIn(ExperimentalSerializationApi::class)
@Serializable
data class Arc(
Expand Down
16 changes: 16 additions & 0 deletions src/main/kotlin/github/buriedincode/kraken/schemas/Character.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,22 @@ import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.JsonNames

/**
* A data model representing a character.
*
* @property alias The aliases of the character.
* @property comicvineId The Comic Vine ID of the character.
* @property creators The creators of the character.
* @property description The description of the character.
* @property grandComicsDatabaseId The Grand Comics Database ID of the character
* @property id The unique identifier of the resource.
* @property image The image URL of the character.
* @property modified The date and time when the resource was last modified.
* @property name The name of the resource.
* @property resourceUrl The URL of the character resource.
* @property teams The teams the character belongs to.
* @property universes The universes the character is associated with.
*/
@OptIn(ExperimentalSerializationApi::class)
@Serializable
data class Character(
Expand Down
23 changes: 23 additions & 0 deletions src/main/kotlin/github/buriedincode/kraken/schemas/Common.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,16 @@ import github.buriedincode.kraken.serializers.NullableStringSerializer
import kotlinx.datetime.Instant
import kotlinx.serialization.Serializable

/**
* A generic response wrapper for paginated API results.
*
* @param T The type of items contained in the `results` list.
* @property count The total number of items available in the resource.
* @property next The URL for the next page of results, if available. `null` if there are no more pages.
* @property previous The URL for the previous page of results, if available. `null` if on the first page.
* @property results A list of items of type `T` returned by the API.
*
*/
@Serializable
data class ListResponse<T>(
val count: Int,
Expand All @@ -14,12 +24,25 @@ data class ListResponse<T>(
val results: List<T> = listOf(),
)

/**
* A data model representing a generic item.
*
* @property id The unique identifier of the generic item.
* @property name The name fo the generic item.
*/
@Serializable
data class GenericItem(
val id: Long,
val name: String,
)

/**
* A data model representing a base resource.
*
* @property id The unique identifier of the base resource.
* @property modified The date and time when the base resource was last modified.
* @property name The name of the base resource.
*/
@Serializable
data class BaseResource(
val id: Long,
Expand Down
15 changes: 15 additions & 0 deletions src/main/kotlin/github/buriedincode/kraken/schemas/Creator.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,21 @@ import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.JsonNames

/**
* A data model representing a creator.
*
* @property alias The aliases of the creator.
* @property birth The birthdate of the creator.
* @property comicvineId The Comic Vine ID of the creator.
* @property death The death date of the creator.
* @property description The description of the creator.
* @property grandComicsDatabaseId The Grand Comics Database ID of the creator.
* @property id The unique identifier of the resource.
* @property image The image URL of the creator.
* @property modified The date and time when the resource was last modified.
* @property name The name of the resource.
* @property resourceUrl The URL of the creator resource.
*/
@OptIn(ExperimentalSerializationApi::class)
@Serializable
data class Creator(
Expand Down
14 changes: 14 additions & 0 deletions src/main/kotlin/github/buriedincode/kraken/schemas/Imprint.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,20 @@ import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.JsonNames

/**
* A data model representing an imprint.
*
* @property comicvineId The Comic Vine ID of the publisher.
* @property description The description of the publisher.
* @property founded The year the publisher was founded.
* @property grandComicsDatabaseId The Grand Comics Database ID of the publisher.
* @property id The unique identifier of the resource.
* @property image The image URL of the publisher.
* @property modified The date and time when the resource was last modified.
* @property name The name of the resource.
* @property publisher The generic item representing the publisher.
* @property resourceUrl The URL of the publisher resource.
*/
@OptIn(ExperimentalSerializationApi::class)
@Serializable
data class Imprint(
Expand Down
Loading