{"id":17305219,"url":"https://github.com/minndevelopment/jda-reactor","last_synced_at":"2025-07-02T17:33:28.916Z","repository":{"id":45862712,"uuid":"169882672","full_name":"MinnDevelopment/jda-reactor","owner":"MinnDevelopment","description":"A collection of kotlin extensions for JDA that make use with reactor-core easier.","archived":false,"fork":false,"pushed_at":"2022-11-28T13:45:31.000Z","size":136,"stargazers_count":24,"open_issues_count":0,"forks_count":2,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-14T13:29:13.459Z","etag":null,"topics":["discord","hacktoberfest","jda","kotlin","reactive","reactive-streams"],"latest_commit_sha":null,"homepage":"","language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/MinnDevelopment.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-02-09T15:47:50.000Z","updated_at":"2025-01-04T07:32:04.000Z","dependencies_parsed_at":"2023-01-23T11:01:03.954Z","dependency_job_id":null,"html_url":"https://github.com/MinnDevelopment/jda-reactor","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/MinnDevelopment/jda-reactor","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MinnDevelopment%2Fjda-reactor","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MinnDevelopment%2Fjda-reactor/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MinnDevelopment%2Fjda-reactor/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MinnDevelopment%2Fjda-reactor/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/MinnDevelopment","download_url":"https://codeload.github.com/MinnDevelopment/jda-reactor/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MinnDevelopment%2Fjda-reactor/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":263184820,"owners_count":23427090,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["discord","hacktoberfest","jda","kotlin","reactive","reactive-streams"],"created_at":"2024-10-15T11:55:01.973Z","updated_at":"2025-07-02T17:33:28.894Z","avatar_url":"https://github.com/MinnDevelopment.png","language":"Kotlin","funding_links":[],"categories":[],"sub_categories":[],"readme":"[ ![version](https://shields.io/github/v/tag/MinnDevelopment/jda-reactor) ](#Installation)\n# jda-reactor\n\nA collection of kotlin extensions for JDA that make use with reactor-core easier.\n\n## Installation\n\nReplace the `$VERSION` with the latest release version.\n\u003cbr\u003eReplace `$JDA_VERSION` with the latest stable JDA v5 release.\n\n### Gradle\n\n```gradle\ndependencies {\n    implementation(\"net.dv8tion:JDA:$JDA_VERSION\")\n    implementation(\"com.github.MinnDevelopment:jda-reactor:$VERSION\")\n}\n\nrepositories {\n    mavenCentral()\n    maven(\"https://jitpack.io\")\n}\n```\n\n### Maven\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003enet.dv8tion\u003c/groupId\u003e\n    \u003cartifactId\u003eJDA\u003c/artifactId\u003e\n    \u003cversion\u003e$JDA_VERSION\u003c/version\u003e\n\u003c/dependency\u003e\n\u003cdependency\u003e\n    \u003cgroupId\u003ecom.github.MinnDevelopment\u003c/groupId\u003e\n    \u003cartifactId\u003ejda-reactor\u003c/artifactId\u003e\n    \u003cversion\u003e$VERSION\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n```xml\n\u003crepository\u003e \u003c!-- jda-reactor --\u003e\n    \u003cname\u003ejitpack\u003c/name\u003e\n    \u003cid\u003ejitpack\u003c/id\u003e\n    \u003curl\u003ehttps://jitpack.io\u003c/url\u003e\n\u003c/repository\u003e\n```\n\n## Examples\n\nSome small example usages of the components supported by this library.\n\nThere is a complete bot written as an example available at [reactive-jda-bot](https://github.com/MinnDevelopment/reactive-jda-bot).\n\n### ReactiveEventManager\n\n```kotlin\nfun main() {\n    // Create a ReactiveEventManager for Flux event streams\n    val manager = ReactiveEventManager()\n    // subscribe directly on the manager instance\n    manager.on\u003cReadyEvent\u003e()                       // Flux\u003cReadyEvent\u003e\n           .next()                                 // Mono\u003cReadyEvent\u003e\n           .subscribe { println(\"Ready to go!\")  } // Subscribe to event\n\n    manager.on\u003cMessageReceivedEvent\u003e()             // Flux\u003cMessageReceivedEvent\u003e\n           .map { it.message }                     // Flux\u003cMessage\u003e\n           .filter { it.contentRaw == \"!ping\" }    // filter by content\n           .map { it.channel }                     // Flux\u003cMessageChannel\u003e\n           .map { it.sendMessage(\"Pong!\") }        // Flux\u003cMessageAction\u003e\n           .flatMap { it.asMono() }                // Flux\u003cMessage\u003e (send message and provide result)\n           .subscribe()                            // Subscribe to event\n\n   val jda = JDABuilder(BOT_TOKEN)\n        .setEventManager(manager)\n        .build()\n\n   // you can also subscribe to events from the JDA instance\n   jda.on\u003cShutdownEvent\u003e()                         // Flux\u003cShutdownEvent\u003e\n      .subscribe { println(\"That was fun!\") }      // Make a statement on shutdown, not guaranteed to run if daemon scheduler (default)\n}\n```\n\n### Mono/Flux RestAction\n\nEvery RestAction receives an `asMono` extensions which converts them into a `Mono\u003cT\u003e` of the same result type.\n\u003cbr\u003eAdditionally some more specific types such as `PaginationAction` can be streamed into a `Flux\u003cT\u003e`\nwhich will automatically paginate the endpoint as demanded by the subscription.\n\n#### PaginationAction\\\u003cT, *\u003e\n\n```kotlin\nfun getMessagesForUser(channel: MessageChannel, user: User): Flux\u003cMessage\u003e {\n    val action = channel.iterableHistory\n    return action.asFlux()                     // Flux\u003cMessage\u003e\n                 .filter { it.author == user } // filter by user\n}\n```\n\n#### RestAction\\\u003cT\u003e\n\n```kotlin\nfun sendAndLog(channel: MessageChannel, content: String) {\n    val action = channel.sendMessage(content)\n    action.asMono()                                             // Mono\u003cMessage\u003e\n          .flatMap { it.addReaction(EMOTE).asMono() }           // Mono\u003cVoid!\u003e = empty mono\n          .doOnSuccess { println(\"${channel.name}: $content\") } // add side-effect\n          .subscribe()                                          // subscribe to empty stream\n}\n```\n\n#### RestAction\u003cIterable\\\u003cT\u003e\u003e\n\n```kotlin\nfun getBannedUsers(guild: Guild): Flux\u003cString\u003e {\n return guild.retrieveBanList()     // RestAction\u003cList\u003cGuild.Ban\u003e\u003e\n             .toFlux()              // Flux\u003cBan\u003e\n             .map { it.user }       // Flux\u003cUser\u003e\n             .map { it.asTag }      // Flux\u003cString\u003e\n}\n```\n\n### Entity Observers\n\n```kotlin\nfun onNextMessage(channel: MessageChannel, callback: (Message) -\u003e Unit) {\n    channel.onMessage()                // Flux\u003cMessageReceivedEvent\u003e\n           .next()                     // Mono\u003cMessageReceivedEvent\u003e\n           .map { it.message }         // Mono\u003cMessage\u003e\n           .subscribe { callback(it) }\n}\n\nfun onReaction(message: Message, reaction: String): Flux\u003cUser\u003e {\n    return message.on\u003cMessageReactionAddEvent\u003e()                // Flux\u003cMessageReactionAddEvent\u003e\n                  .filter { it.emoji.name == reaction }         // Flux\u003cMessageReactionAddEvent\u003e with filter\n                  .map { it.user }                              // Flux\u003cUser\u003e\n}\n```\n\n```kotlin\nfun onNameChange(user: User): Flux\u003cString\u003e {\n    return user.on\u003cUserUpdateNameEvent\u003e() // Flux\u003cUserUpdateNameEvent\u003e\n               .map { it.newValue }       // Flux\u003cString\u003e\n}\n\nfun onNameChange(channel: GuildChannel): Flux\u003cString\u003e {\n    return channel.onUpdate\u003cChannelUpdateNameEvent\u003e() // Flux\u003cChannelUpdateNameEvent\u003e\n                  .map { it.newValue }                // Flux\u003cString\u003e\n}\n```\n\n### CacheView\n\nI've added a special `toFluxLocked` which makes use of the `lockedIterator()` that was introduced in JDA version 4. This will automatically lock the cache view for read access when `subscribe()` is invoked and unlock it on the completion signal.\n\n#### Example toFluxLocked\n\n```kotlin\nfun findUserByName(jda: JDA, name: String): Mono\u003cUser\u003e {\n    return jda.userCache\n              .toFluxLocked()                  // Flux\u003cUser\u003e lazy locked user cache\n              .filterFirst { it.name == name } // Mono\u003cUser\u003e unlock on first match\n}\n\nfun sendToUser(jda: JDA, name: String, content: String) {\n    return findUserByName(name)                          // Mono\u003cUser\u003e\n           .flatMap { it.openPrivateChannel().asMono() } // Mono\u003cPrivateChannel\u003e\n           .flatMap { it.sendMessage(content).asMono() } // Mono\u003cMessage\u003e\n           .subscribe() // lock the user cache and look for the user by name\n}\n```\n\n### Quality of Life Extensions\n\nI've added a few extensions to reactor itself that might be useful when working with JDA.\n\n- `T?.toMono()` improvement of `T.toMono()` which uses `Mono.justOrEmpty` instead\n- `Mono.then(() -\u003e Mono\u003cR\u003e)` lazy version of `Mono.then(Mono\u003cR\u003e)` similar to `Mono.flatMap`\n- `Flux.then(() -\u003e Mono\u003cR\u003e)` same as above\n- `Flux.filterFirst((T) -\u003e Boolean)` combination of `filter().next()`\n- `Flux.filterFirstWhen((T) -\u003e Publisher\u003cBoolean\u003e)` combination of `filterWhen().next()`\n- `Flux.nextWhen((T) -\u003e Mono\u003cR\u003e)` combination of `next().flatMap()`\n- `Iterable\u003cCompletionStage\u003cT\u003e\u003e.asFlux(): Flux\u003cT\u003e` flatten lists of completion stages\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fminndevelopment%2Fjda-reactor","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fminndevelopment%2Fjda-reactor","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fminndevelopment%2Fjda-reactor/lists"}