mirror of
https://github.com/revanced/revanced-api.git
synced 2025-04-30 06:34:36 +02:00
feat: Implement more routes and add configuration
This commit is contained in:
parent
8ae50b543e
commit
9999b242ad
@ -1,2 +1,2 @@
|
|||||||
GITHUB_TOKEN=
|
GITHUB_TOKEN=
|
||||||
API_VERSION=
|
CONFIG_FILE_PATH=
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -37,3 +37,4 @@ out/
|
|||||||
|
|
||||||
### Project ###
|
### Project ###
|
||||||
.env
|
.env
|
||||||
|
configuration.toml
|
@ -42,6 +42,10 @@ dependencies {
|
|||||||
implementation(libs.exposed.core)
|
implementation(libs.exposed.core)
|
||||||
implementation(libs.exposed.jdbc)
|
implementation(libs.exposed.jdbc)
|
||||||
implementation(libs.dotenv.kotlin)
|
implementation(libs.dotenv.kotlin)
|
||||||
|
implementation(libs.ktoml.core)
|
||||||
|
implementation(libs.ktoml.file)
|
||||||
|
|
||||||
testImplementation(libs.ktor.server.tests)
|
testImplementation(libs.ktor.server.tests)
|
||||||
testImplementation(libs.kotlin.test.junit)
|
testImplementation(libs.kotlin.test.junit)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
5
configuration.example.toml
Normal file
5
configuration.example.toml
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
organization = "org"
|
||||||
|
patches-repository = "patches"
|
||||||
|
integrations-repositories = ["integrations"]
|
||||||
|
contributors-repositories = ["patches", "integrations"]
|
||||||
|
api-version = 1
|
14
configuration.toml
Normal file
14
configuration.toml
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
organization = "revanced"
|
||||||
|
patches-repository = "revanced-patches"
|
||||||
|
integrations-repositories = [
|
||||||
|
"revanced-integrations"
|
||||||
|
]
|
||||||
|
contributors-repositories = [
|
||||||
|
"revanced-patcher",
|
||||||
|
"revanced-patches",
|
||||||
|
"revanced-integrations",
|
||||||
|
"revanced-website",
|
||||||
|
"revanced-cli",
|
||||||
|
"revanced-manager",
|
||||||
|
]
|
||||||
|
api-version = 1
|
@ -6,6 +6,7 @@ h2="2.1.214"
|
|||||||
koin="3.5.3"
|
koin="3.5.3"
|
||||||
dotenv="6.4.1"
|
dotenv="6.4.1"
|
||||||
ktor = "2.3.7"
|
ktor = "2.3.7"
|
||||||
|
ktoml = "0.5.1"
|
||||||
|
|
||||||
[libraries]
|
[libraries]
|
||||||
ktor-client-core = { module = "io.ktor:ktor-client-core" }
|
ktor-client-core = { module = "io.ktor:ktor-client-core" }
|
||||||
@ -34,6 +35,8 @@ exposed-jdbc = { module = "org.jetbrains.exposed:exposed-jdbc", version.ref = "e
|
|||||||
dotenv-kotlin = { module = "io.github.cdimascio:dotenv-kotlin", version.ref = "dotenv" }
|
dotenv-kotlin = { module = "io.github.cdimascio:dotenv-kotlin", version.ref = "dotenv" }
|
||||||
ktor-server-tests = { module = "io.ktor:ktor-server-tests" }
|
ktor-server-tests = { module = "io.ktor:ktor-server-tests" }
|
||||||
kotlin-test-junit = { module = "org.jetbrains.kotlin:kotlin-test-junit", version.ref = "kotlin" }
|
kotlin-test-junit = { module = "org.jetbrains.kotlin:kotlin-test-junit", version.ref = "kotlin" }
|
||||||
|
ktoml-core = { module = "com.akuleshov7:ktoml-core", version.ref = "ktoml" }
|
||||||
|
ktoml-file = { module = "com.akuleshov7:ktoml-file", version.ref = "ktoml" }
|
||||||
|
|
||||||
[plugins]
|
[plugins]
|
||||||
serilization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
|
serilization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
|
||||||
|
55
src/main/kotlin/app/revanced/api/APISchema.kt
Normal file
55
src/main/kotlin/app/revanced/api/APISchema.kt
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
package app.revanced.api
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
class APIRelease(
|
||||||
|
val version: String,
|
||||||
|
val createdAt: String,
|
||||||
|
val changelog: String,
|
||||||
|
val assets: Set<APIAsset>
|
||||||
|
)
|
||||||
|
|
||||||
|
interface APIUser {
|
||||||
|
val name: String
|
||||||
|
val avatarUrl: String
|
||||||
|
val url: String
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
class APIMember(
|
||||||
|
override val name: String,
|
||||||
|
override val avatarUrl: String,
|
||||||
|
override val url: String,
|
||||||
|
val gpgKeysUrl: String
|
||||||
|
) : APIUser
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
class APIContributor(
|
||||||
|
override val name: String,
|
||||||
|
override val avatarUrl: String,
|
||||||
|
override val url: String,
|
||||||
|
val contributions: Int,
|
||||||
|
) : APIUser
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
class APIContributable(
|
||||||
|
val name: String,
|
||||||
|
val contributors: Set<APIContributor>
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
class APIAsset(
|
||||||
|
val downloadUrl: String,
|
||||||
|
) {
|
||||||
|
val type = when {
|
||||||
|
downloadUrl.endsWith(".jar") -> "patches"
|
||||||
|
downloadUrl.endsWith(".apk") -> "integrations"
|
||||||
|
else -> "unknown"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
class APIReleaseVersion(
|
||||||
|
val version: String
|
||||||
|
)
|
@ -7,8 +7,6 @@ import io.ktor.server.engine.*
|
|||||||
import io.ktor.server.netty.*
|
import io.ktor.server.netty.*
|
||||||
|
|
||||||
fun main() {
|
fun main() {
|
||||||
Dotenv.load()
|
|
||||||
|
|
||||||
embeddedServer(Netty, port = 8080, host = "0.0.0.0", configure = {
|
embeddedServer(Netty, port = 8080, host = "0.0.0.0", configure = {
|
||||||
connectionGroupSize = 1
|
connectionGroupSize = 1
|
||||||
workerGroupSize = 1
|
workerGroupSize = 1
|
||||||
|
17
src/main/kotlin/app/revanced/api/ConfigurationSchema.kt
Normal file
17
src/main/kotlin/app/revanced/api/ConfigurationSchema.kt
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package app.revanced.api
|
||||||
|
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
class APIConfiguration(
|
||||||
|
val organization: String,
|
||||||
|
@SerialName("patches-repository")
|
||||||
|
val patchesRepository: String,
|
||||||
|
@SerialName("integrations-repositories")
|
||||||
|
val integrationsRepositoryNames: Set<String>,
|
||||||
|
@SerialName("contributors-repositories")
|
||||||
|
val contributorsRepositoryNames: Set<String>,
|
||||||
|
@SerialName("api-version")
|
||||||
|
val apiVersion: Int = 1
|
||||||
|
)
|
@ -19,12 +19,12 @@ abstract class Backend(
|
|||||||
*
|
*
|
||||||
* @property name The name of the user.
|
* @property name The name of the user.
|
||||||
* @property avatarUrl The URL to the avatar of the user.
|
* @property avatarUrl The URL to the avatar of the user.
|
||||||
* @property profileUrl The URL to the profile of the user.
|
* @property url The URL to the profile of the user.
|
||||||
*/
|
*/
|
||||||
interface User {
|
interface BackendUser {
|
||||||
val name: String
|
val name: String
|
||||||
val avatarUrl: String
|
val avatarUrl: String
|
||||||
val profileUrl: String
|
val url: String
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -32,48 +32,50 @@ abstract class Backend(
|
|||||||
*
|
*
|
||||||
* @property members The members of the organization.
|
* @property members The members of the organization.
|
||||||
*/
|
*/
|
||||||
class Organization(
|
class BackendOrganization(
|
||||||
val members: Set<Member>
|
val members: Set<BackendMember>
|
||||||
) {
|
) {
|
||||||
/**
|
/**
|
||||||
* A member of an organization.
|
* A member of an organization.
|
||||||
*
|
*
|
||||||
* @property name The name of the member.
|
* @property name The name of the member.
|
||||||
* @property avatarUrl The URL to the avatar of the member.
|
* @property avatarUrl The URL to the avatar of the member.
|
||||||
* @property profileUrl The URL to the profile of the member.
|
* @property url The URL to the profile of the member.
|
||||||
* @property bio The bio of the member.
|
* @property bio The bio of the member.
|
||||||
* @property gpgKeysUrl The URL to the GPG keys of the member.
|
* @property gpgKeysUrl The URL to the GPG keys of the member.
|
||||||
*/
|
*/
|
||||||
@Serializable
|
@Serializable
|
||||||
class Member (
|
class BackendMember (
|
||||||
override val name: String,
|
override val name: String,
|
||||||
override val avatarUrl: String,
|
override val avatarUrl: String,
|
||||||
override val profileUrl: String,
|
override val url: String,
|
||||||
val bio: String?,
|
val bio: String?,
|
||||||
val gpgKeysUrl: String?
|
val gpgKeysUrl: String
|
||||||
) : User
|
) : BackendUser
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A repository of an organization.
|
* A repository of an organization.
|
||||||
*
|
*
|
||||||
* @property contributors The contributors of the repository.
|
* @property contributors The contributors of the repository.
|
||||||
*/
|
*/
|
||||||
class Repository(
|
class BackendRepository(
|
||||||
val contributors: Set<Contributor>
|
val contributors: Set<BackendContributor>
|
||||||
) {
|
) {
|
||||||
/**
|
/**
|
||||||
* A contributor of a repository.
|
* A contributor of a repository.
|
||||||
*
|
*
|
||||||
* @property name The name of the contributor.
|
* @property name The name of the contributor.
|
||||||
* @property avatarUrl The URL to the avatar of the contributor.
|
* @property avatarUrl The URL to the avatar of the contributor.
|
||||||
* @property profileUrl The URL to the profile of the contributor.
|
* @property url The URL to the profile of the contributor.
|
||||||
|
* @property contributions The number of contributions of the contributor.
|
||||||
*/
|
*/
|
||||||
@Serializable
|
@Serializable
|
||||||
class Contributor(
|
class BackendContributor(
|
||||||
override val name: String,
|
override val name: String,
|
||||||
override val avatarUrl: String,
|
override val avatarUrl: String,
|
||||||
override val profileUrl: String
|
override val url: String,
|
||||||
) : User
|
val contributions: Int
|
||||||
|
) : BackendUser
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A release of a repository.
|
* A release of a repository.
|
||||||
@ -84,11 +86,11 @@ abstract class Backend(
|
|||||||
* @property releaseNote The release note of the release.
|
* @property releaseNote The release note of the release.
|
||||||
*/
|
*/
|
||||||
@Serializable
|
@Serializable
|
||||||
class Release(
|
class BackendRelease(
|
||||||
val tag: String,
|
val tag: String,
|
||||||
val releaseNote: String,
|
val releaseNote: String,
|
||||||
val createdAt: String,
|
val createdAt: String,
|
||||||
val assets: Set<Asset>
|
val assets: Set<BackendAsset>
|
||||||
) {
|
) {
|
||||||
/**
|
/**
|
||||||
* An asset of a release.
|
* An asset of a release.
|
||||||
@ -96,7 +98,7 @@ abstract class Backend(
|
|||||||
* @property downloadUrl The URL to download the asset.
|
* @property downloadUrl The URL to download the asset.
|
||||||
*/
|
*/
|
||||||
@Serializable
|
@Serializable
|
||||||
class Asset(
|
class BackendAsset(
|
||||||
val downloadUrl: String
|
val downloadUrl: String
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -109,17 +111,13 @@ abstract class Backend(
|
|||||||
* @param owner The owner of the repository.
|
* @param owner The owner of the repository.
|
||||||
* @param repository The name of the repository.
|
* @param repository The name of the repository.
|
||||||
* @param tag The tag of the release. If null, the latest release is returned.
|
* @param tag The tag of the release. If null, the latest release is returned.
|
||||||
* @param preRelease Whether to return a pre-release.
|
|
||||||
* If no pre-release exists, the latest release is returned.
|
|
||||||
* If tag is not null, this parameter is ignored.
|
|
||||||
* @return The release.
|
* @return The release.
|
||||||
*/
|
*/
|
||||||
abstract suspend fun getRelease(
|
abstract suspend fun getRelease(
|
||||||
owner: String,
|
owner: String,
|
||||||
repository: String,
|
repository: String,
|
||||||
tag: String? = null,
|
tag: String? = null,
|
||||||
preRelease: Boolean = false
|
): BackendOrganization.BackendRepository.BackendRelease
|
||||||
): Organization.Repository.Release
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the contributors of a repository.
|
* Get the contributors of a repository.
|
||||||
@ -128,7 +126,7 @@ abstract class Backend(
|
|||||||
* @param repository The name of the repository.
|
* @param repository The name of the repository.
|
||||||
* @return The contributors.
|
* @return The contributors.
|
||||||
*/
|
*/
|
||||||
abstract suspend fun getContributors(owner: String, repository: String): Set<Organization.Repository.Contributor>
|
abstract suspend fun getContributors(owner: String, repository: String): Set<BackendOrganization.BackendRepository.BackendContributor>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the members of an organization.
|
* Get the members of an organization.
|
||||||
@ -136,5 +134,5 @@ abstract class Backend(
|
|||||||
* @param organization The name of the organization.
|
* @param organization The name of the organization.
|
||||||
* @return The members.
|
* @return The members.
|
||||||
*/
|
*/
|
||||||
abstract suspend fun getMembers(organization: String): Set<Organization.Member>
|
abstract suspend fun getMembers(organization: String): Set<BackendOrganization.BackendMember>
|
||||||
}
|
}
|
||||||
|
@ -9,13 +9,17 @@ import io.ktor.client.plugins.auth.providers.*
|
|||||||
import io.ktor.client.plugins.cache.*
|
import io.ktor.client.plugins.cache.*
|
||||||
import io.ktor.client.plugins.contentnegotiation.*
|
import io.ktor.client.plugins.contentnegotiation.*
|
||||||
import io.ktor.client.plugins.resources.*
|
import io.ktor.client.plugins.resources.*
|
||||||
|
import app.revanced.api.backend.Backend.BackendOrganization.BackendMember
|
||||||
|
import app.revanced.api.backend.Backend.BackendOrganization.BackendRepository.BackendRelease
|
||||||
|
import app.revanced.api.backend.Backend.BackendOrganization.BackendRepository.BackendContributor
|
||||||
|
import app.revanced.api.backend.Backend.BackendOrganization.BackendRepository.BackendRelease.BackendAsset
|
||||||
import app.revanced.api.backend.github.api.Request.Organization.Repository.Releases
|
import app.revanced.api.backend.github.api.Request.Organization.Repository.Releases
|
||||||
import app.revanced.api.backend.github.api.Request.Organization.Repository.Contributors
|
import app.revanced.api.backend.github.api.Request.Organization.Repository.Contributors
|
||||||
import app.revanced.api.backend.github.api.Request.Organization.Members
|
import app.revanced.api.backend.github.api.Request.Organization.Members
|
||||||
import app.revanced.api.backend.github.api.Response
|
import app.revanced.api.backend.github.api.Response
|
||||||
import app.revanced.api.backend.github.api.Response.Organization.Repository.Release
|
import app.revanced.api.backend.github.api.Response.GitHubOrganization.GitHubRepository.GitHubRelease
|
||||||
import app.revanced.api.backend.github.api.Response.Organization.Repository.Contributor
|
import app.revanced.api.backend.github.api.Response.GitHubOrganization.GitHubRepository.GitHubContributor
|
||||||
import app.revanced.api.backend.github.api.Response.Organization.Member
|
import app.revanced.api.backend.github.api.Response.GitHubOrganization.GitHubMember
|
||||||
import io.ktor.client.plugins.resources.Resources
|
import io.ktor.client.plugins.resources.Resources
|
||||||
import io.ktor.serialization.kotlinx.json.*
|
import io.ktor.serialization.kotlinx.json.*
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
@ -55,59 +59,58 @@ class GitHubBackend(token: String? = null) : Backend({
|
|||||||
owner: String,
|
owner: String,
|
||||||
repository: String,
|
repository: String,
|
||||||
tag: String?,
|
tag: String?,
|
||||||
preRelease: Boolean
|
): BackendRelease {
|
||||||
): Organization.Repository.Release {
|
val release: GitHubRelease = if (tag != null)
|
||||||
val release = if (preRelease) {
|
client.get(Releases.Tag(owner, repository, tag)).body()
|
||||||
val releases: Set<Release> = client.get(Releases(owner, repository)).body()
|
else
|
||||||
releases.firstOrNull { it.preReleases } ?: releases.first() // Latest pre-release or latest release
|
client.get(Releases.Latest(owner, repository)).body()
|
||||||
} else {
|
|
||||||
client.get(
|
|
||||||
tag?.let { Releases.Tag(owner, repository, it) }
|
|
||||||
?: Releases.Latest(owner, repository)
|
|
||||||
).body()
|
|
||||||
}
|
|
||||||
|
|
||||||
return Organization.Repository.Release(
|
|
||||||
|
return BackendRelease(
|
||||||
tag = release.tagName,
|
tag = release.tagName,
|
||||||
releaseNote = release.body,
|
releaseNote = release.body,
|
||||||
createdAt = release.createdAt,
|
createdAt = release.createdAt,
|
||||||
assets = release.assets.map {
|
assets = release.assets.map {
|
||||||
Organization.Repository.Release.Asset(
|
BackendAsset(
|
||||||
downloadUrl = it.browserDownloadUrl
|
downloadUrl = it.browserDownloadUrl
|
||||||
)
|
)
|
||||||
}.toSet()
|
}.toSet()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getContributors(owner: String, repository: String): Set<Organization.Repository.Contributor> {
|
override suspend fun getContributors(
|
||||||
val contributors: Set<Contributor> = client.get(Contributors(owner, repository)).body()
|
owner: String,
|
||||||
|
repository: String
|
||||||
|
): Set<BackendContributor> {
|
||||||
|
val contributors: Set<GitHubContributor> = client.get(Contributors(owner, repository)).body()
|
||||||
|
|
||||||
return contributors.map {
|
return contributors.map {
|
||||||
Organization.Repository.Contributor(
|
BackendContributor(
|
||||||
name = it.login,
|
name = it.login,
|
||||||
avatarUrl = it.avatarUrl,
|
avatarUrl = it.avatarUrl,
|
||||||
profileUrl = it.url
|
url = it.url,
|
||||||
|
contributions = it.contributions
|
||||||
)
|
)
|
||||||
}.toSet()
|
}.toSet()
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getMembers(organization: String): Set<Organization.Member> {
|
override suspend fun getMembers(organization: String): Set<BackendMember> {
|
||||||
// Get the list of members of the organization.
|
// Get the list of members of the organization.
|
||||||
val members: Set<Member> = client.get(Members(organization)).body<Set<Member>>()
|
val members: Set<GitHubMember> = client.get(Members(organization)).body()
|
||||||
|
|
||||||
return runBlocking(Dispatchers.Default) {
|
return runBlocking(Dispatchers.Default) {
|
||||||
members.map { member ->
|
members.map { member ->
|
||||||
// Map the member to a user in order to get the bio.
|
// Map the member to a user in order to get the bio.
|
||||||
async {
|
async {
|
||||||
client.get(Request.User(member.login)).body<Response.User>()
|
client.get(Request.User(member.login)).body<Response.GitHubUser>()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}.awaitAll().map { user ->
|
}.awaitAll().map { user ->
|
||||||
// Map the user back to a member.
|
// Map the user back to a member.
|
||||||
Organization.Member(
|
BackendMember(
|
||||||
name = user.login,
|
name = user.login,
|
||||||
avatarUrl = user.avatarUrl,
|
avatarUrl = user.avatarUrl,
|
||||||
profileUrl = user.url,
|
url = user.url,
|
||||||
bio = user.bio,
|
bio = user.bio,
|
||||||
gpgKeysUrl = "https://github.com/${user.login}.gpg",
|
gpgKeysUrl = "https://github.com/${user.login}.gpg",
|
||||||
)
|
)
|
||||||
|
@ -1,49 +1,50 @@
|
|||||||
package app.revanced.api.backend.github.api
|
package app.revanced.api.backend.github.api
|
||||||
|
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
|
||||||
class Response {
|
class Response {
|
||||||
interface IUser {
|
interface IGitHubUser {
|
||||||
val login: String
|
val login: String
|
||||||
val avatarUrl: String
|
val avatarUrl: String
|
||||||
val url: String
|
val url: String
|
||||||
}
|
}
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
class User (
|
class GitHubUser (
|
||||||
override val login: String,
|
override val login: String,
|
||||||
override val avatarUrl: String,
|
override val avatarUrl: String,
|
||||||
override val url: String,
|
override val url: String,
|
||||||
val bio: String?,
|
val bio: String?,
|
||||||
) : IUser
|
) : IGitHubUser
|
||||||
|
|
||||||
class Organization {
|
class GitHubOrganization {
|
||||||
@Serializable
|
@Serializable
|
||||||
class Member(
|
class GitHubMember(
|
||||||
override val login: String,
|
override val login: String,
|
||||||
override val avatarUrl: String,
|
override val avatarUrl: String,
|
||||||
override val url: String,
|
override val url: String,
|
||||||
) : IUser
|
) : IGitHubUser
|
||||||
|
|
||||||
class Repository {
|
class GitHubRepository {
|
||||||
@Serializable
|
@Serializable
|
||||||
class Contributor(
|
class GitHubContributor(
|
||||||
override val login: String,
|
override val login: String,
|
||||||
override val avatarUrl: String,
|
override val avatarUrl: String,
|
||||||
override val url: String,
|
override val url: String,
|
||||||
) : IUser
|
val contributions: Int,
|
||||||
|
) : IGitHubUser
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
class Release(
|
class GitHubRelease(
|
||||||
val tagName: String,
|
val tagName: String,
|
||||||
val assets: Set<Asset>,
|
val assets: Set<GitHubAsset>,
|
||||||
val preReleases: Boolean,
|
|
||||||
val createdAt: String,
|
val createdAt: String,
|
||||||
val body: String
|
val body: String
|
||||||
) {
|
) {
|
||||||
@Serializable
|
@Serializable
|
||||||
class Asset(
|
class GitHubAsset(
|
||||||
val browserDownloadUrl: String
|
val browserDownloadUrl: String
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1,21 +1,37 @@
|
|||||||
package app.revanced.api.plugins
|
package app.revanced.api.plugins
|
||||||
|
|
||||||
|
import app.revanced.api.APIConfiguration
|
||||||
import app.revanced.api.backend.github.GitHubBackend
|
import app.revanced.api.backend.github.GitHubBackend
|
||||||
|
import com.akuleshov7.ktoml.Toml
|
||||||
|
import com.akuleshov7.ktoml.source.decodeFromStream
|
||||||
import io.github.cdimascio.dotenv.Dotenv
|
import io.github.cdimascio.dotenv.Dotenv
|
||||||
import io.ktor.server.application.*
|
import io.ktor.server.application.*
|
||||||
|
import kotlinx.serialization.decodeFromString
|
||||||
|
import kotlinx.serialization.encodeToString
|
||||||
import org.koin.core.context.startKoin
|
import org.koin.core.context.startKoin
|
||||||
import org.koin.dsl.module
|
import org.koin.dsl.module
|
||||||
import org.koin.ktor.ext.inject
|
import org.koin.ktor.ext.inject
|
||||||
import org.koin.ktor.plugin.Koin
|
import org.koin.ktor.plugin.Koin
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
fun Application.configureDependencies() {
|
fun Application.configureDependencies() {
|
||||||
|
|
||||||
install(Koin) {
|
install(Koin) {
|
||||||
modules(
|
modules(
|
||||||
module {
|
module {
|
||||||
single { Dotenv.load() }
|
single {
|
||||||
single { GitHubBackend(get<Dotenv>().get("GITHUB_TOKEN")) }
|
Dotenv.load()
|
||||||
|
}
|
||||||
|
single {
|
||||||
|
val configFilePath = get<Dotenv>().get("CONFIG_FILE_PATH")!!
|
||||||
|
Toml.decodeFromStream<APIConfiguration>(File(configFilePath).inputStream())
|
||||||
|
}
|
||||||
|
single {
|
||||||
|
val token = get<Dotenv>().get("GITHUB_TOKEN")
|
||||||
|
GitHubBackend(token)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,45 +1,84 @@
|
|||||||
package app.revanced.api.plugins
|
package app.revanced.api.plugins
|
||||||
|
|
||||||
|
import app.revanced.api.*
|
||||||
import app.revanced.api.backend.github.GitHubBackend
|
import app.revanced.api.backend.github.GitHubBackend
|
||||||
import io.github.cdimascio.dotenv.Dotenv
|
import io.ktor.client.utils.EmptyContent.contentType
|
||||||
import io.ktor.http.*
|
import io.ktor.http.*
|
||||||
import io.ktor.server.application.*
|
import io.ktor.server.application.*
|
||||||
import io.ktor.server.http.content.*
|
import io.ktor.server.http.content.*
|
||||||
import io.ktor.server.response.*
|
import io.ktor.server.response.*
|
||||||
import io.ktor.server.routing.*
|
import io.ktor.server.routing.*
|
||||||
|
import kotlinx.coroutines.async
|
||||||
|
import kotlinx.coroutines.awaitAll
|
||||||
import org.koin.ktor.ext.inject
|
import org.koin.ktor.ext.inject
|
||||||
|
|
||||||
fun Application.configureRouting() {
|
fun Application.configureRouting() {
|
||||||
val backend by inject<GitHubBackend>()
|
val backend by inject<GitHubBackend>()
|
||||||
val dotenv by inject<Dotenv>()
|
val configuration by inject<APIConfiguration>()
|
||||||
|
|
||||||
routing {
|
routing {
|
||||||
route("/v${dotenv.get("API_VERSION", "1")}") {
|
route("/v${configuration.apiVersion}") {
|
||||||
route("/manager") {
|
route("/patches") {
|
||||||
|
get {
|
||||||
|
val patches = backend.getRelease(configuration.organization, configuration.patchesRepository)
|
||||||
|
val integrations = configuration.integrationsRepositoryNames.map {
|
||||||
|
async { backend.getRelease(configuration.organization, it) }
|
||||||
|
}.awaitAll()
|
||||||
|
|
||||||
|
val assets = (patches.assets + integrations.flatMap { it.assets }).filter {
|
||||||
|
it.downloadUrl.endsWith(".apk") || it.downloadUrl.endsWith(".jar")
|
||||||
|
}.map { APIAsset(it.downloadUrl) }.toSet()
|
||||||
|
|
||||||
|
val release = APIRelease(
|
||||||
|
patches.tag,
|
||||||
|
patches.createdAt,
|
||||||
|
patches.releaseNote,
|
||||||
|
assets
|
||||||
|
)
|
||||||
|
|
||||||
|
call.respond(release)
|
||||||
|
}
|
||||||
|
|
||||||
|
get("/version") {
|
||||||
|
val patches = backend.getRelease(configuration.organization, configuration.patchesRepository)
|
||||||
|
|
||||||
|
val release = APIReleaseVersion(patches.tag)
|
||||||
|
|
||||||
|
call.respond(release)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
get("/contributors") {
|
get("/contributors") {
|
||||||
val contributors = backend.getContributors("revanced", "revanced-patches")
|
val contributors = configuration.contributorsRepositoryNames.map {
|
||||||
|
async {
|
||||||
|
APIContributable(
|
||||||
|
it,
|
||||||
|
backend.getContributors(configuration.organization, it).map {
|
||||||
|
APIContributor(it.name, it.avatarUrl, it.url, it.contributions)
|
||||||
|
}.toSet()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}.awaitAll()
|
||||||
|
|
||||||
call.respond(contributors)
|
call.respond(contributors)
|
||||||
}
|
}
|
||||||
|
|
||||||
get("/members") {
|
get("/members") {
|
||||||
val members = backend.getMembers("revanced")
|
val members = backend.getMembers(configuration.organization).map {
|
||||||
|
APIMember(it.name, it.avatarUrl, it.url, it.gpgKeysUrl)
|
||||||
|
}
|
||||||
|
|
||||||
call.respond(members)
|
call.respond(members)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
route("/patches") {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
route("/ping") {
|
route("/ping") {
|
||||||
handle {
|
handle {
|
||||||
call.respond(HttpStatusCode.NoContent)
|
call.respond(HttpStatusCode.NoContent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
staticResources("/", "/static/api") { contentType { ContentType.Application.Json } }
|
||||||
}
|
}
|
||||||
|
|
||||||
staticResources("/", "static")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user