Skip to content

Garmr/radiance daemon refactor and clean-up#8578

Open
garmr-ulfr wants to merge 58 commits intomainfrom
garmr/radiance-daemon-refactor
Open

Garmr/radiance daemon refactor and clean-up#8578
garmr-ulfr wants to merge 58 commits intomainfrom
garmr/radiance-daemon-refactor

Conversation

@garmr-ulfr
Copy link
Copy Markdown
Contributor

@garmr-ulfr garmr-ulfr commented Mar 25, 2026

Summary

  • Migrate lantern to radiance's new IPC Client architecture: All client-related functionality now goes through radiance/ipc.Client instead of directly calling radiance internals (radiance.Radiance, vpn.* package-level functions, api.APIClient, etc.)
  • Rewrite lantern-core/core.go: LanternCore now wraps *ipc.Client with platform-specific initialization via build tags (init_mobile.go for iOS/Android/macOS, init_desktop.go for Linux). All VPN, account, server, split tunnel, and settings operations delegate to the IPC client.
  • Update iOS/macOS network extensions: Start the IPC server (MobileStartIPCServer) before VPN operations in startTunnel, and close it (MobileCloseIPCServer) in stopTunnel.
  • Update Linux packaging: systemd service management updated for the lanternd daemon; package scripts use lanternd install/lanternd uninstall.
  • Replace lanternsvc / wintunmgr with lanternd: The Windows service binary now self-installs (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.
  • Migrate Flutter from cached app settings to on-demand radiance queries: Settings previously cached locally in Flutter (smart routing, ad block, split tunneling, etc.) are now fetched from radiance on demand via FFI, eliminating stale-state bugs and the AppSettingNotifier class.
  • Flatten server model to match radiance: The Server / ServerGroup hierarchy is replaced with a flat Server model matching radiance's representation, simplifying server selection and available-server plumbing across Go and Dart.
  • Unify CGo safety with RunOffCgoStack: All gomobile-exported functions in mobile.go and all FFI-exported functions in ffi.go now run on real Go goroutines via utils.RunOffCgoStack, preventing bulkBarrierPreWrite panics from CGo callback stacks.

closes getlantern/engineering/issues/3047

@garmr-ulfr garmr-ulfr changed the title Garmr/radiance daemon refactor Garmr/radiance daemon refactor and clean-up Apr 6, 2026
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.
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

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.Client and updates platform method channels/FFI accordingly.
  • Replaces Windows/Linux service management logic with lanternd install/uninstall flows (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.

Comment thread lib/features/vpn/provider/server_location_notifier.dart Outdated
Comment thread lib/features/vpn/provider/server_location_notifier.dart Outdated
Comment thread lib/core/utils/storage_utils.dart
Comment thread lib/core/utils/storage_utils.dart
Comment thread lib/features/home/home.dart Outdated
Comment thread lib/features/vpn/provider/server_location_notifier.dart
jigar-f and others added 5 commits April 14, 2026 09:39
* 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>
@atavism
Copy link
Copy Markdown
Contributor

atavism commented Apr 15, 2026

Replace lanternsvc / wintunmgr with lanternd: The Windows service binary now self-installs (lanternd install), handling service creation, recovery actions, and startup internally. This removes ~1,600 lines of Windows service management spread across Go (lanternsvc, wintunmgr), Dart (LanternServiceWindows, pipe_client.dart), and installer scripts.

@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!

@garmr-ulfr
Copy link
Copy Markdown
Contributor Author

garmr-ulfr commented Apr 15, 2026

@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:

“This removes ~1,600 lines of Windows service management spread across Go (lanternsvc, wintunmgr), Dart (LanternServiceWindows, pipe_client.dart), and installer scripts.”

to:

“This reduces the Windows service management code across Go (lanternsvc, wintunmgr), Dart (LanternServiceWindows, pipe_client.dart), and installer scripts by adopting Radiance’s lanternd.”

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 go-args instead of the stdlib flags, and I also added a few things. The only similarity is standard service setup (creation and recovery actions).

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!

@atavism
Copy link
Copy Markdown
Contributor

atavism commented Apr 16, 2026

@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.

@atavism
Copy link
Copy Markdown
Contributor

atavism commented Apr 16, 2026

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.

@garmr-ulfr Did radiance have a Windows service implementation before PR getlantern/radiance#370?

jigar-f and others added 4 commits April 16, 2026 20:11
* 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.
Comment thread lantern-core/core.go Outdated
Comment on lines -221 to -226
func (lc *LanternCore) listenConfigEvents() {
events.SubscribeContext(lc.ctx, func(evt config.NewConfigEvent) {
slog.Debug("Config updated, notifying Flutter")
lc.notifyFlutter(EventTypeConfig, "")
})
}
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants