All Downloads are FREE. Search and download functionalities are using the official Maven repository.

commonMain.com.saveourtool.save.utils.github.GitHubHelper.kt Maven / Gradle / Ivy

package com.saveourtool.save.utils.github

import io.ktor.client.*
import io.ktor.client.call.*
import io.ktor.client.plugins.contentnegotiation.*
import io.ktor.client.request.*
import io.ktor.client.statement.*
import io.ktor.http.*
import io.ktor.serialization.kotlinx.json.*
import io.ktor.utils.io.*
import kotlinx.serialization.json.Json

/**
 * A singleton to download assets from GitHub
 */
object GitHubHelper {
    /**
     * A base url for GitHub api
     */
    const val API_URL = "https://api.github.com/repos"

    /**
     * Version which specified the latest version
     */
    const val LATEST_VERSION = "latest"
    private val httpClient: HttpClient = HttpClient {
        install(ContentNegotiation) {
            val json = Json { ignoreUnknownKeys = true }
            json(json)
        }
    }

    /**
     * Queries metadata from GitHub in provided [repo] with provided [tagName]
     *
     * @param repo
     * @param tagName
     * @return metadata as [ReleaseMetadata]
     */
    suspend fun queryMetadata(repo: GitHubRepoInfo, tagName: String): ReleaseMetadata = httpClient.get(repo.getMetadataUrl(tagName)).body()

    /**
     * Downloads provided [asset] from GitHub
     *
     * @param asset
     * @param consumer consumer of content of provided asset
     * @return result of consumer [R] or null
     */
    suspend fun  downloadAsset(
        asset: ReleaseAsset,
        consumer: suspend (ByteReadChannel) -> R,
    ): R? = httpClient.prepareGet {
        url(asset.downloadUrl)
        accept(asset.contentType())
    }
        .execute { response ->
            if (response.status.isSuccess()) {
                consumer(response.bodyAsChannel())
            } else {
                null
            }
        }

    /**
     * Fetches a list of tags from GitHub in provided [repo]
     *
     * @param repo
     * @return list of tags
     */
    suspend fun availableTags(repo: GitHubRepoInfo): List = httpClient.get(repo.getTagsUrl())
        .body>()
        .map { it.name }

    /**
     * Downloads asset from GitHub in provided [repo] with provided [tagName]
     * It expects that there is only a single asset
     *
     * @param repo
     * @param tagName
     * @param assetName
     * @param consumer consumer of content of found asset with its size
     * @return result of consumer [R] or null
     */
    suspend fun  download(
        repo: GitHubRepoInfo,
        tagName: String,
        assetName: String,
        consumer: suspend (Pair) -> R
    ): R? = queryMetadata(repo, tagName)
        .assets
        .singleOrNull { asset -> assetName == asset.name }
        ?.let { asset ->
            downloadAsset(asset) { content ->
                consumer(content to asset.size)
            }
        }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy