Garmr/radiance daemon refactor and clean-up#8578
Conversation
Server tags are determined by URL content, not caller-supplied names. addServerBasedOnURLs now returns the tags of added servers so callers can connect using the actual tag. Also sends VPN status updates from connectToServer on Linux so the UI reflects connection state changes.
There was a problem hiding this comment.
Pull request overview
Refactors Lantern to use radiance’s new IPC client architecture end-to-end, consolidating platform service/daemon management around lanternd, and updating Flutter to query settings/servers on-demand from radiance instead of relying on locally cached state.
Changes:
- Migrates core VPN/account/server/settings operations to delegate through
radiance/ipc.Clientand updates platform method channels/FFI accordingly. - Replaces Windows/Linux service management logic with
lanternd install/uninstallflows (packaging + CI/scripts), removing legacy Windows service/pipe code. - Flattens/updates server + user models in Flutter and adjusts UI + integration tests to work with radiance-aligned representations (including returning added server tags).
Reviewed changes
Copilot reviewed 101 out of 103 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| windows/packaging/exe/inno_setup.iss | Installer now runs lanternd install/uninstall |
| scripts/windows/service_install.ps1 | Dev install uses lanternd install |
| scripts/ci/verify_linux_package.sh | Linux package expectations updated (bundle layout) |
| Makefile | Build targets renamed; stage lanternd into bundles |
| macos/Runner/Handlers/MethodHandler.swift | Adds radiance setting queries + returns tags |
| macos/PacketTunnel/SingBox/ExtensionProvider.swift | Starts/closes IPC server in tunnel lifecycle |
| linux/packaging/nfpm.yaml | Packages bundle under /usr/lib/lantern + symlink |
| linux/packaging/deb/scripts/prerm | Uses lanternd uninstall on remove |
| linux/packaging/deb/scripts/postrm | Removes systemd disable/reload steps |
| linux/packaging/deb/scripts/postinst | Uses lanternd install on configure |
| linux/packaging/arch/preremove.sh | Uses lanternd uninstall |
| linux/packaging/arch/postremove.sh | Keeps systemctl reset-failed only |
| linux/packaging/arch/postinstall.sh | Uses lanternd install |
| lib/lantern/lantern_windows_service.dart | Removes legacy Windows pipe/service client |
| lib/lantern/lantern_service.dart | API updates (user model, settings, server selection) |
| lib/lantern/lantern_platform_service.dart | MethodChannel implementations updated for new APIs |
| lib/lantern/lantern_core_service.dart | Core service interface updated (new methods/returns) |
| lib/features/vpn/single_city_server_view.dart | UI switches from Location_ to Server |
| lib/features/vpn/server_selection.dart | Server selection uses flattened Server model |
| lib/features/vpn/provider/vpn_notifier.g.dart | Regenerated Riverpod code |
| lib/features/vpn/provider/server_location_notifier.g.dart | Regenerated Riverpod code |
| lib/features/vpn/provider/server_location_notifier.dart | Server location now fetched from radiance (no local cache) |
| lib/features/vpn/provider/available_servers_notifier.g.dart | Regenerated Riverpod code |
| lib/features/vpn/provider/available_servers_notifier.dart | Improves error message |
| lib/features/system_tray/provider/system_tray_notifier.g.dart | Regenerated Riverpod code |
| lib/features/system_tray/provider/system_tray_notifier.dart | Tray uses on-demand radiance settings + new server model |
| lib/features/split_tunneling/split_tunneling.dart | Split-tunnel setting driven by radiance providers |
| lib/features/split_tunneling/provider/apps_notifier.g.dart | Regenerated Riverpod code |
| lib/features/setting/vpn_setting.dart | VPN settings UI uses radiance providers/controllers |
| lib/features/setting/smart_routing.dart | Routing mode driven by radiance providers/controllers |
| lib/features/private_server/provider/private_server_notifier.g.dart | Regenerated Riverpod code |
| lib/features/private_server/provider/private_server_notifier.dart | addServerBasedOnURLs now returns tags |
| lib/features/private_server/manage_private_server.dart | Private server UI updated for flattened server model |
| lib/features/private_server/join_private_server.dart | Join flow updated for new signature |
| lib/features/onboarding/onboarding.dart | Routing mode initialization via radiance controller |
| lib/features/home/provider/radiance_settings_providers.g.dart | Generated Riverpod providers/controllers (new) |
| lib/features/home/provider/radiance_settings_providers.dart | On-demand settings queries + mutation controllers (new) |
| lib/features/home/provider/home_notifier.g.dart | Regenerated Riverpod code |
| lib/features/home/provider/home_notifier.dart | Switches to JSON user model + device id field rename |
| lib/features/home/provider/app_setting_notifier.g.dart | Regenerated Riverpod code |
| lib/features/home/provider/app_setting_notifier.dart | Removes cached VPN/routing/ad-block/telemetry logic |
| lib/features/home/provider/app_event_notifier.g.dart | Regenerated Riverpod code |
| lib/features/home/provider/app_event_notifier.dart | Auto-location parsing updated for new server model |
| lib/features/home/home.dart | Uses radiance providers for routing/split-tunnel + logging tweaks |
| lib/features/auth/sign_in_password.dart | Uses UserResponseModel and removes OAuth token caching |
| lib/features/auth/sign_in_email.dart | Removes OAuth token/email caching in app settings |
| lib/features/auth/provider/auth_notifier.g.dart | Regenerated Riverpod code |
| lib/features/auth/provider/auth_notifier.dart | Uses JSON user model types |
| lib/features/auth/device_limit_reached.dart | Device model updated (deviceId) |
| lib/features/auth/create_password.dart | Removes OAuth token caching in app settings |
| lib/features/auth/confirm_email.dart | Refreshes user via HomeNotifier instead of cached email |
| lib/features/auth/add_email.dart | Removes cached email/token writes |
| lib/features/account/delete_account.dart | Uses radiance OAuth providers + compares against current email |
| lib/features/account/account.dart | Email sourced from userEmailProvider |
| lib/core/windows/pipe_commands.dart | Removes legacy Windows pipe commands |
| lib/core/windows/pipe_client.dart | Removes legacy Windows pipe client |
| lib/core/widgets/user_devices.dart | Device model updated (deviceId) |
| lib/core/utils/storage_utils.dart | Windows storage paths adjusted to PUBLIC profile |
| lib/core/services/local_storage_service.dart | Removes persisted server location |
| lib/core/services/app_purchase.dart | Subscription status read simplified |
| lib/core/router/router.gr.dart | Route args updated for new device model |
| lib/core/models/user.dart | New JSON user/device/subscription models |
| lib/core/models/server_location.dart | Adds ServerLocation.fromServer |
| lib/core/models/available_servers.dart | Flattens server model to match radiance |
| lib/core/models/app_setting.dart | Removes cached radiance-driven fields |
| lib/core/extensions/user_data.dart | Updates extension types to new user model |
| lib/core/extensions/ref.dart | Private-server detection uses hasUserServers |
| lib/core/extensions/plan.dart | Adapts plan formatting to new subscription model fields |
| lantern-core/wintunmgr/service_windows.go | Removes legacy Windows service implementation |
| lantern-core/wintunmgr/observability.go | Removes legacy Windows observability helpers |
| lantern-core/wintunmgr/manager.go | Removes legacy Wintun manager |
| lantern-core/wintunmgr/ipc.go | Removes legacy Windows IPC structs |
| lantern-core/vpn_tunnel/vpn_tunnel.go | VPN ops delegate through IPC client |
| lantern-core/utils/gostack.go | Adds RunOffCgoStack helper (new) |
| lantern-core/utils/common.go | Removes log attachment helper; adds Platform to Opts |
| lantern-core/private-server/server.go | Private server flows migrate to IPC client APIs |
| lantern-core/mobile/ipc_extension_other.go | Loopback IPC client stub for non-mobile (new) |
| lantern-core/mobile/ipc_extension_mobile.go | Loopback IPC client for mobile/darwin (new) |
| lantern-core/init_mobile.go | IPC client init for mobile/darwin (new) |
| lantern-core/init_desktop.go | IPC client init for desktop (new) |
| lantern-core/ffi/util.go | Removes unused helper |
| lantern-core/ffi/ffi_nonlinux.go | Adds daemon reachability check helper |
| lantern-core/ffi/ffi_linux.go | Linux daemon reachability + systemd diagnostics helper |
| lantern-core/apps/apps_test.go | Skips macOS-only tests on non-darwin |
| ios/Tunnel/SingBox/ExtensionProvider.swift | Starts/closes IPC server in tunnel lifecycle |
| ios/Runner/Handlers/MethodHandler.swift | Adds radiance setting queries + returns tags |
| integration_test/vpn/config_url_connect_smoke_harness.dart | URL hash normalization + server naming behavior |
| integration_test/vpn/config_url_api_smoke_harness.dart | Uses returned server tags for connect |
| go.sum | Updates radiance version + dependency cleanup |
| go.mod | Updates radiance version + dependency adjustments |
| android/app/src/main/kotlin/org/getlantern/lantern/handler/MethodHandler.kt | Adds settings methods + returns tags from add-server |
| .github/workflows/build-windows.yml | Removes Wintun DLL signing exception |
| .github/workflows/build-windows-service.yml | Builds/uploads lanternd.exe |
| .github/workflows/build-linux.yml | Adjusts smoke test expectations and execution |
| .github/scripts/windows_connect_smoke.ps1 | Uses lanternd install/uninstall; updates config URL flows |
| .github/scripts/linux_config_url_smoke.sh | Runs config URL smoke without sg lantern |
| lantern-core/common/win_command.go | Removes legacy Windows service command constants |
| lantern-core/cmd/lanternsvc/main.go | Removes legacy Windows service binary |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
This reverts commit a21a218.
* if system extension is in uninstall state do not block new installtion. * update macos system extension test * do not cache dart_tool * Set the default status as unknown. * code review updates
* Add split tunneling e2e test * Fix split tunneling website smoke assertion * Fix split tunneling smoke navigation * code review updates * code review updates * code review updates * Filter Windows system apps in split tunneling list * code review updates * code review updates * Update system apps filter * code review updates
…8649) The upload-s3 and upload-release-artifacts jobs required ALL platform builds to succeed or be skipped. When a matrix entry failed (e.g., Linux arm64), the entire build-linux job reported as 'failure', which caused both upload jobs to skip entirely — even though macOS, Android, iOS, and Linux amd64 all succeeded. Simplify the condition: run uploads if at least one platform build succeeded. The upload steps already handle missing artifacts gracefully (upload_if_exists checks for file existence). This ensures the Slack notification goes out with download links for whatever platforms did build successfully. Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: add arch to releases * Update linux/packaging/usr/lib/systemd/system/lanternd.service Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * chore: remove committed lanternd.service file Agent-Logs-Url: https://github.com/getlantern/lantern/sessions/15085485-3c6a-4e1e-93ea-6e9bf0623d09 Co-authored-by: reflog <109876+reflog@users.noreply.github.com> --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: reflog <109876+reflog@users.noreply.github.com>
@garmr-ulfr This summary is a bit misleading. The branch removes about 1,600 lines of code, but it does not remove that functionality. It moves the Windows service implementation into radiance/lanternd, where the service still exists and still owns the same core responsibilities. Please update the PR description to describe this as a migration of the Windows service into Radiance, and acknowledge that the implementation is derived from the existing lanternsvc / wintunmgr code. Thanks! |
I updated the description from:
to:
To clarify, the Windows service implementation wasn’t moved into radiance; the refactor is just reusing radiance’s implementation. It’s not derived from the existing lanternsvc / wintunmgr code; it's actually the CLI that I've been using for manually testing radiance for a while now. It's just [significantly] cleaned up and it uses The goal here was to simplify maintenance and offload some work from the apps team by consolidating on a single implementation. I can revert it to use the existing lanternsvc / wintunmgr implementation if you prefer; it's not a problem. Up to you! |
|
@garmr-ulfr Thanks for updating the description. One factual correction for the record: while Lantern is adopting Radiance’s lanternd, the Windows service implementation is not independent of the existing lanternsvc / wintunmgr work. The current Windows service code preserves the same service identity, SCM/service wrapper pattern, and core responsibilities, and there is direct code overlap with the prior Lantern implementation as well So I think the accurate description is that this consolidates the existing Windows service model into Radiance rather than replacing it with a wholly separate implementation. |
@garmr-ulfr Did radiance have a Windows service implementation before PR getlantern/radiance#370? |
* mobile: return string instead of []byte from gomobile-exported funcs The gomobile wrapper copies Go pointer-containing return values to the C thread stack using runtime.wbMove. When a GC cycle runs during the copy, bulkBarrierPreWrite panics because the destination isn't GC-tracked. Returning string avoids this — gomobile marshals strings via C heap allocation rather than leaving them as Go slice headers. See getlantern/engineering#3175 for the full crash analysis (from Freshdesk #172640 — Derek reporting "Lantern Crash" on macOS 26.3.1). Go changes: AvailableFeatures, UserData, FetchUserData, GetAvailableServers, GetSelectedServerJSON, OAuthLoginCallback, AcknowledgeGooglePurchase, AcknowledgeApplePurchase, Login, Logout, DeleteAccount Swift changes (macos + ios): preserve Flutter contract by converting the string back to Data for methods whose Dart side reads `bytes` via utf8.decode (getUserData, fetchUserData, oauthLoginCallback, login, logout, deleteAccount, acknowledgeInAppPurchase). For methods whose Dart side expects String (featureFlags, getLanternAvailableServers, getSelectedServerJSON), just pass the gomobile string directly. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * android: update MethodHandler for string-returning gomobile bindings The gomobile-exported funcs in lantern-core/mobile/mobile.go now return string instead of []byte. The generated Android binding will therefore return String where it used to return ByteArray. For each affected method, match what the iOS handler does so the Flutter platform-channel contract stays stable: * Methods whose Dart callers expect bytes (Uint8List) — login, logout, deleteAccount, userData, fetchUserData, oauthLoginCallback, acknowledgeGooglePurchase — convert the String result via `.toByteArray(Charsets.UTF_8)` before calling success() (mirrors Swift's `.data(using: .utf8)`). * Methods whose Dart callers expect a String — availableFeatures, getAvailableServers, getSelectedServerJSON — drop the `String(byteArray)` constructor and use the return value directly, with the same "{}" / "[]" empty-default that iOS uses. Addresses Copilot review on PR #8663. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Route all IPC operations through LanternCore methods instead of exposing Client() to callers. Add GetSelectedServerTag, GetAutoLocationJSON, CheckDaemonReachable, PatchSettings, and VPNStatusEvents to the Core interface. Update FFI and mobile layers to use them, and remove now-unused vpn_tunnel helper functions. Also includes Flutter-side fixes: device-removal sign-in race condition, plans fetch retry logic, and private server setup improvements.
| func (lc *LanternCore) listenConfigEvents() { | ||
| events.SubscribeContext(lc.ctx, func(evt config.NewConfigEvent) { | ||
| slog.Debug("Config updated, notifying Flutter") | ||
| lc.notifyFlutter(EventTypeConfig, "") | ||
| }) | ||
| } |
There was a problem hiding this comment.
@jigar-f the config is owned by the daemon/tunnel process so that's where the config fetch happens. On Windows and Linux, there are no config events on the app side. On mobile and macOS, the initial config request happens in the main process before the tunnel process starts, then the config is only fetched from the tunnel process.
None of the radiance events are emitted client-side (main process), with the exception of the initial config requests before the tunnel process starts. All interactions with radiance must go through the ipc.Client.
Why does the main process need to know when the config updated?
The gomobile-exported functions in lantern-core/mobile/mobile.go were
migrated from ([]byte, error) to (string, error). gomobile renders the
new signatures with a non-optional Swift String return (Data was
optional; String is not), so `json?.data(using: .utf8)` and
`payload?.data(using: .utf8)` now fail to compile:
error: cannot use optional chaining on non-optional value of type
'String'
Drop the `?` on all 14 call sites (7 each in ios/ and macos/). The
resulting `json.data(using: .utf8)` returns Data? anyway — an empty
Go string still produces a non-nil empty Data, which preserves the
Flutter contract the comment on these lines describes.
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Summary
lanternd install), handling service creation, recovery actions, and startup internally. This reduces the Windows service management code spread across Go (lanternsvc, wintunmgr), Dart (LanternServiceWindows, pipe_client.dart), and installer scripts by adopting radiance's lanternd.closes getlantern/engineering/issues/3047