feat: expose getServerLocations FFI for pro user location picker#8577
Closed
myleshorton wants to merge 13 commits intomainfrom
Closed
feat: expose getServerLocations FFI for pro user location picker#8577myleshorton wants to merge 13 commits intomainfrom
myleshorton wants to merge 13 commits intomainfrom
Conversation
…panics The radiance API methods are wrapped with RunOffCgoStack, but the FFI bridge in lantern allocates Go memory (base64 encoding, C.CString) AFTER the radiance call returns — still on the CGo callback stack. This triggers bulkBarrierPreWrite panics on macOS. Add runOnGoStack() helper that runs the entire FFI function body on a real Go goroutine. Applied to: getUserData, fetchUserData, login, signup, logout, oAuthLoginCallback, deleteAccount. Fixes getlantern/engineering#3102 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace local runOnGoStack with a thin wrapper around common.RunOffCgoStack from radiance, avoiding code duplication. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add GetServerLocations() which returns all available server locations from the config response (ConfigResponse.Servers). Unlike GetAvailableServers() which returns active outbounds from the sing-box config, this returns every location the user can select — including ones without current routes. The Flutter location picker should use this instead of getAvailableServers so pro users see all available locations. Selecting a location triggers SetPreferredServer which refetches config with routes for that location. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
Pull request overview
This PR exposes a new API to retrieve the full list of selectable VPN server locations (not just currently-active routes) by adding a LanternCore method and exporting it over the Go FFI for the Flutter “pro user location picker” flow.
Changes:
- Add
GetServerLocations()toLanternCore(marshals Radiance server locations to JSON). - Export
getServerLocationsover FFI, and introduce arunOnGoStackhelper to execute FFI logic off the cgo callback stack. - Refactor several existing FFI exports to use
runOnGoStackto avoid GC/write-barrier panics.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 6 comments.
| File | Description |
|---|---|
lantern-core/ffi/ffi.go |
Adds runOnGoStack, exports getServerLocations, and wraps several FFI exports to run off the cgo callback stack. |
lantern-core/core.go |
Extends the core interface and implements GetServerLocations() to return all available server locations as JSON. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Wire up the getServerLocations FFI export through all layers: - lantern_generated_bindings.dart: FFI binding - lantern_core_service.dart: interface method - lantern_ffi_service.dart: desktop implementation - lantern_platform_service.dart: mobile implementation (method channel) - lantern_service.dart: router (FFI vs platform) Returns all available server locations from the config response, enabling the location picker to show locations the user can select even if they don't currently have routes for them. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Full client-side wiring for pro user server location selection: Go layer: - SetPreferredServerLocation in core.go + FFI export - getServerLocations returns all available locations from config Flutter layer: - serverLocationsProvider (Riverpod) fetches all locations - Pro users see all locations (not just active outbounds) - Selecting a location calls setPreferredServerLocation, which triggers a config refetch with that region included in the bandit selection - Free users continue using the existing outbound-based list Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Move all C.GoString conversions inside runOnGoStack closures so Go string allocations happen on a real goroutine, not the cgo stack - Handle error from RunOffCgoStack (panic recovery) via SendError instead of silently discarding it Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…-ffi # Conflicts: # lantern-core/ffi/ffi.go
Pro users see "Smart Protocol" as the subtitle for each location since the bandit system selects the optimal protocol. Free users continue seeing the specific protocol name from the outbound tag. - Add showSmartProtocol flag to SingleCityServerView and _CountryCityListView - Add smart_protocol i18n string - Protocol label logic: show specific protocol if set, otherwise "Smart Protocol" for pro users, or nothing for free users Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add Go mobile bindings, Android Kotlin handler, and iOS Swift handler for both methods. Fixes "No implementation found for method getServerLocations on channel" error on mobile platforms. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
macOS uses gomobile method channels (same as iOS), not direct FFI. Add both methods to the macOS MethodHandler.swift. Platform coverage: - Windows/Linux: FFI exports in ffi.go (already there) - macOS: method channel handler (this commit) - Android: method channel handler (previous commit) - iOS: method channel handler (previous commit) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Fix null crash when getServerLocations returns empty/null - All users see all locations (free users see them but can't select) - Fall back to outbound-based locations if server locations unavailable Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Per Jigar's feedback: move the merge logic from Flutter into radiance. The getServerLocations FFI now calls AllLocations() which returns a unified list with tag, protocol, and active status per location. - radiance: AllLocations() merges ConfigResponse.Servers + active outbounds - core.go: GetAllLocations() wraps the radiance method - FFI/mobile: getServerLocations calls GetAllLocations with fallback - Flutter: provider simplified, just parses the unified response - Bump radiance to include AllLocations() Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
GetServerLocations()to LanternCore — returns all available locations fromConfigResponse.ServersgetServerLocationsFFI export (wrapped withrunOnGoStack)Context
For pro user location selection with the bandit system, the Flutter UI needs the full location list (not just active outbounds). When a user selects a location:
SetPreferredServer(country, city)Test plan
getServerLocationsreturns the config response's server list🤖 Generated with Claude Code