Skip to content

Replace Discord Social SDK (C++/JNI) with OAuth2 Gateway RPC (Kotlin) — removes proprietary SDK dependency - #27

Closed
sang765 wants to merge 11 commits into
devfrom
refactor/discord-rpc-replacement
Closed

sang765 wants to merge 11 commits into
devfrom
refactor/discord-rpc-replacement

Conversation

@sang765

@sang765 sang765 commented Jun 3, 2026

Copy link
Copy Markdown
Owner

Summary

Eliminates the dependency on Discord's proprietary Social SDK (C++ native library + JNI bridge) by replacing it with a pure Kotlin implementation that connects directly to the Discord Gateway WebSocket using an OAuth2 bearer token. The Discord-OAuth2-RPC library handles the WebSocket lifecycle, heartbeats, and presence updates without any native code.

Motivation

  • No proprietary SDK required — removes the need for discord_partner_sdk.aar, which is partner-only and requires manual approval from Discord
  • Simpler build — eliminates CMake, C++ compilation, and per-architecture native library builds
  • Same OAuth flow — reuses the existing PKCE-based OAuth2 authorization; no changes to the user's authorization experience
  • All-Kotlin stack — leverages Ktor WebSocket client and kotlinx-serialization already in the project

Changes

Added

  • com.discord.oauth2rpc library package (Gateway WebSocket client, RichPresence builder, bitfield utilities)
  • DiscordOAuth2RPCClient — singleton gateway client mapping DiscordPresenceActivity → Gateway PRESENCE_UPDATE (opcode 3)

Modified

  • DiscordRPC.kt — delegates to DiscordOAuth2RPCClient instead of DiscordSocialPresenceClient
  • DiscordPresenceManager.kt — removed callbacksJob loop (no longer needed; Gateway handles heartbeats internally)
  • MainActivity.kt — removed DiscordSocialSdkAndroidInitializer.setEngineActivity() calls
  • app/build.gradle.kts — removed CMake/native build config, removed discord_partner_sdk.aar dependency

Removed

  • DiscordSocialNativeBridge.kt — JNI external fun declarations and native library loader
  • DiscordSocialPresenceClient.kt — mutex-guarded presence client wrapping the native bridge
  • DiscordSocialSdkAndroidInitializer.kt — reflection-based setEngineActivity() for Social SDK
  • discord_social_bridge.cpp — 461-line C++ JNI implementation
  • app/src/main/cpp/CMakeLists.txt — CMake build definition

Unchanged

  • DiscordPresenceModels.kt, DiscordOAuthRepository.kt, DiscordOAuthCallbackActivity.kt — same data models and OAuth flow
  • DiscordImageResolver.kt, DiscordSettings.kt, DiscordExperimental.kt — UI and image caching unchanged

Architecture Comparison

Layer Before (Social SDK) After (Gateway RPC)
Transport Discord Social SDK (C++) + JNI Discord Gateway WebSocket
Auth OAuth2 + SDK token OAuth2 bearer token (same flow)
Build CMake + C++ + proprietary .aar Pure Kotlin, no native build
Heartbeat Manual runCallbacks() loop Automatic (GatewayClient internal)
Images SDK handles asset resolution URLs passed as-is (Discord CDN / external supported)

…otlin)

Replace Discord Social SDK native C++/JNI integration with the
Discord-OAuth2-RPC Kotlin library that connects to Discord Gateway
WebSocket directly via OAuth2 bearer token.

Changes:
- Add GatewayClient, RichPresence builder, and supporting utils from
  Discord-OAuth2-RPC library (com.discord.oauth2rpc package)
- Create DiscordOAuth2RPCClient replacing DiscordSocialPresenceClient
  and DiscordSocialNativeBridge JNI layer
- Remove native C++ bridge (discord_social_bridge.cpp, CMakeLists.txt)
- Remove DiscordSocialSdkAndroidInitializer (reflection-based SDK init)
- Remove discord_partner_sdk.aar dependency and CMake build config
- Keep existing DiscordRPC.kt high-level logic, DiscordPresenceModels,
  DiscordOAuthRepository, and OAuth callback unchanged
@sang765 sang765 self-assigned this Jun 3, 2026
@sang765 sang765 added enhancement New feature or request good first issue Good for newcomers labels Jun 3, 2026
@sang765 sang765 changed the title refactor: replace Discord Social SDK (C++) with OAuth2 Gateway RPC (Kotlin) Replace Discord Social SDK (C++/JNI) with OAuth2 Gateway RPC (Kotlin) — removes proprietary SDK dependency Jun 3, 2026
Repository owner deleted a comment from qodo-code-review Bot Jun 3, 2026
sang765 added 7 commits June 4, 2026 05:41
…blic/private methods

- updatePresence() held mutex then called connect() which tried to
  re-acquire the same non-reentrant Mutex — caused JobCancellationException
- Split into connect() (public, with lock) → connectInternal() (private, no lock)
- Removed superfluous scope.launch + CompletableDeferred wrapper;
  gws.connect() already suspends until READY
- Removed unused scope/connectJob members
- Removed -keep rules for com.discord.socialsdk.** and DiscordSocialNativeBridge
- Removed -dontwarn for com.discord.socialsdk.**
These classes no longer exist after the Social SDK→Gateway RPC migration
@kilo-code-bot

kilo-code-bot Bot commented Jun 4, 2026

Copy link
Copy Markdown

Code Review Summary

Status: Issues Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 1
WARNING 2
SUGGESTION 0
Issue Details (click to expand)

CRITICAL

File Line Issue
app/src/gms/kotlin/com/discord/oauth2rpc/utils/JsonObjectMapper.kt 15-19 String replace() calls have no effect - the result is discarded without assignment. Strings are immutable in Kotlin.

WARNING

File Line Issue
app/src/gms/kotlin/com/discord/oauth2rpc/Gateway.kt 196 INVALID_SESSION payload parsing uses jsonPrimitive.boolean but should verify d is a JsonPrimitive first.
app/src/gms/kotlin/com/discord/oauth2rpc/Gateway.kt 49 connect() method is not thread-safe - multiple concurrent calls could race before the wsSession != null check.
Other Observations (not in diff)

No issues found in unchanged code.

Files Reviewed (11 files)
  • app/build.gradle.kts - No issues (build config changes)
  • app/proguard-rules.pro - No issues (removed rules for deleted SDK)
  • app/src/gms/kotlin/com/discord/oauth2rpc/Gateway.kt - 2 issues
  • app/src/gms/kotlin/com/discord/oauth2rpc/Interface.kt - No issues
  • app/src/gms/kotlin/com/discord/oauth2rpc/structures/Presence.kt - No issues
  • app/src/gms/kotlin/com/discord/oauth2rpc/utils/BitField.kt - No issues
  • app/src/gms/kotlin/com/discord/oauth2rpc/utils/Constants.kt - No issues
  • app/src/gms/kotlin/com/discord/oauth2rpc/utils/GatewayCapabilities.kt - No issues
  • app/src/gms/kotlin/com/discord/oauth2rpc/utils/Intents.kt - No issues
  • app/src/gms/kotlin/com/discord/oauth2rpc/utils/JsonObjectMapper.kt - 1 issue
  • app/src/gms/kotlin/moe/koiverse/archivetune/discord/DiscordOAuth2RPCClient.kt - No issues
  • app/src/gms/kotlin/moe/koiverse/archivetune/utils/DiscordRPC.kt - No issues

forceClose(4000, "server reconnect")
}
GatewayOp.INVALID_SESSION -> {
val resumable = d?.jsonPrimitive?.boolean ?: false

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WARNING: INVALID_SESSION payload parsing could fail silently

Discord sends d as a boolean primitive (true/false) for INVALID_SESSION, but the code uses d?.jsonPrimitive?.boolean. If d is not a JsonPrimitive (e.g., null or malformed), this could throw or return incorrect values. Consider adding explicit type checking: d?.jsonPrimitive?.booleanOrNull ?: false

fun getSession(): SessionState? = sessionState?.copy()

suspend fun connect(opts: GatewayConnectOptions) {
if (wsSession != null) throw IllegalStateException("GatewayClient already connected")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WARNING: Potential race condition in connect()

While connect() checks wsSession != null at the start, multiple coroutine contexts could pass this check before either sets wsSession, potentially creating duplicate WebSocket sessions. Though the mutex in DiscordOAuth2RPCClient.connectInternal provides some protection, consider adding synchronization within GatewayClient.connect() itself for robustness.

@kilo-code-bot

kilo-code-bot Bot commented Jun 4, 2026

Copy link
Copy Markdown

Code Review Summary

Status: No Issues Found | Recommendation: Merge

All previously reported issues have been addressed in this incremental diff:

  • Thread-safety race condition in connect() - Fixed with synchronized block
  • INVALID_SESSION parsing - Fixed with booleanOrNull
  • JsonObjectMapper string escaping - Fixed improper StringBuilder usage
Files Reviewed (2 files)
  • app/src/gms/kotlin/com/discord/oauth2rpc/Gateway.kt - No issues (previous issues resolved)
  • app/src/gms/kotlin/com/discord/oauth2rpc/utils/JsonObjectMapper.kt - No issues (previous issue resolved)

Reviewed by laguna-m.1-20260312:free · 147,080 tokens

@sang765 sang765 closed this Jun 4, 2026
@sang765
sang765 deleted the refactor/discord-rpc-replacement branch June 4, 2026 01:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request good first issue Good for newcomers

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant