From 555f5233cc33e8d8a027af9a539470907c158bef Mon Sep 17 00:00:00 2001 From: mlsmaycon Date: Tue, 28 Apr 2026 03:41:36 +0200 Subject: [PATCH] add flutter example app test --- client/flutter_ui/.gitignore | 6 + client/flutter_ui/.metadata | 36 + client/flutter_ui/MIGRATION.md | 115 + client/flutter_ui/README.md | 54 + client/flutter_ui/analysis_options.yaml | 10 + .../assets/tray/connected-macos.png | Bin 0 -> 3858 bytes client/flutter_ui/assets/tray/connected.png | Bin 0 -> 5287 bytes .../assets/tray/connecting-macos.png | Bin 0 -> 3843 bytes client/flutter_ui/assets/tray/connecting.png | Bin 0 -> 5412 bytes .../assets/tray/disconnected-macos.png | Bin 0 -> 3491 bytes .../flutter_ui/assets/tray/disconnected.png | Bin 0 -> 4800 bytes client/flutter_ui/assets/tray/error-macos.png | Bin 0 -> 3837 bytes client/flutter_ui/assets/tray/error.png | Bin 0 -> 5260 bytes client/flutter_ui/lib/main.dart | 53 + client/flutter_ui/lib/src/app_shell.dart | 889 ++ client/flutter_ui/lib/src/daemon_client.dart | 916 ++ client/flutter_ui/lib/src/debug_screen.dart | 460 + .../lib/src/desktop_integration.dart | 434 + .../lib/src/generated/daemon.pb.dart | 7393 +++++++++++++++++ .../lib/src/generated/daemon.pbenum.dart | 153 + .../lib/src/generated/daemon.pbgrpc.dart | 1141 +++ .../lib/src/generated/daemon.pbjson.dart | 2589 ++++++ client/flutter_ui/lib/src/models.dart | 257 + client/flutter_ui/lib/src/platform.dart | 22 + .../flutter_ui/lib/src/update_progress.dart | 140 + client/flutter_ui/linux/.gitignore | 1 + client/flutter_ui/linux/CMakeLists.txt | 128 + .../flutter_ui/linux/flutter/CMakeLists.txt | 88 + .../flutter/generated_plugin_registrant.cc | 27 + .../flutter/generated_plugin_registrant.h | 15 + .../linux/flutter/generated_plugins.cmake | 27 + client/flutter_ui/linux/runner/CMakeLists.txt | 26 + client/flutter_ui/linux/runner/main.cc | 6 + .../flutter_ui/linux/runner/my_application.cc | 148 + .../flutter_ui/linux/runner/my_application.h | 21 + client/flutter_ui/macos/.gitignore | 7 + .../macos/Flutter/Flutter-Debug.xcconfig | 2 + .../macos/Flutter/Flutter-Release.xcconfig | 2 + .../Flutter/GeneratedPluginRegistrant.swift | 18 + client/flutter_ui/macos/Podfile | 42 + client/flutter_ui/macos/Podfile.lock | 40 + .../macos/Runner.xcodeproj/project.pbxproj | 801 ++ .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../xcshareddata/xcschemes/Runner.xcscheme | 99 + .../contents.xcworkspacedata | 10 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../flutter_ui/macos/Runner/AppDelegate.swift | 13 + .../AppIcon.appiconset/Contents.json | 68 + .../AppIcon.appiconset/app_icon_1024.png | Bin 0 -> 102994 bytes .../AppIcon.appiconset/app_icon_128.png | Bin 0 -> 5680 bytes .../AppIcon.appiconset/app_icon_16.png | Bin 0 -> 520 bytes .../AppIcon.appiconset/app_icon_256.png | Bin 0 -> 14142 bytes .../AppIcon.appiconset/app_icon_32.png | Bin 0 -> 1066 bytes .../AppIcon.appiconset/app_icon_512.png | Bin 0 -> 36406 bytes .../AppIcon.appiconset/app_icon_64.png | Bin 0 -> 2218 bytes .../macos/Runner/Base.lproj/MainMenu.xib | 343 + .../macos/Runner/Configs/AppInfo.xcconfig | 14 + .../macos/Runner/Configs/Debug.xcconfig | 2 + .../macos/Runner/Configs/Release.xcconfig | 2 + .../macos/Runner/Configs/Warnings.xcconfig | 13 + .../macos/Runner/DebugProfile.entitlements | 12 + client/flutter_ui/macos/Runner/Info.plist | 32 + .../macos/Runner/MainFlutterWindow.swift | 15 + .../macos/Runner/Release.entitlements | 10 + .../macos/RunnerTests/RunnerTests.swift | 12 + client/flutter_ui/pubspec.lock | 413 + client/flutter_ui/pubspec.yaml | 28 + client/flutter_ui/test/app_shell_test.dart | 19 + client/flutter_ui/tool/bootstrap.sh | 36 + client/flutter_ui/tool/generate_proto.sh | 29 + client/flutter_ui/windows/.gitignore | 17 + client/flutter_ui/windows/CMakeLists.txt | 108 + .../flutter_ui/windows/flutter/CMakeLists.txt | 109 + .../flutter/generated_plugin_registrant.cc | 23 + .../flutter/generated_plugin_registrant.h | 15 + .../windows/flutter/generated_plugins.cmake | 27 + .../flutter_ui/windows/runner/CMakeLists.txt | 40 + client/flutter_ui/windows/runner/Runner.rc | 121 + .../windows/runner/flutter_window.cpp | 71 + .../windows/runner/flutter_window.h | 33 + client/flutter_ui/windows/runner/main.cpp | 43 + client/flutter_ui/windows/runner/resource.h | 16 + .../windows/runner/resources/app_icon.ico | Bin 0 -> 33772 bytes .../windows/runner/runner.exe.manifest | 14 + client/flutter_ui/windows/runner/utils.cpp | 65 + client/flutter_ui/windows/runner/utils.h | 19 + .../windows/runner/win32_window.cpp | 288 + .../flutter_ui/windows/runner/win32_window.h | 102 + 88 files changed, 18364 insertions(+) create mode 100644 client/flutter_ui/.gitignore create mode 100644 client/flutter_ui/.metadata create mode 100644 client/flutter_ui/MIGRATION.md create mode 100644 client/flutter_ui/README.md create mode 100644 client/flutter_ui/analysis_options.yaml create mode 100644 client/flutter_ui/assets/tray/connected-macos.png create mode 100644 client/flutter_ui/assets/tray/connected.png create mode 100644 client/flutter_ui/assets/tray/connecting-macos.png create mode 100644 client/flutter_ui/assets/tray/connecting.png create mode 100644 client/flutter_ui/assets/tray/disconnected-macos.png create mode 100644 client/flutter_ui/assets/tray/disconnected.png create mode 100644 client/flutter_ui/assets/tray/error-macos.png create mode 100644 client/flutter_ui/assets/tray/error.png create mode 100644 client/flutter_ui/lib/main.dart create mode 100644 client/flutter_ui/lib/src/app_shell.dart create mode 100644 client/flutter_ui/lib/src/daemon_client.dart create mode 100644 client/flutter_ui/lib/src/debug_screen.dart create mode 100644 client/flutter_ui/lib/src/desktop_integration.dart create mode 100644 client/flutter_ui/lib/src/generated/daemon.pb.dart create mode 100644 client/flutter_ui/lib/src/generated/daemon.pbenum.dart create mode 100644 client/flutter_ui/lib/src/generated/daemon.pbgrpc.dart create mode 100644 client/flutter_ui/lib/src/generated/daemon.pbjson.dart create mode 100644 client/flutter_ui/lib/src/models.dart create mode 100644 client/flutter_ui/lib/src/platform.dart create mode 100644 client/flutter_ui/lib/src/update_progress.dart create mode 100644 client/flutter_ui/linux/.gitignore create mode 100644 client/flutter_ui/linux/CMakeLists.txt create mode 100644 client/flutter_ui/linux/flutter/CMakeLists.txt create mode 100644 client/flutter_ui/linux/flutter/generated_plugin_registrant.cc create mode 100644 client/flutter_ui/linux/flutter/generated_plugin_registrant.h create mode 100644 client/flutter_ui/linux/flutter/generated_plugins.cmake create mode 100644 client/flutter_ui/linux/runner/CMakeLists.txt create mode 100644 client/flutter_ui/linux/runner/main.cc create mode 100644 client/flutter_ui/linux/runner/my_application.cc create mode 100644 client/flutter_ui/linux/runner/my_application.h create mode 100644 client/flutter_ui/macos/.gitignore create mode 100644 client/flutter_ui/macos/Flutter/Flutter-Debug.xcconfig create mode 100644 client/flutter_ui/macos/Flutter/Flutter-Release.xcconfig create mode 100644 client/flutter_ui/macos/Flutter/GeneratedPluginRegistrant.swift create mode 100644 client/flutter_ui/macos/Podfile create mode 100644 client/flutter_ui/macos/Podfile.lock create mode 100644 client/flutter_ui/macos/Runner.xcodeproj/project.pbxproj create mode 100644 client/flutter_ui/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 client/flutter_ui/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme create mode 100644 client/flutter_ui/macos/Runner.xcworkspace/contents.xcworkspacedata create mode 100644 client/flutter_ui/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 client/flutter_ui/macos/Runner/AppDelegate.swift create mode 100644 client/flutter_ui/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 client/flutter_ui/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png create mode 100644 client/flutter_ui/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png create mode 100644 client/flutter_ui/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png create mode 100644 client/flutter_ui/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png create mode 100644 client/flutter_ui/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png create mode 100644 client/flutter_ui/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png create mode 100644 client/flutter_ui/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png create mode 100644 client/flutter_ui/macos/Runner/Base.lproj/MainMenu.xib create mode 100644 client/flutter_ui/macos/Runner/Configs/AppInfo.xcconfig create mode 100644 client/flutter_ui/macos/Runner/Configs/Debug.xcconfig create mode 100644 client/flutter_ui/macos/Runner/Configs/Release.xcconfig create mode 100644 client/flutter_ui/macos/Runner/Configs/Warnings.xcconfig create mode 100644 client/flutter_ui/macos/Runner/DebugProfile.entitlements create mode 100644 client/flutter_ui/macos/Runner/Info.plist create mode 100644 client/flutter_ui/macos/Runner/MainFlutterWindow.swift create mode 100644 client/flutter_ui/macos/Runner/Release.entitlements create mode 100644 client/flutter_ui/macos/RunnerTests/RunnerTests.swift create mode 100644 client/flutter_ui/pubspec.lock create mode 100644 client/flutter_ui/pubspec.yaml create mode 100644 client/flutter_ui/test/app_shell_test.dart create mode 100755 client/flutter_ui/tool/bootstrap.sh create mode 100755 client/flutter_ui/tool/generate_proto.sh create mode 100644 client/flutter_ui/windows/.gitignore create mode 100644 client/flutter_ui/windows/CMakeLists.txt create mode 100644 client/flutter_ui/windows/flutter/CMakeLists.txt create mode 100644 client/flutter_ui/windows/flutter/generated_plugin_registrant.cc create mode 100644 client/flutter_ui/windows/flutter/generated_plugin_registrant.h create mode 100644 client/flutter_ui/windows/flutter/generated_plugins.cmake create mode 100644 client/flutter_ui/windows/runner/CMakeLists.txt create mode 100644 client/flutter_ui/windows/runner/Runner.rc create mode 100644 client/flutter_ui/windows/runner/flutter_window.cpp create mode 100644 client/flutter_ui/windows/runner/flutter_window.h create mode 100644 client/flutter_ui/windows/runner/main.cpp create mode 100644 client/flutter_ui/windows/runner/resource.h create mode 100644 client/flutter_ui/windows/runner/resources/app_icon.ico create mode 100644 client/flutter_ui/windows/runner/runner.exe.manifest create mode 100644 client/flutter_ui/windows/runner/utils.cpp create mode 100644 client/flutter_ui/windows/runner/utils.h create mode 100644 client/flutter_ui/windows/runner/win32_window.cpp create mode 100644 client/flutter_ui/windows/runner/win32_window.h diff --git a/client/flutter_ui/.gitignore b/client/flutter_ui/.gitignore new file mode 100644 index 000000000..e4efcb381 --- /dev/null +++ b/client/flutter_ui/.gitignore @@ -0,0 +1,6 @@ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +build/ +coverage/ diff --git a/client/flutter_ui/.metadata b/client/flutter_ui/.metadata new file mode 100644 index 000000000..cb5faccaa --- /dev/null +++ b/client/flutter_ui/.metadata @@ -0,0 +1,36 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: "02085feb3f5d8a8156e5e28512b9d99351d510c0" + channel: "stable" + +project_type: app + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: 02085feb3f5d8a8156e5e28512b9d99351d510c0 + base_revision: 02085feb3f5d8a8156e5e28512b9d99351d510c0 + - platform: linux + create_revision: 02085feb3f5d8a8156e5e28512b9d99351d510c0 + base_revision: 02085feb3f5d8a8156e5e28512b9d99351d510c0 + - platform: macos + create_revision: 02085feb3f5d8a8156e5e28512b9d99351d510c0 + base_revision: 02085feb3f5d8a8156e5e28512b9d99351d510c0 + - platform: windows + create_revision: 02085feb3f5d8a8156e5e28512b9d99351d510c0 + base_revision: 02085feb3f5d8a8156e5e28512b9d99351d510c0 + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/client/flutter_ui/MIGRATION.md b/client/flutter_ui/MIGRATION.md new file mode 100644 index 000000000..9d9b25e5b --- /dev/null +++ b/client/flutter_ui/MIGRATION.md @@ -0,0 +1,115 @@ +# Flutter UI Migration + +## Current Boundary + +Keep the daemon as-is and replace only the desktop UI process. The Flutter app +should continue to talk to `DaemonService` from `client/proto/daemon.proto`. + +The current UI is not a simple settings window. It owns: + +- tray/menu-bar state and nested menu actions +- gRPC connection management and event subscription +- connect, disconnect, login, and session-expired flows +- profile switching, deregistration, and profile windows +- network route and exit-node selection +- advanced settings +- debug bundle creation and upload status dialogs +- enforced update notifications and progress windows +- OS sleep/wake notification to the daemon +- single-instance signaling and quick-actions windows + +## Phases + +1. Scaffold and generated gRPC client + - Done: generated Dart stubs from `client/proto/daemon.proto`. + - Done: app defaults to a gRPC-backed implementation and keeps + `--fake-daemon` for UI-only work. + - Remaining: replace the development user agent suffix with the release + version at build time. + +2. Core connection parity + - Done: status polling and `SubscribeEvents` refresh hooks. + - Done: `connect()` runs `Login` → optional SSO browser handoff via + `openExternalUrl` → `WaitSSOLogin` → `Up`, with an `awaitingLogin` snapshot + state and a banner that exposes the verification URI and user code. + - Done: `disconnect()` calls `Down`. + - Match current daemon address defaults: + - Windows: `tcp://127.0.0.1:41731` + - Unix-like desktop: `unix:///var/run/netbird.sock` + +3. Settings, profiles, and networks + - Done: `GetConfig`/`SetConfig` for the toggleable settings (auto-connect, + allow SSH, quantum resistance, lazy connections, block inbound, + notifications). Read-only fields (management URL, interface, port, MTU) + still need editable forms. + - Done: profile add/switch/remove/logout via `AddProfile`, + `SwitchProfile`, `RemoveProfile`, `Logout`. + - Done: network list with overlap filtering, per-route + `SelectNetworks`/`DeselectNetworks`, and exit-node single-selection. + +4. Desktop integration + - Done: tray icon and menu via `tray_manager` (status header, profile, + Connect/Disconnect, Show window, Quit) with status-aware icons that fall + back to template variants on macOS. + - Done: window lifecycle via `window_manager` — close hides instead of + exiting; tray "Quit" actually destroys the window. + - Done: native notifications via `local_notifier`, fed by the daemon's + `SubscribeEvents` stream and gated by the `notifications` setting (with + CRITICAL severity always firing). + - Done: browser launch and clipboard via `Process.run` and + `flutter/services` Clipboard. + - Remaining: file/folder reveal for debug bundles, single-instance + signaling, quick-actions invocation, and sleep/wake forwarding through + `NotifyOSLifecycle`. Settings/Networks submenus on the tray are deferred + until the window-side flows are stable. + - Note: `local_notifier` uses macOS's deprecated `NSUserNotificationCenter` + (warns at build time). Plan to swap to `flutter_local_notifications` + before release. + +5. Debug and update flows + - Done: rich debug bundle screen with anonymize, system-info, upload (URL), + and run-with-trace + duration. State machine drives `GetLogLevel` → + `SetLogLevel(TRACE)` → `Down` → `SetSyncResponsePersistence` → `Up` → + progress over duration → `StopCPUProfile` → `DebugBundle`, with restore + of original log level and persistence in a finally. Result dialog covers + uploaded, upload-failed, and local-only outcomes with copy/open actions. + - Done: enforced-update modal triggered by daemon `progress_window=show` + metadata. Polls `GetInstallerResult` with a 15-min timeout, blocks close + for 10 s, then surfaces success (auto-close) or failure (error message). + - Remaining: hook a "Check for updates" / "Install now" button into the + About surface that calls `TriggerUpdate` directly. + +6. Release pipeline + - Update `.github/workflows/release.yml` UI build steps. + - Update `client/netbird.wxs`, `release_files/install.sh`, and + `release_files/ui-post-install.sh` where they assume the Go UI artifact. + - Update updater restart behavior in `client/internal/updater/installer`. + - Preserve public artifact names until installers and updater logic are + intentionally migrated. + +## RPCs Used By The Current UI + +The first production implementation should cover: + +- `Status`, `Up`, `Down` +- `Login`, `WaitSSOLogin`, `Logout` +- `GetConfig`, `SetConfig`, `GetFeatures` +- `SubscribeEvents` +- `ListNetworks`, `SelectNetworks`, `DeselectNetworks` +- `ListProfiles`, `AddProfile`, `SwitchProfile`, `RemoveProfile`, + `GetActiveProfile` +- `DebugBundle`, `GetLogLevel`, `SetLogLevel`, `SetSyncResponsePersistence`, + `StartCPUProfile`, `StopCPUProfile` +- `TriggerUpdate`, `GetInstallerResult` +- `NotifyOSLifecycle` + +## Risk Register + +- Desktop tray support differs sharply across Windows, macOS, and Linux. +- Linux app indicators and desktop-session startup need distro-level testing. +- The updater currently restarts `netbird-ui` by process/app name on Windows and + macOS, so artifact naming changes must be coordinated. +- Dart gRPC over Unix domain sockets must be validated against the daemon's + existing `unix://` address behavior. +- Flutter desktop packaging is separate from Go builds, so release CI needs a + new toolchain and cache strategy. diff --git a/client/flutter_ui/README.md b/client/flutter_ui/README.md new file mode 100644 index 000000000..7a9f3a6fa --- /dev/null +++ b/client/flutter_ui/README.md @@ -0,0 +1,54 @@ +# NetBird Flutter UI + +This is the migration workspace for a Flutter-based replacement for `client/ui`. +The existing Go/Fyne UI remains the production UI until this package reaches +feature and release-pipeline parity. + +## Scope + +The first target is the desktop UI only. The NetBird daemon, service lifecycle, +network engine, and daemon gRPC API stay in Go. + +Initial parity target: + +- tray/menu-bar entry with connection status and connect/disconnect actions +- settings and feature flags backed by `DaemonService.GetConfig` and `SetConfig` +- profile management +- network and exit-node selection +- daemon event subscription and desktop notifications +- login/session-expired flow +- debug bundle flow +- enforced-update progress window +- Windows, macOS, and Linux packaging integration + +## Bootstrap + +Flutter and Dart are not committed into this repository. After installing the +Flutter SDK, run: + +```sh +cd client/flutter_ui +bash tool/bootstrap.sh +bash tool/generate_proto.sh +flutter run -d macos -- --daemon-addr=unix:///var/run/netbird.sock +``` + +Use `-d windows` or `-d linux` on those platforms. The Windows daemon address is +currently `tcp://127.0.0.1:41731`. + +For UI-only development without a daemon, run: + +```sh +flutter run -d macos -- --fake-daemon +``` + +## Layout + +- `lib/main.dart`: app entry point and command-line flag parsing +- `lib/src/app_shell.dart`: first-pass desktop shell +- `lib/src/daemon_client.dart`: daemon boundary with fake and gRPC-backed clients +- `lib/src/models.dart`: UI-facing models independent from generated protobufs +- `lib/src/generated/`: generated Dart protobuf and gRPC files +- `tool/bootstrap.sh`: creates Flutter desktop platform folders once Flutter is installed +- `tool/generate_proto.sh`: generates Dart gRPC bindings from `client/proto/daemon.proto` +- `MIGRATION.md`: parity plan and release integration checklist diff --git a/client/flutter_ui/analysis_options.yaml b/client/flutter_ui/analysis_options.yaml new file mode 100644 index 000000000..a8d28bb5d --- /dev/null +++ b/client/flutter_ui/analysis_options.yaml @@ -0,0 +1,10 @@ +include: package:lints/recommended.yaml + +analyzer: + exclude: + - lib/src/generated/** + +linter: + rules: + avoid_print: true + diff --git a/client/flutter_ui/assets/tray/connected-macos.png b/client/flutter_ui/assets/tray/connected-macos.png new file mode 100644 index 0000000000000000000000000000000000000000..ead210250d7a4b25461aa0311fcb6c13cec75057 GIT binary patch literal 3858 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 literal 0 HcmV?d00001 diff --git a/client/flutter_ui/assets/tray/connected.png b/client/flutter_ui/assets/tray/connected.png new file mode 100644 index 0000000000000000000000000000000000000000..4258a5c1c42a47842c09fb65c1b93e1df74584ed GIT binary patch literal 5287 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 literal 0 HcmV?d00001 diff --git a/client/flutter_ui/assets/tray/disconnected-macos.png b/client/flutter_ui/assets/tray/disconnected-macos.png new file mode 100644 index 0000000000000000000000000000000000000000..36b9a488f16673b1fcb1c87037d3d1606dfb1e5b GIT binary patch literal 3491 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 VFbHp#EYMSdj14UGKVEZ=`9J&Jr*QxP literal 0 HcmV?d00001 diff --git a/client/flutter_ui/assets/tray/disconnected.png b/client/flutter_ui/assets/tray/disconnected.png new file mode 100644 index 0000000000000000000000000000000000000000..a92e9ed4cd17d7998a819f1b80f7551b7004fd6e GIT binary patch literal 4800 zcmb7Ii93|t`+sH(W63_YRD>pLwiih;wi0ERykTUrW(ir!GKPxRn(UM{$?_V@n=K5* zj4dfNL$+RwEM*_Yn3>;ruiroLeXi@d&U5bToco;fxj*;kKG*Y?wdFNl?vvaA0PtQn zGqD8#5bF~JaB{F3=is-VtcL4>nNtV=@CYBjAfVu-`0mGRtMr`c+(I7 z8q#@=?y>`bki&HoL;DEOuNh>(DPlHZ%WmT4&_9p_bN7gsL3nNsO>9-I+oDLXYtN`s z;D#zkk}m2thsEX*;~VFtZN z2jaXl4++07?SIpCzzH4i_%H`#(o2Zg2}gld>hlEso)z$zQ_3MTw8w3RW1 zhV-12~?tK6#z4J9sIRDuXqLWA%)(UIzXu^ z7A|26o5&q=l!&mGpgA}w3EO~Ke>$&+GTdYLa!rlxw(^vzel%y7ClQG zh4k7E=ODv#Hi9-2uH&@7SEkad%dg_LTA02FMn<5yGw}y zT_)3GK|y&xHz;z?K6HoDGknx2dQ=O^$1&ydX?(loQ1u5|q_6Np!ma#)V%LF1hLV&e z{NKqR@96yOUq*R`Y0Fs4--ALU$^fCJ{l!qi_pmX}GKul>@>g*Ts#Ux0BlOUTFpFi#mdxE|NO+6geL!Y+e)7gA~MUsax&)OdUk75I1H=Kb_er zv)lXV1s8bi^<0TsyEfC4nV!5iJw2J=otLNDxi|M*RHHdM$QCL)@cuB~pa{8rw86Q7 z;Z)IO9pHO^Q0xNRB}&jGMUJ80CrF0`ugQkFzvh;IvSlvkWCy3q2j=QfrhDND&v(LEMwsq8aUPv{4va3Do++FV4|FN>L?@CC3!Tu0|Vv97n_wxF$ z!e~)lb&lzYKygz|c@^?tuWeoWtzGXRPe;Ups=hxV=6nopjB(yn`X-?>F2h;p>HNz1 zKI4<Qef*G}f8vlAiL zZD{#f#cPhuu!0QUOTaNBmrE8%FxgR9>~LS<>O*{CtZPy3!!(EzgGq=W!lz znbCwCx#r8po#kW_*XxgUj5}Vqb?SchjG(l1{*B#Lrsj&_-)3q}!lOKR6~o=ZYdiO2 zs=}dTDxH!CX)_4+v~$+3760iH&SzksKRMC)1v{zxlm9JN9_*TTvE2rDr4?V*9cf2JoQ60_!{^L8 zCzvooCHp#u^ZSYA)j;LFq?jg~+D?teectC10vOX&9Nb&z($_H(*0*XI>^z<4w`@0) z*YC#(2Um9e4p{QknZJre;e^p?|8z$${;<<~lTZBEQ=OZ3#M>zu@oEM^Z10*y7u~Yr z_;V)D&qH<5B@FyS5x4GBae*Js{s(8IT5$N5%i6Vg8^{NT$aP|z?m2mb<*X8=ig*^N zmPNeYNwGy5omM%Bi!7bHuLG@^8Vj7pdB8Bu!(OXPD5PeLeCcxwt9yUUubPEd|Q6=YV=CD zh<4?fKcIzMp~DYdffJdx%mp_;`t^J|*U>dep3m*<=zM`9#H1C2LtnQz_QODpkm-<# zgBoN1=-x3e}w;Q4mxec{4%*fLkw8$7gjAg5GC)8<76wuzyvbg|lVY z?iEd~ClNRFF)~BRRa-h%VU}2>vf2%Ojq3Mcg3+^@s2+JB;)1f}w?TYKB>^NeE336BMp}{hsuX7(~vH>N!Nu zdZ(F4HNkW^SFD}4gi+)P;`CW}6d4~7t1{YYOQCM}P}pqWKfPGrfOL2;=WhquMOL>Y zoW1%fs}JVLlxUW!FSN|q5!{(Dsh?Y!Nly;V9`MIx50bDsA{k%Ma%v|}JYcz7Z^^SS z&8^U&)bv480tn0v2gP9)r%LWCR~bRq_ZVEM^i?%SU3^qkz0c7r+$Ao?^{Jk~#(ts1 z{m0DasD#31p$7|rw_sjQ#uva8aDJ~O+RNs>(2`61F~W&&K56vIxJjbt_-M0_Xnr5_ zUi98r2wbJC==+;YcxjosnPFr~2~oN>_z8hOP&hx7(5Fykn+vMOiK3F@q(H$P`R(wm zdkfv=y)rBiO?7>=s*I|Y}zGqjaQhmIJwWT#od{n zDwk7WU)IOUp`CubYa09hlTuDebkmF0eU0p6{|ocQO8>Yb5?TC^3vKiX1237K`H3Dc zFnQL1j3y5lk-3a#J%W)~#+Oir*SYL2w=i%6M-mAdStc6!=pmqY?g}ND5iqg%?`_l# z5p!*FjVj3bwD=kct2l7kvrrM%(@A=!IF?3TO(w#AbhGd?(|&%X0Fe>+WCATwLHt?o zO^9(AP`zShpiuX7YyKveKq@Y*apGeow=Ugy;S9~;9Mepc?jC(|)xS4BiMopEbe`JV zlA^M7N#OH6ZgmU9uM?`|8vYA~nC309`LXCJalG-QT!)M`{#3Y#z+UfYuX#5NdYE7h@?4zF4*V4=~j!X=K(an=Qk;|`DpHgy)oybbxy zMkM-lU$mg53QNzJ zv$(5u0Cw9wEpIfOE9vqZ?EbjjN>bTE^Dt4g35B}`1H>-9*O6{mqc7iusx5e*AN9xq zPzK@c?K;x$SjJMo{$ajiFX?mVx2m4}8@4R)YyitI4%N>O<203tQL1&2_PV!L08IVdMCNQsWM_wwpl+x_5y$YbWok zy>38?u$N#=O}kS{#A#IGYifb}f2%zsS8!*i&_7sfx2n3uvO)oiJ@+z4(PY@s&G!$m zT`JW#4qPvnsrVY*eqSF>R=Uh%#U_+?Y#seDYp-9Aks)^!PZ%ikoWv*)qO^J%C%*1T znl|j`9)Z}U)gJpu(w8M1A-oamj(vP36=D_6lJxg6<$rS;X;cb|_i4(WE(QMCTwHK> zVeS^`9w>l8mzG8ldX)E<+EnZ10hLASa5e^pnSVQGImDq)sVM`LeZres!(?>Lq>iX} zk~Vzh6)OSbzgQb;SrzhocpJV}8GS*oQVv}xBk*KdQ>qX@m&H1J;Mln=RGYS{&ZsCx zN~=|Zz0>+LbApXU0zcGOr|~=iH00G95H1h4H5m#!F@l z>;3yp#68RTn_*!6d>c3I7vb!cWxyY9_?X96R11zy+CdtntRYc0bL9Bs|Iq2SK;huH z-!vFVb=Te#{r=v%4wSv*jU6F|*BUZCG&1liIsEo9S;ko!CL{S($h7;_@bs^J)Gel| zJfKBtKwk3`jBpuk5!^o{_N4e?&g&$}s4ih1)<(S)mim^t-Z9m_`5l@<_jQBTBkESu z=_l!3fjQ(;BGCs$?rTV4b~nDr7G#1Icb$e+V+H3!CCQ;zJh(Ff{a$vkSj{~ATq6oM zwf&Lc6au}gGfcw1-XcQS=T9i+B6r&krH0y4TQ!##MNv3Ud7x6Q1{aX-D(KiRTF*f$N6Ha>Wv-)s?u^Z?Xi z!y3}K8SmeFzN7COjwc>@tAmA%nw9h|WP@DXDMC}&)YOM4?Du!SPnZRVYNG-Dll`Br!p5klpe3|N3z^XF7hE#mx^9XOIcTsO8U`h zYOUbW@ZsDLHZzg0%Z%Qry?fT|2!Ggp^;EjAg|0(?Z`Zs0Gv>GGB z8s)3TUQ$y@gQzsfAch^89CknlE9W2BLxdtchEnpdUA*omTAQ3YDw(C7m*-{eeO1R~ zKMbdFqfA&L7Ec2G{Cn}HMBY!kr-{^H87lbsGzp8j{a^3=3V42TMIV!V!J$8eP7$ZI zy?6-XR3{HX?I2}ssS&1inv{_9lW;c;A}w5g_gGY>EyAEB{EQwghA5Z5^Qi#>Ix?>Y)F}5aFf*2q7w9m5!_`m1vRi#|cd8@AgtIg&YnZR(6z`g6v1Pt} zY0Ks5t4D!;^k|DRAg`f#b`Tb~q&p%cO;$Q_9R}cIP6s)#Ldbn}mp!%tNpOZ?UgTk| zOf^B?p<-hE}-Mn->Nc7p~s21 zfUF;Vu-fOE{(9`2U8x!_O{681UN7NPN8U~Lg?5uvPo#!{W!<}sL_hJdc(j?79%3{1 zivGyG>w_4}f=5R9mGr-~KYQFa1w}MFjUMofJ5?F=M)jR#)u@wb54arDn*LH zLs1|>jG!O{jyW_13{53R5}HX!OuoRncisEr{=46-^{(0FnZ5VCd(WOVsEh6{l0Zcu z0059Y=j!MM00{6&0l)(=h{+Z=SlPe!-)CE=`zC@*jH zm&veng7cgBOA0bB2RR+vN7UWZ9pA+JgVd#z$12hSFWW~rY<~L9TI_MHo_4#J7aI-# zS&ov!^j>zJzmJyu(a!CF=Ea6sQ!fyK!*jYCZOH7(jkJ2A;JmumC?}PdKbJH&gStcg z?SwI_nq*gxa@C(o5P|P2VUAC#k$wWxiBLyH#XPy9-csECIH2w%W}eO#TVH5pY}+(F z5mB9VwakXh8*VNVUM)OEWJu`1G*zruFEM|gO;{d;2U-cadcff+KD>AO71Rw{##gFj zY05mQaQiPFk9F?%<_8)?g~vL)<-h8-Vnk@sV=NA5{H{E~i23n33&K@(NZnw^V>xiv z^pM-V@MgD5T^x=D!T65bb{M|KgTh$$`0_%u^_EBxb4S1B%G$^r^;17fvW%aLPHh6O zB*WlFxL7=%PM_h$w3=krAp(9RbIiBezC2anEUzBunwO{4YNf7ct`#dja^`W8^TLtMJnH9c8R}Q(R+M2dJ35(5 z(_S?SQ{l~+$c}O1ZalfI+-|tse=Gf4LjF#E8C5zoqe2Ol^g`pIr*i-^1+;zUi9m8= z4Yj+x*iY2b3p!NpV;%RCAtKR5?J=}4kfrvyG+lEYAF`H|aq%XU@TD z9;LrMyHY3t+Lk|P7Hrkps-zvJm-X#DI&|N_{f4v-#p?G4)P#&#GZ0M8a^e8GScfgQ zrm>xmR;pttP8-a+eeD=RTUew&<1h=ziCGJa+g-ra!LrG48_baDNe0hT&ev7+nF zgFEA>Y)s$G5ZcHS(S+KNWzU`|A3a7Eo**L)1AYMOYu=W2!H zYlA^kpM6KP%^!|Ii8SvTiQB8;8Nub|;1Cantm_SThHOf&^N?#SBlg54_ygK9_>By! zQwVpc#rxX%-dbzB2L=R_Qb&K(ly*Tr=MNc}0Iby0IcqgM=rsidb%NXU6}8Ia4&fsG z&X-qxC@UR(zQqt$p9|U2Uh>w!9eU|pvIFn6+s3st8$q2o*ZuA1jAdbVZWE4X3Yh#` zS2Lb92^lMNc5ctM7oWWw&?XB_f5P>PZ_t1`F{4k{zU1ll&RW2qPRk&#MUUYi?n-&Y2HVS7Q9wfxK4raEMrU|^by`;_#2rtb$2d`ZpdE}fc}%LXk+L>sRB zRdPJ-fu~3Oes@<-)Nf^-gz82x}Bg2o-h zO;x_^yawJhV?`4*Gy8q%v%nJ$dKu;$fLQeT% ztQPlp%36BwS0#}s*n7+%NJ9v9I8S@%!&t<}G)Z35R!Nq|!kiCS^%H3juK6t>uptfX zj7em4bRl~7^6~Tde$n*iR^$88lfs6}7x>GpvUv;n*zJ;B*{hgL&w*s}QCK|R_7_uz z7ozu^X;J-WVXdJCv(ezUHWd)rR6oeH>&S2(2r8d6Fqy{RKx{X@4W|hHDmvuKv}8y9 z0%gMR3TM^3!z`OiwLUXN88bl!IKx9Kcd~|0xc@0W6m^iR_t=xUysz}$ zx|ag<*gE(M{0Z7P8LqRZoj%FmKyZ!nL zmuq4}Byu3f&|ZgcAM3DUpWvt~VJ5!K!#=)$)Z}aU&Kwk6aAIiJ5i33I7gpjv~hiyN_e#E~$Y9QQ8 zf~5S;RR{9$yWW>kj=hC|G;u^W-v{EBT}?XZy9uXqPbG=E4z6O*(oHR!Mw=OP3hf}<3;3>d?QYfDlG{OsvI8n#mK`gLD z2=3&of^QeYQIpV$QNaX> z0f$UQ=K~P{5aA@h2e&HVZyV9^Z{D1hgV*8ff}}w-h@Br57az)$8lw+PiAIHcGarBW zQ!>mRT;&ate^lU2N$#K0%HwzD8F0uoYaa*G62F@cg{*m&?Jd4AU{~nuV0s3Z{$}M2 zEyftBSt=7n7XEcPH}(_`PJ!1*nF!=S6uWAL8 z+fqs^BH|!p8cFE^^r=lI2rtjIucHt9T6@KX7LpB4rTmkR$?VsEer$+mP^giVFRo%y zt5roG4g)0}+5!C!-z}STIK8Ui(|Qor7Ls5sCHB?n_nRs2D21Mw!zK#eqQ;Km&>X= zD(TnJJX~-xxqHF^=t`V+4cx7>R;?G|<$g*H(A@%z5wwUT&e%4ak`L%`#wRZL1f(J_ zv??_YBp-+~AQ|o4}JSZQy(r7xf_64s2uWG15gDxQARIxP*;BMS?b<+Xc0 zG({5e62t%@6C_~82#OxTbr`b$B`Aa|=*8Gdm-|)J4)WpDvgcyLp~RVkR;Ea#-(Ub( zHIK+8aXp?-K#3-jMDu|dL8LOOT_zQ_yYlLYVo{AO&eZn9jtoyE?8v7>CaUi)5Cb@W znNTKeo5H8tM3y4wL9lVy-+4BCJcX}6^MM#ZS1cLNu_}hywuBJ_zAKh^G8q?z+RocY z@$&l#b&5srtU<5@H(zH8Brum3bx&xcC7b5d6r_-YxH|m+huOqQy|2(p*AE#P(&4~{ zgXLeE9icuIS#rvylP3RJh)&Sj1!I(cU$B z@8T4Or=7#E1PJ~0a}d7AQ~hgkL4iV#E9kwpCc3rsR=vekpM)!#F;$nu=EX17?iq@U zA|F|7HW{mC-S;Kk^?JQ095Ucv&@kB7^8~d@Rt$mVjD>uE%YVZlm>60Q#htk=I#fX0 zVkY+2eOe^hsCi8*!%0yNwJJhu%9DNP=hfRr&oI4rKJvc&SU2d|=rL{6$R)hQju-HI zywjDOzGxEvnovJw9}+vbOH}0cO;zryOvR9tJG%rXw~xN30^5f$p<7mn;zqU89HX5| wf@_Jie1bfXaAWj)+NRQfZqEC^M-yEiQ-;c+gI$1yM0yCA{DG6I%m_o_2E@!PD3L*xpt zauv9-N0b+QKV|>L?(l!~{*o1pkuO)bW2a4v2&MErI{1kvPSgRhjIXA^FGq74NxcTr~p%M$(A zKNg1KYjk_Ux$i0_5hx&gB7>OQ9PdE0ZnC2+yiu?lH81JQj{ei;4D6_kx631O{e1^| zjVQT#^QmxE`b2d7snSGRU9uobvuFA3yqNj-w8(4K&l~77QV}>>30lkYrs`#<{Z4X@ zE^(cKzMMh0w#O@+9U!G?nIpcDKA&v!CJwCv~}du%AuUzLbg;tw?gVWa^@K zz0{%28Dnw0o)eVP%%mP-BN;#sEqu%wwf?5Uoo{HzI&4BlOs-2TqxR3e@3TzzcT-RE z;lOYvnxd?K&Ie`E(8%0kaRjyqDB>|?o@%d=Mokq@n2gR&=xH4x*aoK871~8} ztfKs6J+P+D@f{5tKC{dS&5O*t$|v-NXU+B8@|WjqXvu98zbRRRBzwhT@rN{xJsPam zyld_5wraa-6!3p%KAnZazxl1tm{Sr!xXL9d( z45_@)<9EiEqFsL`4!@d>3Ez3_mALh3c*tsV-4f}1#+RiS*mzU}2+fmjtNXO2UG?ZvwOdCqn9=^bfa%U^cIJzjCvyC{yuSrP5 z^mDE4t3SS1>|4Das|=IN?;n~MuU_7RkHo0@!T-yOEylI~nd#h3Yx=@C8(f`ED_19P z(|Fo4YgNrZNKdTI!`8d7tiXt8<+ioIal)H_jvX@)A+n?$A|VZqeRzB+*gU6gbSH8B zs~w?i{=6MwVfFzwsKWuJ3g+F{NEpprS0tQ7O1X()#&xPqZ@szcVG0vi|r7d7y zeB^%EVz+y}r0Z>f73mgC-Z)Zp5m!*Br)47SjW|mnE&tagyYksm*W3!+bYUm6rDf`X zMPFWRk@$nyrU~xvw4IXF)%#+7#+Ug$e<(u{tN?GRs7PVT>VDtnJNpXn{Kh2jKUN9; zFw{(XJ>#@@#7?QzGsfhStD#BRVvhPy^^U2qk4Idl~l7hA}g5FOaUw)awNoNP$ zyc_&z38bGpYLHLg(F#s^oy%gEWailB3w#Q(Wf?sWfuS^5sOr67eR|n8oLcU z9K6f__SwI)LFLXg|KahlNve$18PJ7guc@7CC8;_;902Vs`%iKslMwXD{*V=+j$J1% zmsS<%xzjLxeyL+tMXr#ZlzN9t3g-dhXJ*c z2ET+bDilifu4~KxI7{)!(>w0?AP|$jDiOnRk25}hI3<< zuNItU*L_@)T0iL$=WumJek`S$Hap;&h2YJ2A!F`**nm}dJzhH#E7whE^JUBj0dNLgL1?eOGIn3MnnmwE0=bP zmbiT6VwJ6tUiuB0E6&;rK2FZOWU5ZOr=J74Sln=@zGUIB_k5tIs>$Y84TJ&~^?XCX z=~kVWS1tc+Pz;TH>2%rPFu(L++{3~O`A%CmdP?bkyv9aXdY|JfRWpN-4*SY|U$(K+ zw?z+g$)6+s5$vOYoYg24GNqpUV?nHPs1y)+-&LieKfjnAJjqM8MciC1T=8#<^t%Do zV$akD9li9S?f-n;%dXC0E&HRacOBcMyyDON(z+aW==O0`Pq-Q6nCEcA;N$I?G}p2C zn!4Y9%AHS(>lKt@dx&z9ix2hWh3aTBw;cEMu zlG76ItX5S%GUa`m7(PE&nzqcy9$9^0!!$)P6tMs~r?K$)jM zW!CoCUcR>TX5h>|W z*!$v3tmQorSO)7h`RFvp6mi3~E8vtok@^LLjO8_+Kmj&d`fG_1K>-fym11*g)Sr4lFN5$!aFqdOP;`7?=l0@HRQ3m}ccpZqL{ARskewlYn*f`# z0lm}>N)zq0#V*1@23J}q{Q`uCei81vZ2@U<_p+G`&Cdvd*(@^d-h%s5a3@&&M}00a z)kn=r;>w7Z1h1D=txJX@AVZtsyuT%en3bzE?+i+B4Tw@C7NtnD5|UDP=dI+I0G{%a zs>Z2O_eU#_R7DDi@_RWLbkeZt7uK?1$=+tO`dAiw+qpw_ zM|JOGd(UDqQpDN{d*A=nd+S2(3-~(51|MfY<#0k3xvlNv#>*M3tRv3Ax+ms7&PN9c z!8~j^MV!ynKZI)5Mg(2f^}6_AeB3F5SA1jc_pvK3xOe=2V4sl?c;u#OH-o!cb`(W! z5<3GHU$peMo%-MKd%C~}AYnAU0TXoXhp`Zfz9}Drjupmk!%KN2=Ga)q6ZZ;#|H7!m z&Qi?;)p6#d#}>2f*cNB^PxJ4?!&!G`COuBdUU61ic(_k+0}2D6|H+!c*Q;T*EsI&@%i30m7@F zx&O+1q-^=wY{Okq=6pWx9fRxQ1}|yRMwF+=8d zWm&ub{+_(3g+M?~vU16P+tuTct)QXP;^_0d-fvF}>B4G1xSS+M(FgIm0g5;5-0;Ww zk2z%O1coebO+w*#rh|#7>{E~h@E6UqDt{8N5k(+Uw6s(R29HAim9V!9rNeK4v#*#< zt1h1M^BM_vzy~t4#4*-0yG?bM$X!hHz1!dSDm>}7jWd789D3fc%-n?fPUD1)^7Y!B z>=XJ`Z)_2HnGZ^GC3Q~ec-UuFk@)C$!}P=%?6=J@jZc4mX1L2dNQ9I3};~hzpVTQQ5oycO%X#ZP=6}?1&-w7SCX}6yjQa zjM9fPDO+L2tXlpI>%WOW2`nEsSfZP*ltGz5vfu$@hAG=eeJMmW%Y#Z;QWN&;WjztZ zOY$tZZbhEW24Ybb;lNc_wEws(`XMW<5@3fzJ%!~l*g@I>oxZ303vm&Qk9g=jup0ngmq-|7#a*b{+yQ*G7A(MG@S6iFyOYfLm>&g?o1|*?cZj8* z6xiRD+OMjf*`S~$G9H#E6^ol>u<=s+;RkZeyy0=qa>Sw&(&*G-YV&|(wXg=fmeC<6H9R5-7zgLC5QwYqKD-8Nq>9 zh-2-{aV<|BfTRw=_Kup=jwsIkkkR(EP}6^jM>IJ&K-JceWPE@0#?9G=`f4eeLORd{ zVsmU^jxDn)be(j{g#ar$87%pvBr=``>ABc{{e%g3yS?ugm^M}G^06*)#ib|O9W89CsTm>k6{c@f!f2`f0lUxz1BuCGM@_PWN3 zanfkf3|ex20nYnh+~vgOjlD8y{IsTopX)Pd8&DdVhkSs; z{B?8&)}FWQ60C##SDFN+kgWi_pSQuzb8U{lHt>9?!VFwxVSM0+FhC%`@!>(cI@Jt< zf`JSA3JBrVk)rR;&hY6?K#@2C$IG!ei^7kCj!>%$(&Qa1WPJR9?yD;i@(gMhzK}E` z&-zt!@2%U2-pvgRswZ=81#NYh--gT})N~lZ3K8g^W(2pbf-f^W5tTL|eMPbkEx14M zW`guwp8jJab39C0P7>s0b;5hTyx-Ok=A#Vh-A-a{@V)cRNZcV6;0v!Z1fa$wowdQz z=J~O|Z+~w$f>|KwcepX(r7T%USfzK)!vaz10$4NCWHPWr4W<7*xCwe=NGfg8&=muO zNZ<|?97Q3S;Ohpa0+?2(+cM+&&`iGrPQOW&hvtu#r`;Z+kO8ouVJe)V{Ulc-p(_yK zm>ju-<15eLcHRb|yNtuG(5Pf>|(`cPRS?(U_q>fdNFvJExxT7a>QB4$RJemgrxh`@UTQitB$D!gHq~jpNATzk9m=NmlFwzdaRj{vj z4OPS0DTk4!RjiRfxkW0N4z(?7WC1i)^`Oa`qO#^W=>Fwv!bVU%gZXKVGy5)EX5zef z$wwi!1onJ7fDBh4dc1-N7FXemfcHYYv8IIMUx3brlyt8tX_rG}+=O`O`I>m?9y=t| z!=NB)0nR_wmkVA`^cYza=dz{kAopF?JW+MDkn@BXcxg`dj2(}%9XW90FJJ2azLLYW Z(%>Cos#cWtK%X^)%YJvqTKk}k{{iS8*lPd) literal 0 HcmV?d00001 diff --git a/client/flutter_ui/lib/main.dart b/client/flutter_ui/lib/main.dart new file mode 100644 index 000000000..f35017165 --- /dev/null +++ b/client/flutter_ui/lib/main.dart @@ -0,0 +1,53 @@ +import 'dart:io'; + +import 'package:flutter/material.dart'; +import 'package:window_manager/window_manager.dart'; + +import 'src/app_shell.dart'; +import 'src/daemon_client.dart'; +import 'src/desktop_integration.dart'; + +Future main(List args) async { + WidgetsFlutterBinding.ensureInitialized(); + + final daemonAddr = _readFlag(args, 'daemon-addr') ?? _defaultDaemonAddr(); + final fakeDaemon = args.contains('--fake-daemon'); + + await windowManager.ensureInitialized(); + const windowOptions = WindowOptions( + size: Size(900, 640), + minimumSize: Size(720, 520), + center: true, + title: 'NetBird', + ); + await windowManager.waitUntilReadyToShow(windowOptions, () async { + await windowManager.show(); + await windowManager.focus(); + }); + + final client = fakeDaemon + ? FakeDaemonClient(daemonAddr: daemonAddr) + : GrpcDaemonClient(daemonAddr: daemonAddr); + + final integration = DesktopIntegration(client: client); + await integration.initialize(); + + runApp(NetBirdFlutterApp(client: client, integration: integration)); +} + +String? _readFlag(List args, String name) { + final prefix = '--$name='; + for (final arg in args) { + if (arg.startsWith(prefix)) { + return arg.substring(prefix.length); + } + } + return null; +} + +String _defaultDaemonAddr() { + if (Platform.isWindows) { + return 'tcp://127.0.0.1:41731'; + } + return 'unix:///var/run/netbird.sock'; +} diff --git a/client/flutter_ui/lib/src/app_shell.dart b/client/flutter_ui/lib/src/app_shell.dart new file mode 100644 index 000000000..3c099125e --- /dev/null +++ b/client/flutter_ui/lib/src/app_shell.dart @@ -0,0 +1,889 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; + +import 'daemon_client.dart'; +import 'debug_screen.dart'; +import 'desktop_integration.dart'; +import 'models.dart'; +import 'platform.dart'; +import 'update_progress.dart'; + +class NetBirdFlutterApp extends StatelessWidget { + const NetBirdFlutterApp({required this.client, this.integration, super.key}); + + final DaemonClient client; + final DesktopIntegration? integration; + + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'NetBird', + debugShowCheckedModeBanner: false, + theme: ThemeData( + useMaterial3: true, + colorSchemeSeed: const Color(0xFF008C95), + brightness: Brightness.light, + ), + darkTheme: ThemeData( + useMaterial3: true, + colorSchemeSeed: const Color(0xFF008C95), + brightness: Brightness.dark, + ), + home: AppShell(client: client, integration: integration), + ); + } +} + +class AppShell extends StatefulWidget { + const AppShell({required this.client, this.integration, super.key}); + + final DaemonClient client; + final DesktopIntegration? integration; + + @override + State createState() => _AppShellState(); +} + +class _AppShellState extends State { + late ClientSnapshot _snapshot; + StreamSubscription? _subscription; + StreamSubscription? _updateSubscription; + StreamSubscription? _tabSubscription; + int _selectedIndex = 0; + bool _busy = false; + bool _updateDialogOpen = false; + + @override + void initState() { + super.initState(); + _snapshot = ClientSnapshot.initial(widget.client.daemonAddr); + _subscription = widget.client.watchSnapshot().listen((snapshot) { + if (!mounted) { + return; + } + setState(() => _snapshot = snapshot); + }); + _updateSubscription = widget.client.watchUpdateRequests().listen( + _showUpdateDialog, + ); + _tabSubscription = widget.integration?.tabRequests.listen((index) { + if (!mounted) { + return; + } + setState(() => _selectedIndex = index); + }); + } + + @override + void dispose() { + _subscription?.cancel(); + _updateSubscription?.cancel(); + _tabSubscription?.cancel(); + widget.client.dispose(); + super.dispose(); + } + + Future _showUpdateDialog(UpdateProgressEvent event) async { + if (!mounted || _updateDialogOpen) { + return; + } + _updateDialogOpen = true; + try { + await showUpdateProgressDialog( + context: context, + client: widget.client, + event: event, + ); + } finally { + if (mounted) { + _updateDialogOpen = false; + } + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + body: Row( + children: [ + NavigationRail( + selectedIndex: _selectedIndex, + onDestinationSelected: (index) { + setState(() => _selectedIndex = index); + }, + labelType: NavigationRailLabelType.all, + leading: Padding( + padding: const EdgeInsets.symmetric(vertical: 16), + child: _StatusGlyph(status: _snapshot.status), + ), + destinations: const [ + NavigationRailDestination( + icon: Icon(Icons.hub_outlined), + selectedIcon: Icon(Icons.hub), + label: Text('Status'), + ), + NavigationRailDestination( + icon: Icon(Icons.route_outlined), + selectedIcon: Icon(Icons.route), + label: Text('Networks'), + ), + NavigationRailDestination( + icon: Icon(Icons.account_circle_outlined), + selectedIcon: Icon(Icons.account_circle), + label: Text('Profiles'), + ), + NavigationRailDestination( + icon: Icon(Icons.tune_outlined), + selectedIcon: Icon(Icons.tune), + label: Text('Settings'), + ), + NavigationRailDestination( + icon: Icon(Icons.bug_report_outlined), + selectedIcon: Icon(Icons.bug_report), + label: Text('Debug'), + ), + ], + ), + const VerticalDivider(width: 1), + Expanded(child: SafeArea(child: _buildPage(context))), + ], + ), + ); + } + + Widget _buildPage(BuildContext context) { + return switch (_selectedIndex) { + 0 => _StatusPane( + snapshot: _snapshot, + busy: _busy, + onConnect: () => _run(widget.client.connect), + onDisconnect: () => _run(widget.client.disconnect), + ), + 1 => _NetworksPane(snapshot: _snapshot, client: widget.client), + 2 => _ProfilesPane(snapshot: _snapshot, client: widget.client), + 3 => _SettingsPane(snapshot: _snapshot, client: widget.client), + _ => DebugScreen(client: widget.client), + }; + } + + Future _run(Future Function() action) async { + if (_busy) { + return; + } + setState(() => _busy = true); + try { + await action(); + } finally { + if (mounted) { + setState(() => _busy = false); + } + } + } +} + +class _Page extends StatelessWidget { + const _Page({required this.title, required this.child, this.actions}); + + final String title; + final Widget child; + final List? actions; + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.all(24), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Expanded( + child: Text( + title, + style: Theme.of(context).textTheme.headlineSmall, + ), + ), + if (actions != null) ...actions!, + ], + ), + const SizedBox(height: 20), + Expanded(child: child), + ], + ), + ); + } +} + +class _StatusPane extends StatelessWidget { + const _StatusPane({ + required this.snapshot, + required this.busy, + required this.onConnect, + required this.onDisconnect, + }); + + final ClientSnapshot snapshot; + final bool busy; + final VoidCallback onConnect; + final VoidCallback onDisconnect; + + @override + Widget build(BuildContext context) { + final connected = snapshot.status == ConnectionStatus.connected; + final connecting = + snapshot.status == ConnectionStatus.connecting || + snapshot.status == ConnectionStatus.awaitingLogin; + + return _Page( + title: 'Status', + child: ListView( + children: [ + _InfoRow(label: 'Connection', value: snapshot.status.label), + _InfoRow(label: 'Daemon', value: snapshot.daemonAddr), + _InfoRow(label: 'Daemon version', value: snapshot.daemonVersion), + if (snapshot.pendingLogin != null) ...[ + const SizedBox(height: 16), + _LoginBanner(pending: snapshot.pendingLogin!), + ], + if (snapshot.errorMessage != null) ...[ + const SizedBox(height: 16), + _ErrorBanner(message: snapshot.errorMessage!), + ], + const SizedBox(height: 24), + Wrap( + spacing: 12, + runSpacing: 12, + children: [ + FilledButton.icon( + onPressed: busy || connected || connecting ? null : onConnect, + icon: const Icon(Icons.power_settings_new), + label: const Text('Connect'), + ), + OutlinedButton.icon( + onPressed: busy || !connected ? null : onDisconnect, + icon: const Icon(Icons.power_off), + label: const Text('Disconnect'), + ), + ], + ), + const SizedBox(height: 32), + _SectionLabel('Active profile'), + _ProfileTile(profile: snapshot.activeProfile), + ], + ), + ); + } +} + +class _NetworksPane extends StatefulWidget { + const _NetworksPane({required this.snapshot, required this.client}); + + final ClientSnapshot snapshot; + final DaemonClient client; + + @override + State<_NetworksPane> createState() => _NetworksPaneState(); +} + +class _NetworksPaneState extends State<_NetworksPane> { + NetworkFilter _filter = NetworkFilter.all; + final Set _busyRoutes = {}; + + @override + Widget build(BuildContext context) { + final networks = widget.snapshot.networks + .where(_filter.matches) + .toList(); + + return _Page( + title: 'Networks', + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SegmentedButton( + segments: const [ + ButtonSegment( + value: NetworkFilter.all, + icon: Icon(Icons.all_inclusive), + label: Text('All'), + ), + ButtonSegment( + value: NetworkFilter.overlapping, + icon: Icon(Icons.compare_arrows), + label: Text('Overlapping'), + ), + ButtonSegment( + value: NetworkFilter.exitNode, + icon: Icon(Icons.public), + label: Text('Exit nodes'), + ), + ], + selected: {_filter}, + onSelectionChanged: (selected) { + setState(() => _filter = selected.single); + }, + ), + const SizedBox(height: 16), + if (networks.isEmpty) + const Padding( + padding: EdgeInsets.symmetric(vertical: 24), + child: Text('No networks to show.'), + ) + else + Expanded( + child: ListView.separated( + itemCount: networks.length, + separatorBuilder: (_, _) => const Divider(height: 1), + itemBuilder: (context, index) { + final route = networks[index]; + final exitNodeMode = _filter == NetworkFilter.exitNode; + return _NetworkTile( + route: route, + exitNodeMode: exitNodeMode, + busy: _busyRoutes.contains(route.id), + onChanged: (selected) => + _toggle(route, selected, exitNodeMode), + ); + }, + ), + ), + ], + ), + ); + } + + Future _toggle( + NetworkRoute route, + bool selected, + bool exitNodeMode, + ) async { + if (_busyRoutes.contains(route.id)) { + return; + } + setState(() => _busyRoutes.add(route.id)); + try { + if (exitNodeMode) { + await widget.client.setExitNode(selected ? route.id : null); + } else { + await widget.client.setNetworkSelection(route.id, selected); + } + } finally { + if (mounted) { + setState(() => _busyRoutes.remove(route.id)); + } + } + } +} + +class _ProfilesPane extends StatefulWidget { + const _ProfilesPane({required this.snapshot, required this.client}); + + final ClientSnapshot snapshot; + final DaemonClient client; + + @override + State<_ProfilesPane> createState() => _ProfilesPaneState(); +} + +class _ProfilesPaneState extends State<_ProfilesPane> { + bool _busy = false; + + @override + Widget build(BuildContext context) { + return _Page( + title: 'Profiles', + actions: [ + FilledButton.tonalIcon( + onPressed: _busy ? null : _showAddDialog, + icon: const Icon(Icons.add), + label: const Text('Add profile'), + ), + ], + child: ListView.separated( + itemCount: widget.snapshot.profiles.length, + separatorBuilder: (_, _) => const Divider(height: 1), + itemBuilder: (context, index) { + final profile = widget.snapshot.profiles[index]; + return _ProfileTile( + profile: profile, + onTap: profile.active || _busy ? null : () => _confirmSwitch(profile), + trailing: _profileMenu(profile), + ); + }, + ), + ); + } + + Widget _profileMenu(ProfileInfo profile) { + return PopupMenuButton<_ProfileAction>( + enabled: !_busy, + onSelected: (action) => _handleAction(action, profile), + itemBuilder: (context) => [ + if (profile.active) + const PopupMenuItem( + value: _ProfileAction.logout, + child: ListTile( + leading: Icon(Icons.logout), + title: Text('Logout'), + contentPadding: EdgeInsets.zero, + ), + ), + PopupMenuItem( + value: _ProfileAction.remove, + enabled: !profile.active, + child: const ListTile( + leading: Icon(Icons.delete_outline), + title: Text('Remove'), + contentPadding: EdgeInsets.zero, + ), + ), + ], + ); + } + + Future _handleAction( + _ProfileAction action, + ProfileInfo profile, + ) async { + switch (action) { + case _ProfileAction.logout: + await _confirmAndRun( + title: 'Logout from ${profile.name}?', + message: + 'This disconnects the active profile and clears its session.', + run: widget.client.logoutActive, + ); + case _ProfileAction.remove: + await _confirmAndRun( + title: 'Remove profile ${profile.name}?', + message: 'This deletes the profile from this device.', + run: () => widget.client.removeProfile(profile.name), + ); + } + } + + Future _confirmSwitch(ProfileInfo profile) async { + await _confirmAndRun( + title: 'Switch to ${profile.name}?', + message: 'The connection will restart with the new profile.', + run: () => widget.client.switchProfile(profile.name), + ); + } + + Future _showAddDialog() async { + final controller = TextEditingController(); + final name = await showDialog( + context: context, + builder: (context) { + return AlertDialog( + title: const Text('Add profile'), + content: TextField( + controller: controller, + autofocus: true, + decoration: const InputDecoration(labelText: 'Profile name'), + onSubmitted: (value) => Navigator.of(context).pop(value.trim()), + ), + actions: [ + TextButton( + onPressed: () => Navigator.of(context).pop(), + child: const Text('Cancel'), + ), + FilledButton( + onPressed: () => + Navigator.of(context).pop(controller.text.trim()), + child: const Text('Add'), + ), + ], + ); + }, + ); + if (name == null || name.isEmpty) { + return; + } + await _runBusy(() => widget.client.addProfile(name)); + } + + Future _confirmAndRun({ + required String title, + required String message, + required Future Function() run, + }) async { + final confirm = await showDialog( + context: context, + builder: (context) { + return AlertDialog( + title: Text(title), + content: Text(message), + actions: [ + TextButton( + onPressed: () => Navigator.of(context).pop(false), + child: const Text('Cancel'), + ), + FilledButton( + onPressed: () => Navigator.of(context).pop(true), + child: const Text('Confirm'), + ), + ], + ); + }, + ); + if (confirm != true) { + return; + } + await _runBusy(run); + } + + Future _runBusy(Future Function() action) async { + if (_busy) { + return; + } + setState(() => _busy = true); + try { + await action(); + } finally { + if (mounted) { + setState(() => _busy = false); + } + } + } +} + +enum _ProfileAction { logout, remove } + +class _SettingsPane extends StatefulWidget { + const _SettingsPane({required this.snapshot, required this.client}); + + final ClientSnapshot snapshot; + final DaemonClient client; + + @override + State<_SettingsPane> createState() => _SettingsPaneState(); +} + +class _SettingsPaneState extends State<_SettingsPane> { + bool _writing = false; + + @override + Widget build(BuildContext context) { + final settings = widget.snapshot.settings; + final disabled = _writing; + + return _Page( + title: 'Settings', + child: ListView( + children: [ + _InfoRow(label: 'Management URL', value: settings.managementUrl), + _InfoRow(label: 'Interface', value: settings.interfaceName), + _InfoRow(label: 'WireGuard port', value: '${settings.wireguardPort}'), + _InfoRow(label: 'MTU', value: '${settings.mtu}'), + const SizedBox(height: 16), + SwitchListTile( + value: settings.autoConnect, + onChanged: disabled + ? null + : (value) => + _apply(settings.copyWith(autoConnect: value)), + title: const Text('Connect on startup'), + ), + SwitchListTile( + value: settings.allowSsh, + onChanged: disabled + ? null + : (value) => _apply(settings.copyWith(allowSsh: value)), + title: const Text('Allow SSH'), + ), + SwitchListTile( + value: settings.quantumResistance, + onChanged: disabled + ? null + : (value) => + _apply(settings.copyWith(quantumResistance: value)), + title: const Text('Quantum resistance'), + ), + SwitchListTile( + value: settings.lazyConnection, + onChanged: disabled + ? null + : (value) => + _apply(settings.copyWith(lazyConnection: value)), + title: const Text('Lazy connections'), + ), + SwitchListTile( + value: settings.blockInbound, + onChanged: disabled + ? null + : (value) => + _apply(settings.copyWith(blockInbound: value)), + title: const Text('Block inbound'), + ), + SwitchListTile( + value: settings.notifications, + onChanged: disabled + ? null + : (value) => + _apply(settings.copyWith(notifications: value)), + title: const Text('Notifications'), + ), + ], + ), + ); + } + + Future _apply(ClientSettings updated) async { + setState(() => _writing = true); + try { + await widget.client.updateSettings(updated); + } finally { + if (mounted) { + setState(() => _writing = false); + } + } + } +} + +class _StatusGlyph extends StatelessWidget { + const _StatusGlyph({required this.status}); + + final ConnectionStatus status; + + @override + Widget build(BuildContext context) { + final color = switch (status) { + ConnectionStatus.connected => Colors.green, + ConnectionStatus.connecting => Colors.amber, + ConnectionStatus.awaitingLogin => Colors.lightBlue, + ConnectionStatus.error => Colors.red, + ConnectionStatus.disconnected => Colors.grey, + }; + + return Tooltip( + message: status.label, + child: Icon(Icons.circle, color: color, size: 18), + ); + } +} + +class _InfoRow extends StatelessWidget { + const _InfoRow({required this.label, required this.value}); + + final String label; + final String value; + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.symmetric(vertical: 8), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox( + width: 160, + child: Text(label, style: Theme.of(context).textTheme.labelLarge), + ), + Expanded(child: Text(value)), + ], + ), + ); + } +} + +class _SectionLabel extends StatelessWidget { + const _SectionLabel(this.text); + + final String text; + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.only(bottom: 8), + child: Text(text, style: Theme.of(context).textTheme.titleMedium), + ); + } +} + +class _ErrorBanner extends StatelessWidget { + const _ErrorBanner({required this.message}); + + final String message; + + @override + Widget build(BuildContext context) { + final colors = Theme.of(context).colorScheme; + return DecoratedBox( + decoration: BoxDecoration( + color: colors.errorContainer, + borderRadius: BorderRadius.circular(8), + ), + child: Padding( + padding: const EdgeInsets.all(12), + child: Row( + children: [ + Icon(Icons.error_outline, color: colors.onErrorContainer), + const SizedBox(width: 12), + Expanded( + child: Text( + message, + style: TextStyle(color: colors.onErrorContainer), + ), + ), + ], + ), + ), + ); + } +} + +class _LoginBanner extends StatelessWidget { + const _LoginBanner({required this.pending}); + + final PendingLogin pending; + + @override + Widget build(BuildContext context) { + final colors = Theme.of(context).colorScheme; + return DecoratedBox( + decoration: BoxDecoration( + color: colors.tertiaryContainer, + borderRadius: BorderRadius.circular(8), + ), + child: Padding( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Sign in to continue', + style: Theme.of(context).textTheme.titleMedium?.copyWith( + color: colors.onTertiaryContainer, + ), + ), + const SizedBox(height: 8), + Text( + 'A browser window opened to complete sign-in. ' + 'If it did not, open the URL below.', + style: TextStyle(color: colors.onTertiaryContainer), + ), + const SizedBox(height: 12), + SelectableText( + pending.verificationUri, + style: TextStyle(color: colors.onTertiaryContainer), + ), + const SizedBox(height: 4), + Text( + 'Code: ${pending.userCode}', + style: TextStyle(color: colors.onTertiaryContainer), + ), + const SizedBox(height: 12), + Wrap( + spacing: 8, + children: [ + FilledButton.tonalIcon( + onPressed: () => _openUrl(pending.verificationUri), + icon: const Icon(Icons.open_in_new), + label: const Text('Open in browser'), + ), + OutlinedButton.icon( + onPressed: () => _copy(context, pending.verificationUri), + icon: const Icon(Icons.copy), + label: const Text('Copy URL'), + ), + ], + ), + ], + ), + ), + ); + } + + Future _openUrl(String url) async { + await openExternalUrl(url); + } + + Future _copy(BuildContext context, String url) async { + await Clipboard.setData(ClipboardData(text: url)); + if (!context.mounted) { + return; + } + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('URL copied')), + ); + } +} + +class _NetworkTile extends StatelessWidget { + const _NetworkTile({ + required this.route, + required this.exitNodeMode, + required this.busy, + required this.onChanged, + }); + + final NetworkRoute route; + final bool exitNodeMode; + final bool busy; + final ValueChanged onChanged; + + @override + Widget build(BuildContext context) { + final subtitle = [ + route.range, + if (route.domains.isNotEmpty) route.domains.join(', '), + ].join(' '); + + Widget leading; + if (busy) { + leading = const SizedBox( + width: 24, + height: 24, + child: CircularProgressIndicator(strokeWidth: 2), + ); + } else if (exitNodeMode) { + leading = IconButton( + icon: Icon( + route.selected + ? Icons.radio_button_checked + : Icons.radio_button_unchecked, + ), + onPressed: () => onChanged(!route.selected), + ); + } else { + leading = Checkbox( + value: route.selected, + onChanged: (value) => onChanged(value ?? false), + ); + } + + return ListTile( + contentPadding: EdgeInsets.zero, + leading: leading, + title: Text(route.id), + subtitle: Text(subtitle), + trailing: route.isExitNode ? const Icon(Icons.public) : null, + onTap: busy ? null : () => onChanged(!route.selected), + ); + } +} + +class _ProfileTile extends StatelessWidget { + const _ProfileTile({required this.profile, this.onTap, this.trailing}); + + final ProfileInfo profile; + final VoidCallback? onTap; + final Widget? trailing; + + @override + Widget build(BuildContext context) { + return ListTile( + contentPadding: EdgeInsets.zero, + leading: Icon( + profile.active ? Icons.check_circle : Icons.circle_outlined, + ), + title: Text(profile.name), + subtitle: profile.email == null ? null : Text(profile.email!), + onTap: onTap, + trailing: trailing, + ); + } +} diff --git a/client/flutter_ui/lib/src/daemon_client.dart b/client/flutter_ui/lib/src/daemon_client.dart new file mode 100644 index 000000000..766a538cf --- /dev/null +++ b/client/flutter_ui/lib/src/daemon_client.dart @@ -0,0 +1,916 @@ +import 'dart:async'; +import 'dart:io'; + +import 'package:grpc/grpc.dart'; + +import 'generated/daemon.pbgrpc.dart' as daemon; +import 'models.dart'; +import 'platform.dart'; + +const _userAgent = 'netbird-desktop-ui/development'; + +abstract class DaemonClient { + String get daemonAddr; + + Stream watchSnapshot(); + + Stream watchEvents(); + + Stream watchUpdateRequests(); + + Future connect(); + + Future disconnect(); + + Future bringUp(); + + Future bringDown(); + + Future debugBundle({ + required bool anonymize, + required bool systemInfo, + String? uploadUrl, + }); + + Future getLogLevel(); + + Future setLogLevel(DaemonLogLevel level); + + Future setSyncResponsePersistence(bool enabled); + + Future startCpuProfile(); + + Future stopCpuProfile(); + + Future triggerUpdate(); + + Future getInstallerResult(); + + Future updateSettings(ClientSettings updated); + + Future setNetworkSelection(String routeId, bool selected); + + Future setExitNode(String? routeId); + + Future switchProfile(String name); + + Future addProfile(String name); + + Future removeProfile(String name); + + Future logoutActive(); + + void dispose(); +} + +class GrpcDaemonClient implements DaemonClient { + GrpcDaemonClient({required this.daemonAddr}) { + _snapshot = ClientSnapshot.initial(daemonAddr); + _channel = _createChannel(daemonAddr); + _client = daemon.DaemonServiceClient(_channel); + } + + @override + final String daemonAddr; + + final _snapshots = StreamController.broadcast(); + final _events = StreamController.broadcast(); + final _updateRequests = StreamController.broadcast(); + final _refreshInterval = const Duration(seconds: 2); + final _callTimeout = const Duration(seconds: 5); + final _ssoLoginTimeout = const Duration(minutes: 5); + final _installerPollTimeout = const Duration(minutes: 15); + + late final ClientChannel _channel; + late final daemon.DaemonServiceClient _client; + late ClientSnapshot _snapshot; + + Timer? _poller; + StreamSubscription? _eventSubscription; + var _started = false; + + @override + Stream watchSnapshot() { + _start(); + scheduleMicrotask(_emit); + return _snapshots.stream; + } + + @override + Stream watchEvents() { + _start(); + return _events.stream; + } + + @override + Stream watchUpdateRequests() { + _start(); + return _updateRequests.stream; + } + + @override + Future connect() async { + _setStatus(ConnectionStatus.connecting, clearError: true); + try { + await _runLoginFlow(); + await _client.up( + daemon.UpRequest(username: _username()), + options: _options(timeout: const Duration(seconds: 30)), + ); + } catch (error) { + _snapshot = _snapshot.copyWith( + status: ConnectionStatus.error, + errorMessage: _formatError(error), + clearPendingLogin: true, + ); + _emit(); + return; + } finally { + await _refresh(); + } + } + + @override + Future disconnect() async { + await _runRpc(() async { + await _client.down(daemon.DownRequest(), options: _options()); + }); + } + + @override + Future bringUp() async { + await _client.up( + daemon.UpRequest(username: _username()), + options: _options(timeout: const Duration(seconds: 30)), + ); + } + + @override + Future bringDown() async { + await _client.down( + daemon.DownRequest(), + options: _options(timeout: const Duration(seconds: 15)), + ); + } + + @override + Future debugBundle({ + required bool anonymize, + required bool systemInfo, + String? uploadUrl, + }) async { + final request = daemon.DebugBundleRequest( + anonymize: anonymize, + systemInfo: systemInfo, + uploadURL: uploadUrl ?? '', + ); + final response = await _client.debugBundle( + request, + options: _options(timeout: const Duration(minutes: 2)), + ); + return DebugBundleResult( + path: response.path, + uploadedKey: response.uploadedKey, + uploadFailureReason: response.uploadFailureReason, + ); + } + + @override + Future getLogLevel() async { + final response = await _client.getLogLevel( + daemon.GetLogLevelRequest(), + options: _options(), + ); + return _mapLogLevelFromProto(response.level); + } + + @override + Future setLogLevel(DaemonLogLevel level) async { + await _client.setLogLevel( + daemon.SetLogLevelRequest(level: _mapLogLevelToProto(level)), + options: _options(), + ); + } + + @override + Future setSyncResponsePersistence(bool enabled) async { + await _client.setSyncResponsePersistence( + daemon.SetSyncResponsePersistenceRequest(enabled: enabled), + options: _options(), + ); + } + + @override + Future startCpuProfile() async { + await _client.startCPUProfile( + daemon.StartCPUProfileRequest(), + options: _options(), + ); + } + + @override + Future stopCpuProfile() async { + await _client.stopCPUProfile( + daemon.StopCPUProfileRequest(), + options: _options(), + ); + } + + @override + Future triggerUpdate() async { + final response = await _client.triggerUpdate( + daemon.TriggerUpdateRequest(), + options: _options(timeout: const Duration(seconds: 30)), + ); + return TriggerUpdateResult( + success: response.success, + errorMessage: response.errorMsg, + ); + } + + @override + Future getInstallerResult() async { + final response = await _client.getInstallerResult( + daemon.InstallerResultRequest(), + options: _options(timeout: _installerPollTimeout), + ); + return InstallerResult( + success: response.success, + errorMessage: response.errorMsg, + ); + } + + @override + Future updateSettings(ClientSettings updated) async { + await _runRpc(() async { + final activeProfile = _snapshot.activeProfile.name; + await _client.setConfig( + daemon.SetConfigRequest( + username: _username(), + profileName: activeProfile, + managementUrl: updated.managementUrl, + rosenpassEnabled: updated.quantumResistance, + serverSSHAllowed: updated.allowSsh, + disableAutoConnect: !updated.autoConnect, + disableNotifications: !updated.notifications, + lazyConnectionEnabled: updated.lazyConnection, + blockInbound: updated.blockInbound, + ), + options: _options(timeout: const Duration(seconds: 10)), + ); + }); + } + + @override + Future setNetworkSelection(String routeId, bool selected) async { + await _runRpc(() async { + final request = daemon.SelectNetworksRequest(networkIDs: [routeId]); + if (selected) { + await _client.selectNetworks(request, options: _options()); + } else { + await _client.deselectNetworks(request, options: _options()); + } + }); + } + + @override + Future setExitNode(String? routeId) async { + await _runRpc(() async { + final exitNodeIds = _snapshot.networks + .where((route) => route.isExitNode) + .map((route) => route.id) + .toList(); + if (exitNodeIds.isNotEmpty) { + await _client.deselectNetworks( + daemon.SelectNetworksRequest(networkIDs: exitNodeIds), + options: _options(), + ); + } + if (routeId != null) { + await _client.selectNetworks( + daemon.SelectNetworksRequest(networkIDs: [routeId]), + options: _options(), + ); + } + }); + } + + @override + Future switchProfile(String name) async { + await _runRpc(() async { + await _client.switchProfile( + daemon.SwitchProfileRequest(profileName: name, username: _username()), + options: _options(), + ); + }); + } + + @override + Future addProfile(String name) async { + await _runRpc(() async { + await _client.addProfile( + daemon.AddProfileRequest(profileName: name, username: _username()), + options: _options(), + ); + }); + } + + @override + Future removeProfile(String name) async { + await _runRpc(() async { + await _client.removeProfile( + daemon.RemoveProfileRequest(profileName: name, username: _username()), + options: _options(), + ); + }); + } + + @override + Future logoutActive() async { + await _runRpc(() async { + final active = _snapshot.activeProfile.name; + await _client.logout( + daemon.LogoutRequest(profileName: active, username: _username()), + options: _options(timeout: const Duration(seconds: 15)), + ); + }); + } + + @override + void dispose() { + _poller?.cancel(); + unawaited(_eventSubscription?.cancel() ?? Future.value()); + _events.close(); + _updateRequests.close(); + _snapshots.close(); + unawaited(_channel.shutdown()); + } + + void _start() { + if (_started) { + return; + } + _started = true; + unawaited(_refresh()); + _poller = Timer.periodic(_refreshInterval, (_) { + unawaited(_refresh()); + }); + _eventSubscription = _client + .subscribeEvents(daemon.SubscribeRequest(), options: _options()) + .listen( + (event) { + _checkUpdateMetadata(event); + final notification = _mapSystemEvent(event); + if (notification != null && !_events.isClosed) { + _events.add(notification); + } + unawaited(_refresh()); + }, + onError: (_) {}, + ); + } + + DaemonLogLevel _mapLogLevelFromProto(daemon.LogLevel level) { + return switch (level) { + daemon.LogLevel.PANIC => DaemonLogLevel.panic, + daemon.LogLevel.FATAL => DaemonLogLevel.fatal, + daemon.LogLevel.ERROR => DaemonLogLevel.error, + daemon.LogLevel.WARN => DaemonLogLevel.warn, + daemon.LogLevel.INFO => DaemonLogLevel.info, + daemon.LogLevel.DEBUG => DaemonLogLevel.debug, + daemon.LogLevel.TRACE => DaemonLogLevel.trace, + _ => DaemonLogLevel.unknown, + }; + } + + daemon.LogLevel _mapLogLevelToProto(DaemonLogLevel level) { + return switch (level) { + DaemonLogLevel.panic => daemon.LogLevel.PANIC, + DaemonLogLevel.fatal => daemon.LogLevel.FATAL, + DaemonLogLevel.error => daemon.LogLevel.ERROR, + DaemonLogLevel.warn => daemon.LogLevel.WARN, + DaemonLogLevel.info => daemon.LogLevel.INFO, + DaemonLogLevel.debug => daemon.LogLevel.DEBUG, + DaemonLogLevel.trace => daemon.LogLevel.TRACE, + DaemonLogLevel.unknown => daemon.LogLevel.UNKNOWN, + }; + } + + void _checkUpdateMetadata(daemon.SystemEvent event) { + final action = event.metadata['progress_window']; + if (action != 'show') { + return; + } + final version = event.metadata['version'] ?? 'unknown'; + if (!_updateRequests.isClosed) { + _updateRequests.add(UpdateProgressEvent(version: version)); + } + } + + SystemNotification? _mapSystemEvent(daemon.SystemEvent event) { + final severity = switch (event.severity) { + daemon.SystemEvent_Severity.WARNING => NotificationSeverity.warning, + daemon.SystemEvent_Severity.ERROR => NotificationSeverity.error, + daemon.SystemEvent_Severity.CRITICAL => NotificationSeverity.critical, + _ => NotificationSeverity.info, + }; + final category = switch (event.category) { + daemon.SystemEvent_Category.NETWORK => NotificationCategory.network, + daemon.SystemEvent_Category.DNS => NotificationCategory.dns, + daemon.SystemEvent_Category.AUTHENTICATION => + NotificationCategory.authentication, + daemon.SystemEvent_Category.CONNECTIVITY => + NotificationCategory.connectivity, + daemon.SystemEvent_Category.SYSTEM => NotificationCategory.system, + _ => NotificationCategory.system, + }; + return SystemNotification( + severity: severity, + category: category, + message: event.message, + userMessage: event.userMessage, + id: event.metadata['id'], + ); + } + + Future _runLoginFlow() async { + final loginResponse = await _client.login( + daemon.LoginRequest( + isUnixDesktopClient: Platform.isLinux, + profileName: _snapshot.activeProfile.name, + username: _username(), + hint: _snapshot.activeProfile.email, + ), + options: _options(timeout: const Duration(seconds: 30)), + ); + + if (!loginResponse.needsSSOLogin) { + return; + } + + _snapshot = _snapshot.copyWith( + status: ConnectionStatus.awaitingLogin, + pendingLogin: PendingLogin( + verificationUri: loginResponse.verificationURIComplete, + userCode: loginResponse.userCode, + ), + ); + _emit(); + + if (loginResponse.verificationURIComplete.isNotEmpty) { + await openExternalUrl(loginResponse.verificationURIComplete); + } + + await _client.waitSSOLogin( + daemon.WaitSSOLoginRequest(userCode: loginResponse.userCode), + options: _options(timeout: _ssoLoginTimeout), + ); + + _snapshot = _snapshot.copyWith( + status: ConnectionStatus.connecting, + clearPendingLogin: true, + ); + _emit(); + } + + Future _runRpc(Future Function() action) async { + try { + _snapshot = _snapshot.copyWith(clearError: true); + _emit(); + await action(); + } catch (error) { + _snapshot = _snapshot.copyWith( + status: ConnectionStatus.error, + errorMessage: _formatError(error), + ); + _emit(); + } finally { + await _refresh(); + } + } + + Future _refresh() async { + try { + final status = await _client.status( + daemon.StatusRequest(), + options: _options(), + ); + + final activeProfile = await _loadActiveProfile(); + final profiles = await _loadProfiles(activeProfile); + final networks = await _loadNetworks(); + final settings = await _loadSettings(activeProfile); + + final mappedStatus = _mapStatus(status.status); + final preserveAwaiting = + _snapshot.status == ConnectionStatus.awaitingLogin && + mappedStatus != ConnectionStatus.connected; + + _snapshot = ClientSnapshot( + daemonAddr: daemonAddr, + daemonVersion: status.daemonVersion.isEmpty + ? 'unknown' + : status.daemonVersion, + status: preserveAwaiting ? ConnectionStatus.awaitingLogin : mappedStatus, + activeProfile: activeProfile, + profiles: profiles, + networks: networks, + settings: settings, + pendingLogin: preserveAwaiting ? _snapshot.pendingLogin : null, + ); + } catch (error) { + _snapshot = _snapshot.copyWith( + status: ConnectionStatus.error, + errorMessage: _formatError(error), + ); + } + _emit(); + } + + Future _loadActiveProfile() async { + try { + final active = await _client.getActiveProfile( + daemon.GetActiveProfileRequest(), + options: _options(), + ); + if (active.profileName.isNotEmpty) { + return ProfileInfo( + name: active.profileName, + email: _snapshot.activeProfile.email, + active: true, + ); + } + } catch (_) { + // Keep the status pane usable even when optional profile RPCs fail. + } + return _snapshot.activeProfile; + } + + Future> _loadProfiles(ProfileInfo activeProfile) async { + try { + final response = await _client.listProfiles( + daemon.ListProfilesRequest(username: _username()), + options: _options(), + ); + final profiles = response.profiles.map((profile) { + return ProfileInfo(name: profile.name, active: profile.isActive); + }).toList(); + if (profiles.isNotEmpty) { + return profiles; + } + } catch (_) { + // Profile listing is not required for core connection status. + } + return [activeProfile]; + } + + Future> _loadNetworks() async { + try { + final response = await _client.listNetworks( + daemon.ListNetworksRequest(), + options: _options(), + ); + return _mapNetworks(response.routes); + } catch (_) { + return _snapshot.networks; + } + } + + Future _loadSettings(ProfileInfo activeProfile) async { + try { + final config = await _client.getConfig( + daemon.GetConfigRequest( + profileName: activeProfile.name, + username: _username(), + ), + options: _options(), + ); + return ClientSettings( + managementUrl: config.managementUrl.isEmpty + ? 'https://api.netbird.io' + : config.managementUrl, + interfaceName: config.interfaceName.isEmpty + ? 'wt0' + : config.interfaceName, + wireguardPort: config.hasWireguardPort() + ? config.wireguardPort.toInt() + : 51820, + mtu: config.hasMtu() ? config.mtu.toInt() : 1280, + autoConnect: !config.disableAutoConnect, + allowSsh: config.serverSSHAllowed, + quantumResistance: config.rosenpassEnabled, + notifications: !config.disableNotifications, + lazyConnection: config.lazyConnectionEnabled, + blockInbound: config.blockInbound, + ); + } catch (_) { + return _snapshot.settings; + } + } + + List _mapNetworks(Iterable routes) { + final rangeCounts = {}; + for (final route in routes) { + if (route.domains.isEmpty) { + rangeCounts.update( + route.range, + (count) => count + 1, + ifAbsent: () => 1, + ); + } + } + + return routes.map((route) { + final resolvedIps = route.resolvedIPs.map((domain, ipList) { + return MapEntry(domain, ipList.ips.toList()); + }); + + return NetworkRoute( + id: route.iD, + range: route.range, + selected: route.selected, + domains: route.domains.toList(), + resolvedIps: resolvedIps, + overlapping: + route.domains.isEmpty && (rangeCounts[route.range] ?? 0) > 1, + ); + }).toList() + ..sort((a, b) => a.id.toLowerCase().compareTo(b.id.toLowerCase())); + } + + CallOptions _options({Duration? timeout}) { + return CallOptions(timeout: timeout ?? _callTimeout); + } + + void _setStatus( + ConnectionStatus status, { + bool clearError = false, + bool clearPendingLogin = false, + }) { + _snapshot = _snapshot.copyWith( + status: status, + clearError: clearError, + clearPendingLogin: clearPendingLogin, + ); + _emit(); + } + + void _emit() { + if (!_snapshots.isClosed) { + _snapshots.add(_snapshot); + } + } +} + +class FakeDaemonClient implements DaemonClient { + FakeDaemonClient({required this.daemonAddr}) { + scheduleMicrotask(_emit); + } + + @override + final String daemonAddr; + + final _snapshots = StreamController.broadcast(); + + late ClientSnapshot _snapshot = ClientSnapshot.initial(daemonAddr).copyWith( + daemonVersion: 'development', + profiles: const [ + ProfileInfo(name: 'default', email: 'user@example.com', active: true), + ProfileInfo(name: 'staging', active: false), + ], + networks: const [ + NetworkRoute(id: 'office', range: '10.10.0.0/16', selected: true), + NetworkRoute(id: 'prod', range: '10.20.0.0/16'), + NetworkRoute(id: 'exit-us', range: '0.0.0.0/0'), + ], + ); + + @override + Stream watchSnapshot() { + scheduleMicrotask(_emit); + return _snapshots.stream; + } + + @override + Stream watchEvents() => + const Stream.empty(); + + @override + Stream watchUpdateRequests() => + const Stream.empty(); + + @override + Future connect() async { + _snapshot = _snapshot.copyWith(status: ConnectionStatus.connecting); + _emit(); + await Future.delayed(const Duration(milliseconds: 450)); + _snapshot = _snapshot.copyWith(status: ConnectionStatus.connected); + _emit(); + } + + @override + Future disconnect() async { + _snapshot = _snapshot.copyWith(status: ConnectionStatus.disconnected); + _emit(); + } + + @override + Future bringUp() async { + _snapshot = _snapshot.copyWith(status: ConnectionStatus.connected); + _emit(); + } + + @override + Future bringDown() async { + _snapshot = _snapshot.copyWith(status: ConnectionStatus.disconnected); + _emit(); + } + + @override + Future debugBundle({ + required bool anonymize, + required bool systemInfo, + String? uploadUrl, + }) async { + await Future.delayed(const Duration(milliseconds: 400)); + return DebugBundleResult( + path: '/tmp/netbird-debug.tar.gz', + uploadedKey: uploadUrl == null ? '' : 'fake-upload-key', + ); + } + + @override + Future getLogLevel() async => DaemonLogLevel.info; + + @override + Future setLogLevel(DaemonLogLevel level) async {} + + @override + Future setSyncResponsePersistence(bool enabled) async {} + + @override + Future startCpuProfile() async {} + + @override + Future stopCpuProfile() async {} + + @override + Future triggerUpdate() async { + return const TriggerUpdateResult(success: true); + } + + @override + Future getInstallerResult() async { + await Future.delayed(const Duration(seconds: 2)); + return const InstallerResult(success: true); + } + + @override + Future updateSettings(ClientSettings updated) async { + _snapshot = _snapshot.copyWith(settings: updated); + _emit(); + } + + @override + Future setNetworkSelection(String routeId, bool selected) async { + final next = _snapshot.networks.map((route) { + if (route.id != routeId) { + return route; + } + return NetworkRoute( + id: route.id, + range: route.range, + domains: route.domains, + resolvedIps: route.resolvedIps, + overlapping: route.overlapping, + selected: selected, + ); + }).toList(); + _snapshot = _snapshot.copyWith(networks: next); + _emit(); + } + + @override + Future setExitNode(String? routeId) async { + final next = _snapshot.networks.map((route) { + if (!route.isExitNode) { + return route; + } + return NetworkRoute( + id: route.id, + range: route.range, + domains: route.domains, + resolvedIps: route.resolvedIps, + overlapping: route.overlapping, + selected: route.id == routeId, + ); + }).toList(); + _snapshot = _snapshot.copyWith(networks: next); + _emit(); + } + + @override + Future switchProfile(String name) async { + final profiles = _snapshot.profiles.map((profile) { + return ProfileInfo( + name: profile.name, + email: profile.email, + active: profile.name == name, + ); + }).toList(); + final active = profiles.firstWhere( + (profile) => profile.active, + orElse: () => _snapshot.activeProfile, + ); + _snapshot = _snapshot.copyWith(profiles: profiles, activeProfile: active); + _emit(); + } + + @override + Future addProfile(String name) async { + final profiles = [ + ..._snapshot.profiles, + ProfileInfo(name: name, active: false), + ]; + _snapshot = _snapshot.copyWith(profiles: profiles); + _emit(); + } + + @override + Future removeProfile(String name) async { + final profiles = _snapshot.profiles + .where((profile) => profile.name != name) + .toList(); + _snapshot = _snapshot.copyWith(profiles: profiles); + _emit(); + } + + @override + Future logoutActive() async { + _snapshot = _snapshot.copyWith(status: ConnectionStatus.disconnected); + _emit(); + } + + @override + void dispose() { + _snapshots.close(); + } + + void _emit() { + if (!_snapshots.isClosed) { + _snapshots.add(_snapshot); + } + } +} + +ClientChannel _createChannel(String daemonAddr) { + final options = ChannelOptions( + credentials: const ChannelCredentials.insecure(), + userAgent: _userAgent, + connectTimeout: const Duration(seconds: 3), + ); + + if (daemonAddr.startsWith('unix://')) { + final path = daemonAddr.substring('unix://'.length); + return ClientChannel( + InternetAddress(path, type: InternetAddressType.unix), + port: 0, + options: options, + ); + } + + final uri = daemonAddr.contains('://') + ? Uri.parse(daemonAddr) + : Uri.parse('tcp://$daemonAddr'); + final host = uri.host.isEmpty ? '127.0.0.1' : uri.host; + final port = uri.hasPort ? uri.port : 41731; + return ClientChannel(host, port: port, options: options); +} + +ConnectionStatus _mapStatus(String status) { + return switch (status) { + 'Connected' => ConnectionStatus.connected, + 'Connecting' => ConnectionStatus.connecting, + 'Idle' || 'SessionExpired' => ConnectionStatus.disconnected, + _ => ConnectionStatus.error, + }; +} + +String _username() { + if (Platform.isWindows) { + final username = Platform.environment['USERNAME'] ?? ''; + final domain = Platform.environment['USERDOMAIN'] ?? ''; + if (domain.isNotEmpty && username.isNotEmpty) { + return '$domain\\$username'; + } + return username; + } + return Platform.environment['USER'] ?? Platform.environment['LOGNAME'] ?? ''; +} + +String _formatError(Object error) { + if (error is GrpcError) { + return error.message ?? error.toString(); + } + return error.toString(); +} diff --git a/client/flutter_ui/lib/src/debug_screen.dart b/client/flutter_ui/lib/src/debug_screen.dart new file mode 100644 index 000000000..65627c026 --- /dev/null +++ b/client/flutter_ui/lib/src/debug_screen.dart @@ -0,0 +1,460 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; + +import 'daemon_client.dart'; +import 'models.dart'; +import 'platform.dart'; + +const _defaultUploadUrl = 'https://upload.netbird.io/'; + +class DebugScreen extends StatefulWidget { + const DebugScreen({required this.client, super.key}); + + final DaemonClient client; + + @override + State createState() => _DebugScreenState(); +} + +class _DebugScreenState extends State { + final _uploadUrlController = + TextEditingController(text: _defaultUploadUrl); + final _durationController = TextEditingController(text: '1'); + + bool _anonymize = false; + bool _systemInfo = true; + bool _upload = true; + bool _runWithTrace = true; + bool _busy = false; + + String _status = ''; + double? _progress; + + @override + void dispose() { + _uploadUrlController.dispose(); + _durationController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.all(24), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('Debug', style: Theme.of(context).textTheme.headlineSmall), + const SizedBox(height: 16), + Text( + 'Create a debug bundle to help troubleshoot issues with NetBird.', + style: Theme.of(context).textTheme.bodyMedium, + ), + const SizedBox(height: 24), + Expanded( + child: ListView( + children: [ + CheckboxListTile( + contentPadding: EdgeInsets.zero, + value: _anonymize, + onChanged: _busy + ? null + : (value) => setState(() => _anonymize = value ?? false), + title: const Text( + 'Anonymize sensitive information (public IPs, domains, ...)', + ), + ), + CheckboxListTile( + contentPadding: EdgeInsets.zero, + value: _systemInfo, + onChanged: _busy + ? null + : (value) => setState(() => _systemInfo = value ?? false), + title: const Text( + 'Include system information (routes, interfaces, ...)', + ), + ), + CheckboxListTile( + contentPadding: EdgeInsets.zero, + value: _upload, + onChanged: _busy + ? null + : (value) => setState(() => _upload = value ?? false), + title: const Text('Upload bundle automatically after creation'), + ), + if (_upload) + Padding( + padding: const EdgeInsets.only(left: 32, bottom: 8, top: 4), + child: TextField( + controller: _uploadUrlController, + enabled: !_busy, + decoration: const InputDecoration( + labelText: 'Debug upload URL', + border: OutlineInputBorder(), + ), + ), + ), + const Divider(height: 32), + CheckboxListTile( + contentPadding: EdgeInsets.zero, + value: _runWithTrace, + onChanged: _busy + ? null + : (value) => + setState(() => _runWithTrace = value ?? false), + title: const Text( + 'Run with trace logs before creating bundle', + ), + ), + if (_runWithTrace) + Padding( + padding: const EdgeInsets.only(left: 32, top: 4), + child: Row( + children: [ + const Text('Run for'), + const SizedBox(width: 12), + SizedBox( + width: 80, + child: TextField( + controller: _durationController, + enabled: !_busy, + keyboardType: TextInputType.number, + inputFormatters: [ + FilteringTextInputFormatter.digitsOnly, + ], + decoration: const InputDecoration( + isDense: true, + ), + ), + ), + const SizedBox(width: 8), + Text(_durationLabel()), + ], + ), + ), + if (_runWithTrace) + const Padding( + padding: EdgeInsets.only(left: 32, top: 8), + child: Text( + 'Note: NetBird will be brought up and down during collection.', + style: TextStyle(fontStyle: FontStyle.italic), + ), + ), + const SizedBox(height: 24), + if (_status.isNotEmpty) + Padding( + padding: const EdgeInsets.only(bottom: 12), + child: Text(_status), + ), + if (_progress != null) + Padding( + padding: const EdgeInsets.only(bottom: 16), + child: LinearProgressIndicator(value: _progress), + ), + Align( + alignment: Alignment.centerLeft, + child: FilledButton.icon( + onPressed: _busy ? null : _onCreate, + icon: _busy + ? const SizedBox( + width: 18, + height: 18, + child: CircularProgressIndicator(strokeWidth: 2), + ) + : const Icon(Icons.archive_outlined), + label: const Text('Create Debug Bundle'), + ), + ), + ], + ), + ), + ], + ), + ); + } + + String _durationLabel() { + final value = int.tryParse(_durationController.text) ?? 0; + return value == 1 ? 'minute' : 'minutes'; + } + + Future _onCreate() async { + final uploadUrl = _upload ? _uploadUrlController.text.trim() : null; + if (_upload && (uploadUrl == null || uploadUrl.isEmpty)) { + setState(() => _status = 'Upload URL is required when upload is enabled'); + return; + } + + Duration? traceDuration; + if (_runWithTrace) { + final minutes = int.tryParse(_durationController.text); + if (minutes == null || minutes < 1) { + setState(() => _status = 'Duration must be a number ≥ 1'); + return; + } + traceDuration = Duration(minutes: minutes); + } + + setState(() { + _busy = true; + _status = ''; + _progress = null; + }); + + try { + DebugBundleResult result; + if (traceDuration != null) { + result = await _runWithTraceLogs( + duration: traceDuration, + uploadUrl: uploadUrl, + ); + } else { + setState(() => _status = 'Creating debug bundle...'); + result = await widget.client.debugBundle( + anonymize: _anonymize, + systemInfo: _systemInfo, + uploadUrl: uploadUrl, + ); + } + if (!mounted) { + return; + } + setState(() => _status = 'Bundle created successfully'); + await _showResultDialog(result); + } catch (error) { + if (!mounted) { + return; + } + setState(() { + _status = 'Error: $error'; + _progress = null; + }); + } finally { + if (mounted) { + setState(() => _busy = false); + } + } + } + + Future _runWithTraceLogs({ + required Duration duration, + required String? uploadUrl, + }) async { + final initialLevel = await widget.client.getLogLevel(); + final wasTrace = initialLevel == DaemonLogLevel.trace; + + var levelChanged = false; + var persistenceEnabled = false; + var cpuProfileStarted = false; + + try { + if (!wasTrace) { + await widget.client.setLogLevel(DaemonLogLevel.trace); + levelChanged = true; + } + + try { + await widget.client.bringDown(); + } catch (_) { + // Already down is fine; daemon returns OK either way. + } + await Future.delayed(const Duration(seconds: 1)); + + try { + await widget.client.setSyncResponsePersistence(true); + persistenceEnabled = true; + } catch (_) { + // Persistence is best-effort — the bundle still works without it. + } + + await widget.client.bringUp(); + await Future.delayed(const Duration(seconds: 3)); + + try { + await widget.client.startCpuProfile(); + cpuProfileStarted = true; + } catch (_) { + // CPU profiling is optional. + } + + await _trackProgress(duration); + + if (cpuProfileStarted) { + try { + await widget.client.stopCpuProfile(); + } catch (_) {} + } + + if (!mounted) { + return const DebugBundleResult(path: ''); + } + setState(() { + _status = 'Creating debug bundle with collected logs...'; + _progress = null; + }); + + return await widget.client.debugBundle( + anonymize: _anonymize, + systemInfo: _systemInfo, + uploadUrl: uploadUrl, + ); + } finally { + if (levelChanged) { + try { + await widget.client.setLogLevel(initialLevel); + } catch (_) {} + } + if (persistenceEnabled) { + try { + await widget.client.setSyncResponsePersistence(false); + } catch (_) {} + } + } + } + + Future _trackProgress(Duration total) async { + final start = DateTime.now(); + final end = start.add(total); + setState(() { + _progress = 0; + _status = 'Running with trace logs... ${_formatRemaining(total)} remaining'; + }); + + while (DateTime.now().isBefore(end)) { + await Future.delayed(const Duration(milliseconds: 500)); + if (!mounted) { + return; + } + final elapsed = DateTime.now().difference(start); + final fraction = (elapsed.inMilliseconds / total.inMilliseconds).clamp( + 0.0, + 1.0, + ); + final remaining = end.difference(DateTime.now()); + setState(() { + _progress = fraction; + _status = + 'Running with trace logs... ${_formatRemaining(remaining < Duration.zero ? Duration.zero : remaining)} remaining'; + }); + } + } + + String _formatRemaining(Duration d) { + final hours = d.inHours.toString().padLeft(2, '0'); + final minutes = (d.inMinutes % 60).toString().padLeft(2, '0'); + final seconds = (d.inSeconds % 60).toString().padLeft(2, '0'); + return '$hours:$minutes:$seconds'; + } + + Future _showResultDialog(DebugBundleResult result) async { + if (!mounted) { + return; + } + await showDialog( + context: context, + builder: (context) => _DebugResultDialog(result: result), + ); + } +} + +class _DebugResultDialog extends StatelessWidget { + const _DebugResultDialog({required this.result}); + + final DebugBundleResult result; + + @override + Widget build(BuildContext context) { + final folder = _parentFolder(result.path); + + String title; + Widget body; + if (result.uploadFailed) { + title = 'Upload Failed'; + body = Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Text('Bundle upload failed:\n${result.uploadFailureReason}'), + const SizedBox(height: 12), + SelectableText('Local copy: ${result.path}'), + ], + ); + } else if (result.uploaded) { + title = 'Upload Successful'; + body = Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + const Text('Bundle uploaded successfully.'), + const SizedBox(height: 12), + const Text('Upload key:'), + SelectableText(result.uploadedKey), + const SizedBox(height: 12), + SelectableText('Local copy: ${result.path}'), + ], + ); + } else { + title = 'Debug Bundle Created'; + body = Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Text('Bundle created locally at:\n${result.path}'), + const SizedBox(height: 8), + const Text( + 'Administrator privileges may be required to access the file.', + style: TextStyle(fontStyle: FontStyle.italic), + ), + ], + ); + } + + return AlertDialog( + title: Text(title), + content: SingleChildScrollView(child: body), + actions: [ + if (result.uploaded) + TextButton.icon( + onPressed: () async { + await Clipboard.setData( + ClipboardData(text: result.uploadedKey), + ); + if (context.mounted) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('Upload key copied')), + ); + } + }, + icon: const Icon(Icons.copy), + label: const Text('Copy key'), + ), + TextButton.icon( + onPressed: result.path.isEmpty + ? null + : () => openExternalUrl(result.path), + icon: const Icon(Icons.description_outlined), + label: const Text('Open file'), + ), + TextButton.icon( + onPressed: folder.isEmpty ? null : () => openExternalUrl(folder), + icon: const Icon(Icons.folder_open), + label: const Text('Open folder'), + ), + FilledButton( + onPressed: () => Navigator.of(context).pop(), + child: const Text('Close'), + ), + ], + ); + } + + String _parentFolder(String path) { + if (path.isEmpty) { + return ''; + } + final lastSlash = path.lastIndexOf(RegExp(r'[/\\]')); + return lastSlash <= 0 ? '' : path.substring(0, lastSlash); + } +} diff --git a/client/flutter_ui/lib/src/desktop_integration.dart b/client/flutter_ui/lib/src/desktop_integration.dart new file mode 100644 index 000000000..4d2bdff76 --- /dev/null +++ b/client/flutter_ui/lib/src/desktop_integration.dart @@ -0,0 +1,434 @@ +import 'dart:async'; +import 'dart:io'; + +import 'package:local_notifier/local_notifier.dart'; +import 'package:tray_manager/tray_manager.dart'; +import 'package:window_manager/window_manager.dart'; + +import 'daemon_client.dart'; +import 'models.dart'; +import 'platform.dart'; + +const uiVersion = '0.1.0'; +const _githubUrl = 'https://github.com/netbirdio/netbird'; +const _downloadUrl = 'https://netbird.io/download/'; + +class TabIndex { + static const status = 0; + static const networks = 1; + static const profiles = 2; + static const settings = 3; + static const debug = 4; +} + +/// Owns native desktop integration: window lifecycle (hide on close), system +/// tray icon and menu, and OS-level notifications driven by daemon events. +class DesktopIntegration with TrayListener, WindowListener { + DesktopIntegration({required this.client}); + + final DaemonClient client; + final _tabRequests = StreamController.broadcast(); + + StreamSubscription? _snapshotSub; + StreamSubscription? _eventSub; + ClientSnapshot? _lastSnapshot; + String? _lastMenuKey; + bool _disposed = false; + bool _settingsBusy = false; + + Stream get tabRequests => _tabRequests.stream; + + static const _trayMenuConnect = 'connect'; + static const _trayMenuDisconnect = 'disconnect'; + static const _trayMenuShow = 'show'; + static const _trayMenuQuit = 'quit'; + static const _trayMenuAllowSSH = 'settings.allow_ssh'; + static const _trayMenuAutoConnect = 'settings.auto_connect'; + static const _trayMenuQuantum = 'settings.quantum'; + static const _trayMenuLazy = 'settings.lazy'; + static const _trayMenuBlockInbound = 'settings.block_inbound'; + static const _trayMenuNotifications = 'settings.notifications'; + static const _trayMenuAdvancedSettings = 'open.settings'; + static const _trayMenuDebugBundle = 'open.debug'; + static const _trayMenuNetworks = 'open.networks'; + static const _trayMenuManageProfiles = 'open.profiles'; + static const _trayMenuLogout = 'profile.logout'; + static const _trayMenuGithub = 'about.github'; + static const _trayMenuDownload = 'about.download'; + static const _profileSwitchPrefix = 'profile.switch:'; + + Future initialize() async { + await localNotifier.setup(appName: 'NetBird'); + await windowManager.setPreventClose(true); + windowManager.addListener(this); + trayManager.addListener(this); + + await _applyTrayIcon(ConnectionStatus.disconnected); + await trayManager.setToolTip('NetBird'); + await _refreshTrayMenu(null); + + _snapshotSub = client.watchSnapshot().listen(_onSnapshot); + _eventSub = client.watchEvents().listen(_onEvent); + } + + Future dispose() async { + if (_disposed) { + return; + } + _disposed = true; + await _snapshotSub?.cancel(); + await _eventSub?.cancel(); + await _tabRequests.close(); + windowManager.removeListener(this); + trayManager.removeListener(this); + await trayManager.destroy(); + } + + @override + void onWindowClose() { + unawaited(_handleWindowClose()); + } + + Future _handleWindowClose() async { + final prevent = await windowManager.isPreventClose(); + if (prevent) { + await windowManager.hide(); + } + } + + @override + void onTrayIconMouseDown() { + if (Platform.isMacOS) { + unawaited(trayManager.popUpContextMenu()); + } else { + unawaited(_showWindow()); + } + } + + @override + void onTrayIconRightMouseDown() { + unawaited(trayManager.popUpContextMenu()); + } + + @override + void onTrayMenuItemClick(MenuItem menuItem) { + final key = menuItem.key; + if (key == null) { + return; + } + if (key.startsWith(_profileSwitchPrefix)) { + final name = key.substring(_profileSwitchPrefix.length); + unawaited(_switchProfile(name)); + return; + } + switch (key) { + case _trayMenuConnect: + unawaited(client.connect()); + case _trayMenuDisconnect: + unawaited(client.disconnect()); + case _trayMenuShow: + unawaited(_showWindow()); + case _trayMenuQuit: + unawaited(_quit()); + case _trayMenuAllowSSH: + unawaited(_toggleSetting((s) => s.copyWith(allowSsh: !s.allowSsh))); + case _trayMenuAutoConnect: + unawaited( + _toggleSetting((s) => s.copyWith(autoConnect: !s.autoConnect)), + ); + case _trayMenuQuantum: + unawaited( + _toggleSetting( + (s) => s.copyWith(quantumResistance: !s.quantumResistance), + ), + ); + case _trayMenuLazy: + unawaited( + _toggleSetting( + (s) => s.copyWith(lazyConnection: !s.lazyConnection), + ), + ); + case _trayMenuBlockInbound: + unawaited( + _toggleSetting( + (s) => s.copyWith(blockInbound: !s.blockInbound), + ), + ); + case _trayMenuNotifications: + unawaited( + _toggleSetting( + (s) => s.copyWith(notifications: !s.notifications), + ), + ); + case _trayMenuAdvancedSettings: + unawaited(_openTab(TabIndex.settings)); + case _trayMenuDebugBundle: + unawaited(_openTab(TabIndex.debug)); + case _trayMenuNetworks: + unawaited(_openTab(TabIndex.networks)); + case _trayMenuManageProfiles: + unawaited(_openTab(TabIndex.profiles)); + case _trayMenuLogout: + unawaited(client.logoutActive()); + case _trayMenuGithub: + unawaited(openExternalUrl(_githubUrl)); + case _trayMenuDownload: + unawaited(openExternalUrl(_downloadUrl)); + } + } + + Future _openTab(int index) async { + if (!_tabRequests.isClosed) { + _tabRequests.add(index); + } + await _showWindow(); + } + + Future _toggleSetting( + ClientSettings Function(ClientSettings) mutate, + ) async { + if (_settingsBusy) { + return; + } + final snapshot = _lastSnapshot; + if (snapshot == null) { + return; + } + _settingsBusy = true; + try { + await client.updateSettings(mutate(snapshot.settings)); + } finally { + _settingsBusy = false; + } + } + + Future _switchProfile(String name) async { + final snapshot = _lastSnapshot; + if (snapshot == null || snapshot.activeProfile.name == name) { + return; + } + await client.switchProfile(name); + } + + Future _showWindow() async { + await windowManager.show(); + await windowManager.focus(); + } + + Future _quit() async { + await dispose(); + await windowManager.setPreventClose(false); + await windowManager.destroy(); + } + + void _onSnapshot(ClientSnapshot snapshot) { + final previous = _lastSnapshot; + _lastSnapshot = snapshot; + if (previous == null || previous.status != snapshot.status) { + unawaited(_applyTrayIcon(snapshot.status)); + unawaited(trayManager.setToolTip('NetBird — ${snapshot.status.label}')); + } + unawaited(_refreshTrayMenu(snapshot)); + } + + void _onEvent(SystemNotification event) { + if (event.userMessage.isEmpty) { + return; + } + final notificationsEnabled = + _lastSnapshot?.settings.notifications ?? true; + final critical = event.severity == NotificationSeverity.critical; + if (!notificationsEnabled && !critical) { + return; + } + + final title = '${_severityPrefix(event.severity)} [${event.category.label}]'; + final body = event.id == null + ? event.userMessage + : '${event.userMessage} (id: ${event.id})'; + + unawaited( + LocalNotification(title: title, body: body).show(), + ); + } + + Future _applyTrayIcon(ConnectionStatus status) async { + final basename = switch (status) { + ConnectionStatus.connected => 'connected', + ConnectionStatus.connecting || + ConnectionStatus.awaitingLogin => 'connecting', + ConnectionStatus.error => 'error', + ConnectionStatus.disconnected => 'disconnected', + }; + final asset = Platform.isMacOS + ? 'assets/tray/$basename-macos.png' + : 'assets/tray/$basename.png'; + await trayManager.setIcon(asset, isTemplate: Platform.isMacOS); + } + + Future _refreshTrayMenu(ClientSnapshot? snapshot) async { + final key = _menuKey(snapshot); + if (key == _lastMenuKey) { + return; + } + _lastMenuKey = key; + + final connected = snapshot?.status == ConnectionStatus.connected; + final connecting = snapshot?.status == ConnectionStatus.connecting || + snapshot?.status == ConnectionStatus.awaitingLogin; + + final statusLabel = + snapshot?.status.label ?? ConnectionStatus.disconnected.label; + final settings = snapshot?.settings ?? const ClientSettings(); + final activeName = snapshot?.activeProfile.name ?? 'unknown'; + final email = snapshot?.activeProfile.email; + final daemonVersion = snapshot?.daemonVersion ?? 'unknown'; + + final profileItems = []; + final profiles = snapshot?.profiles ?? const []; + for (final profile in profiles) { + profileItems.add( + MenuItem.checkbox( + key: '$_profileSwitchPrefix${profile.name}', + label: profile.name, + checked: profile.active, + ), + ); + } + if (profileItems.isNotEmpty) { + profileItems.add(MenuItem.separator()); + } + profileItems + ..add(MenuItem(key: _trayMenuManageProfiles, label: 'Manage Profiles')) + ..add( + MenuItem( + key: _trayMenuLogout, + label: 'Deregister', + disabled: !connected, + ), + ); + + await trayManager.setContextMenu( + Menu( + items: [ + MenuItem(label: statusLabel, disabled: true), + MenuItem.submenu( + label: 'Profile: $activeName', + submenu: Menu(items: profileItems), + ), + if (email != null && email.isNotEmpty) + MenuItem(label: '($email)', disabled: true), + MenuItem.separator(), + MenuItem( + key: _trayMenuConnect, + label: 'Connect', + disabled: connected || connecting, + ), + MenuItem( + key: _trayMenuDisconnect, + label: 'Disconnect', + disabled: !connected, + ), + MenuItem.separator(), + MenuItem.submenu( + label: 'Settings', + submenu: Menu( + items: [ + MenuItem.checkbox( + key: _trayMenuAllowSSH, + label: 'Allow SSH', + checked: settings.allowSsh, + ), + MenuItem.checkbox( + key: _trayMenuAutoConnect, + label: 'Connect on Startup', + checked: settings.autoConnect, + ), + MenuItem.checkbox( + key: _trayMenuQuantum, + label: 'Enable Quantum-Resistance', + checked: settings.quantumResistance, + ), + MenuItem.checkbox( + key: _trayMenuLazy, + label: 'Enable Lazy Connections', + checked: settings.lazyConnection, + ), + MenuItem.checkbox( + key: _trayMenuBlockInbound, + label: 'Block Inbound Connections', + checked: settings.blockInbound, + ), + MenuItem.checkbox( + key: _trayMenuNotifications, + label: 'Notifications', + checked: settings.notifications, + ), + MenuItem.separator(), + MenuItem( + key: _trayMenuAdvancedSettings, + label: 'Advanced Settings', + ), + MenuItem( + key: _trayMenuDebugBundle, + label: 'Create Debug Bundle', + ), + ], + ), + ), + MenuItem(key: _trayMenuNetworks, label: 'Networks'), + MenuItem.separator(), + MenuItem.submenu( + label: 'About', + submenu: Menu( + items: [ + MenuItem(key: _trayMenuGithub, label: 'GitHub'), + MenuItem(label: 'GUI: $uiVersion', disabled: true), + MenuItem(label: 'Daemon: $daemonVersion', disabled: true), + MenuItem( + key: _trayMenuDownload, + label: 'Download latest version', + ), + ], + ), + ), + MenuItem.separator(), + MenuItem(key: _trayMenuShow, label: 'Show window'), + MenuItem(key: _trayMenuQuit, label: 'Quit'), + ], + ), + ); + } + + String _menuKey(ClientSnapshot? snapshot) { + if (snapshot == null) { + return 'null'; + } + final s = snapshot.settings; + final profiles = snapshot.profiles + .map((p) => '${p.name}:${p.active}:${p.email ?? ''}') + .join(','); + return [ + snapshot.status.name, + snapshot.activeProfile.name, + snapshot.activeProfile.email ?? '', + snapshot.daemonVersion, + profiles, + s.allowSsh, + s.autoConnect, + s.quantumResistance, + s.lazyConnection, + s.blockInbound, + s.notifications, + ].join('|'); + } + + String _severityPrefix(NotificationSeverity severity) { + return switch (severity) { + NotificationSeverity.critical => 'Critical', + NotificationSeverity.error => 'Error', + NotificationSeverity.warning => 'Warning', + NotificationSeverity.info => 'Info', + }; + } +} diff --git a/client/flutter_ui/lib/src/generated/daemon.pb.dart b/client/flutter_ui/lib/src/generated/daemon.pb.dart new file mode 100644 index 000000000..57aa33f7c --- /dev/null +++ b/client/flutter_ui/lib/src/generated/daemon.pb.dart @@ -0,0 +1,7393 @@ +// This is a generated file - do not edit. +// +// Generated from daemon.proto. + +// @dart = 3.3 + +// ignore_for_file: annotate_overrides, camel_case_types, comment_references +// ignore_for_file: constant_identifier_names +// ignore_for_file: curly_braces_in_flow_control_structures +// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes +// ignore_for_file: non_constant_identifier_names, prefer_relative_imports + +import 'dart:core' as $core; + +import 'package:fixnum/fixnum.dart' as $fixnum; +import 'package:protobuf/protobuf.dart' as $pb; +import 'package:protobuf/well_known_types/google/protobuf/duration.pb.dart' + as $1; +import 'package:protobuf/well_known_types/google/protobuf/timestamp.pb.dart' + as $2; + +import 'daemon.pbenum.dart'; + +export 'package:protobuf/protobuf.dart' show GeneratedMessageGenericExtensions; + +export 'daemon.pbenum.dart'; + +class EmptyRequest extends $pb.GeneratedMessage { + factory EmptyRequest() => create(); + + EmptyRequest._(); + + factory EmptyRequest.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory EmptyRequest.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'EmptyRequest', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + EmptyRequest clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + EmptyRequest copyWith(void Function(EmptyRequest) updates) => + super.copyWith((message) => updates(message as EmptyRequest)) + as EmptyRequest; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static EmptyRequest create() => EmptyRequest._(); + @$core.override + EmptyRequest createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static EmptyRequest getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static EmptyRequest? _defaultInstance; +} + +class OSLifecycleRequest extends $pb.GeneratedMessage { + factory OSLifecycleRequest({ + OSLifecycleRequest_CycleType? type, + }) { + final result = create(); + if (type != null) result.type = type; + return result; + } + + OSLifecycleRequest._(); + + factory OSLifecycleRequest.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory OSLifecycleRequest.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'OSLifecycleRequest', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..aE(1, _omitFieldNames ? '' : 'type', + enumValues: OSLifecycleRequest_CycleType.values) + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + OSLifecycleRequest clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + OSLifecycleRequest copyWith(void Function(OSLifecycleRequest) updates) => + super.copyWith((message) => updates(message as OSLifecycleRequest)) + as OSLifecycleRequest; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static OSLifecycleRequest create() => OSLifecycleRequest._(); + @$core.override + OSLifecycleRequest createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static OSLifecycleRequest getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static OSLifecycleRequest? _defaultInstance; + + @$pb.TagNumber(1) + OSLifecycleRequest_CycleType get type => $_getN(0); + @$pb.TagNumber(1) + set type(OSLifecycleRequest_CycleType value) => $_setField(1, value); + @$pb.TagNumber(1) + $core.bool hasType() => $_has(0); + @$pb.TagNumber(1) + void clearType() => $_clearField(1); +} + +class OSLifecycleResponse extends $pb.GeneratedMessage { + factory OSLifecycleResponse() => create(); + + OSLifecycleResponse._(); + + factory OSLifecycleResponse.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory OSLifecycleResponse.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'OSLifecycleResponse', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + OSLifecycleResponse clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + OSLifecycleResponse copyWith(void Function(OSLifecycleResponse) updates) => + super.copyWith((message) => updates(message as OSLifecycleResponse)) + as OSLifecycleResponse; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static OSLifecycleResponse create() => OSLifecycleResponse._(); + @$core.override + OSLifecycleResponse createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static OSLifecycleResponse getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static OSLifecycleResponse? _defaultInstance; +} + +class LoginRequest extends $pb.GeneratedMessage { + factory LoginRequest({ + $core.String? setupKey, + @$core.Deprecated('This field is deprecated.') $core.String? preSharedKey, + $core.String? managementUrl, + $core.String? adminURL, + $core.Iterable<$core.String>? natExternalIPs, + $core.bool? cleanNATExternalIPs, + $core.List<$core.int>? customDNSAddress, + $core.bool? isUnixDesktopClient, + $core.String? hostname, + $core.bool? rosenpassEnabled, + $core.String? interfaceName, + $fixnum.Int64? wireguardPort, + $core.String? optionalPreSharedKey, + $core.bool? disableAutoConnect, + $core.bool? serverSSHAllowed, + $core.bool? rosenpassPermissive, + $core.Iterable<$core.String>? extraIFaceBlacklist, + $core.bool? networkMonitor, + $1.Duration? dnsRouteInterval, + $core.bool? disableClientRoutes, + $core.bool? disableServerRoutes, + $core.bool? disableDns, + $core.bool? disableFirewall, + $core.bool? blockLanAccess, + $core.bool? disableNotifications, + $core.Iterable<$core.String>? dnsLabels, + $core.bool? cleanDNSLabels, + $core.bool? lazyConnectionEnabled, + $core.bool? blockInbound, + $core.String? profileName, + $core.String? username, + $fixnum.Int64? mtu, + $core.String? hint, + $core.bool? enableSSHRoot, + $core.bool? enableSSHSFTP, + $core.bool? enableSSHLocalPortForwarding, + $core.bool? enableSSHRemotePortForwarding, + $core.bool? disableSSHAuth, + $core.int? sshJWTCacheTTL, + }) { + final result = create(); + if (setupKey != null) result.setupKey = setupKey; + if (preSharedKey != null) result.preSharedKey = preSharedKey; + if (managementUrl != null) result.managementUrl = managementUrl; + if (adminURL != null) result.adminURL = adminURL; + if (natExternalIPs != null) result.natExternalIPs.addAll(natExternalIPs); + if (cleanNATExternalIPs != null) + result.cleanNATExternalIPs = cleanNATExternalIPs; + if (customDNSAddress != null) result.customDNSAddress = customDNSAddress; + if (isUnixDesktopClient != null) + result.isUnixDesktopClient = isUnixDesktopClient; + if (hostname != null) result.hostname = hostname; + if (rosenpassEnabled != null) result.rosenpassEnabled = rosenpassEnabled; + if (interfaceName != null) result.interfaceName = interfaceName; + if (wireguardPort != null) result.wireguardPort = wireguardPort; + if (optionalPreSharedKey != null) + result.optionalPreSharedKey = optionalPreSharedKey; + if (disableAutoConnect != null) + result.disableAutoConnect = disableAutoConnect; + if (serverSSHAllowed != null) result.serverSSHAllowed = serverSSHAllowed; + if (rosenpassPermissive != null) + result.rosenpassPermissive = rosenpassPermissive; + if (extraIFaceBlacklist != null) + result.extraIFaceBlacklist.addAll(extraIFaceBlacklist); + if (networkMonitor != null) result.networkMonitor = networkMonitor; + if (dnsRouteInterval != null) result.dnsRouteInterval = dnsRouteInterval; + if (disableClientRoutes != null) + result.disableClientRoutes = disableClientRoutes; + if (disableServerRoutes != null) + result.disableServerRoutes = disableServerRoutes; + if (disableDns != null) result.disableDns = disableDns; + if (disableFirewall != null) result.disableFirewall = disableFirewall; + if (blockLanAccess != null) result.blockLanAccess = blockLanAccess; + if (disableNotifications != null) + result.disableNotifications = disableNotifications; + if (dnsLabels != null) result.dnsLabels.addAll(dnsLabels); + if (cleanDNSLabels != null) result.cleanDNSLabels = cleanDNSLabels; + if (lazyConnectionEnabled != null) + result.lazyConnectionEnabled = lazyConnectionEnabled; + if (blockInbound != null) result.blockInbound = blockInbound; + if (profileName != null) result.profileName = profileName; + if (username != null) result.username = username; + if (mtu != null) result.mtu = mtu; + if (hint != null) result.hint = hint; + if (enableSSHRoot != null) result.enableSSHRoot = enableSSHRoot; + if (enableSSHSFTP != null) result.enableSSHSFTP = enableSSHSFTP; + if (enableSSHLocalPortForwarding != null) + result.enableSSHLocalPortForwarding = enableSSHLocalPortForwarding; + if (enableSSHRemotePortForwarding != null) + result.enableSSHRemotePortForwarding = enableSSHRemotePortForwarding; + if (disableSSHAuth != null) result.disableSSHAuth = disableSSHAuth; + if (sshJWTCacheTTL != null) result.sshJWTCacheTTL = sshJWTCacheTTL; + return result; + } + + LoginRequest._(); + + factory LoginRequest.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory LoginRequest.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'LoginRequest', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..aOS(1, _omitFieldNames ? '' : 'setupKey', protoName: 'setupKey') + ..aOS(2, _omitFieldNames ? '' : 'preSharedKey', protoName: 'preSharedKey') + ..aOS(3, _omitFieldNames ? '' : 'managementUrl', protoName: 'managementUrl') + ..aOS(4, _omitFieldNames ? '' : 'adminURL', protoName: 'adminURL') + ..pPS(5, _omitFieldNames ? '' : 'natExternalIPs', + protoName: 'natExternalIPs') + ..aOB(6, _omitFieldNames ? '' : 'cleanNATExternalIPs', + protoName: 'cleanNATExternalIPs') + ..a<$core.List<$core.int>>( + 7, _omitFieldNames ? '' : 'customDNSAddress', $pb.PbFieldType.OY, + protoName: 'customDNSAddress') + ..aOB(8, _omitFieldNames ? '' : 'isUnixDesktopClient', + protoName: 'isUnixDesktopClient') + ..aOS(9, _omitFieldNames ? '' : 'hostname') + ..aOB(10, _omitFieldNames ? '' : 'rosenpassEnabled', + protoName: 'rosenpassEnabled') + ..aOS(11, _omitFieldNames ? '' : 'interfaceName', + protoName: 'interfaceName') + ..aInt64(12, _omitFieldNames ? '' : 'wireguardPort', + protoName: 'wireguardPort') + ..aOS(13, _omitFieldNames ? '' : 'optionalPreSharedKey', + protoName: 'optionalPreSharedKey') + ..aOB(14, _omitFieldNames ? '' : 'disableAutoConnect', + protoName: 'disableAutoConnect') + ..aOB(15, _omitFieldNames ? '' : 'serverSSHAllowed', + protoName: 'serverSSHAllowed') + ..aOB(16, _omitFieldNames ? '' : 'rosenpassPermissive', + protoName: 'rosenpassPermissive') + ..pPS(17, _omitFieldNames ? '' : 'extraIFaceBlacklist', + protoName: 'extraIFaceBlacklist') + ..aOB(18, _omitFieldNames ? '' : 'networkMonitor', + protoName: 'networkMonitor') + ..aOM<$1.Duration>(19, _omitFieldNames ? '' : 'dnsRouteInterval', + protoName: 'dnsRouteInterval', subBuilder: $1.Duration.create) + ..aOB(20, _omitFieldNames ? '' : 'disableClientRoutes') + ..aOB(21, _omitFieldNames ? '' : 'disableServerRoutes') + ..aOB(22, _omitFieldNames ? '' : 'disableDns') + ..aOB(23, _omitFieldNames ? '' : 'disableFirewall') + ..aOB(24, _omitFieldNames ? '' : 'blockLanAccess') + ..aOB(25, _omitFieldNames ? '' : 'disableNotifications') + ..pPS(26, _omitFieldNames ? '' : 'dnsLabels') + ..aOB(27, _omitFieldNames ? '' : 'cleanDNSLabels', + protoName: 'cleanDNSLabels') + ..aOB(28, _omitFieldNames ? '' : 'lazyConnectionEnabled', + protoName: 'lazyConnectionEnabled') + ..aOB(29, _omitFieldNames ? '' : 'blockInbound') + ..aOS(30, _omitFieldNames ? '' : 'profileName', protoName: 'profileName') + ..aOS(31, _omitFieldNames ? '' : 'username') + ..aInt64(32, _omitFieldNames ? '' : 'mtu') + ..aOS(33, _omitFieldNames ? '' : 'hint') + ..aOB(34, _omitFieldNames ? '' : 'enableSSHRoot', + protoName: 'enableSSHRoot') + ..aOB(35, _omitFieldNames ? '' : 'enableSSHSFTP', + protoName: 'enableSSHSFTP') + ..aOB(36, _omitFieldNames ? '' : 'enableSSHLocalPortForwarding', + protoName: 'enableSSHLocalPortForwarding') + ..aOB(37, _omitFieldNames ? '' : 'enableSSHRemotePortForwarding', + protoName: 'enableSSHRemotePortForwarding') + ..aOB(38, _omitFieldNames ? '' : 'disableSSHAuth', + protoName: 'disableSSHAuth') + ..aI(39, _omitFieldNames ? '' : 'sshJWTCacheTTL', + protoName: 'sshJWTCacheTTL') + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + LoginRequest clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + LoginRequest copyWith(void Function(LoginRequest) updates) => + super.copyWith((message) => updates(message as LoginRequest)) + as LoginRequest; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static LoginRequest create() => LoginRequest._(); + @$core.override + LoginRequest createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static LoginRequest getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static LoginRequest? _defaultInstance; + + /// setupKey netbird setup key. + @$pb.TagNumber(1) + $core.String get setupKey => $_getSZ(0); + @$pb.TagNumber(1) + set setupKey($core.String value) => $_setString(0, value); + @$pb.TagNumber(1) + $core.bool hasSetupKey() => $_has(0); + @$pb.TagNumber(1) + void clearSetupKey() => $_clearField(1); + + /// This is the old PreSharedKey field which will be deprecated in favor of optionalPreSharedKey field that is defined as optional + /// to allow clearing of preshared key while being able to persist in the config file. + @$core.Deprecated('This field is deprecated.') + @$pb.TagNumber(2) + $core.String get preSharedKey => $_getSZ(1); + @$core.Deprecated('This field is deprecated.') + @$pb.TagNumber(2) + set preSharedKey($core.String value) => $_setString(1, value); + @$core.Deprecated('This field is deprecated.') + @$pb.TagNumber(2) + $core.bool hasPreSharedKey() => $_has(1); + @$core.Deprecated('This field is deprecated.') + @$pb.TagNumber(2) + void clearPreSharedKey() => $_clearField(2); + + /// managementUrl to authenticate. + @$pb.TagNumber(3) + $core.String get managementUrl => $_getSZ(2); + @$pb.TagNumber(3) + set managementUrl($core.String value) => $_setString(2, value); + @$pb.TagNumber(3) + $core.bool hasManagementUrl() => $_has(2); + @$pb.TagNumber(3) + void clearManagementUrl() => $_clearField(3); + + /// adminUrl to manage keys. + @$pb.TagNumber(4) + $core.String get adminURL => $_getSZ(3); + @$pb.TagNumber(4) + set adminURL($core.String value) => $_setString(3, value); + @$pb.TagNumber(4) + $core.bool hasAdminURL() => $_has(3); + @$pb.TagNumber(4) + void clearAdminURL() => $_clearField(4); + + /// natExternalIPs map list of external IPs + @$pb.TagNumber(5) + $pb.PbList<$core.String> get natExternalIPs => $_getList(4); + + /// cleanNATExternalIPs clean map list of external IPs. + /// This is needed because the generated code + /// omits initialized empty slices due to omitempty tags + @$pb.TagNumber(6) + $core.bool get cleanNATExternalIPs => $_getBF(5); + @$pb.TagNumber(6) + set cleanNATExternalIPs($core.bool value) => $_setBool(5, value); + @$pb.TagNumber(6) + $core.bool hasCleanNATExternalIPs() => $_has(5); + @$pb.TagNumber(6) + void clearCleanNATExternalIPs() => $_clearField(6); + + @$pb.TagNumber(7) + $core.List<$core.int> get customDNSAddress => $_getN(6); + @$pb.TagNumber(7) + set customDNSAddress($core.List<$core.int> value) => $_setBytes(6, value); + @$pb.TagNumber(7) + $core.bool hasCustomDNSAddress() => $_has(6); + @$pb.TagNumber(7) + void clearCustomDNSAddress() => $_clearField(7); + + @$pb.TagNumber(8) + $core.bool get isUnixDesktopClient => $_getBF(7); + @$pb.TagNumber(8) + set isUnixDesktopClient($core.bool value) => $_setBool(7, value); + @$pb.TagNumber(8) + $core.bool hasIsUnixDesktopClient() => $_has(7); + @$pb.TagNumber(8) + void clearIsUnixDesktopClient() => $_clearField(8); + + @$pb.TagNumber(9) + $core.String get hostname => $_getSZ(8); + @$pb.TagNumber(9) + set hostname($core.String value) => $_setString(8, value); + @$pb.TagNumber(9) + $core.bool hasHostname() => $_has(8); + @$pb.TagNumber(9) + void clearHostname() => $_clearField(9); + + @$pb.TagNumber(10) + $core.bool get rosenpassEnabled => $_getBF(9); + @$pb.TagNumber(10) + set rosenpassEnabled($core.bool value) => $_setBool(9, value); + @$pb.TagNumber(10) + $core.bool hasRosenpassEnabled() => $_has(9); + @$pb.TagNumber(10) + void clearRosenpassEnabled() => $_clearField(10); + + @$pb.TagNumber(11) + $core.String get interfaceName => $_getSZ(10); + @$pb.TagNumber(11) + set interfaceName($core.String value) => $_setString(10, value); + @$pb.TagNumber(11) + $core.bool hasInterfaceName() => $_has(10); + @$pb.TagNumber(11) + void clearInterfaceName() => $_clearField(11); + + @$pb.TagNumber(12) + $fixnum.Int64 get wireguardPort => $_getI64(11); + @$pb.TagNumber(12) + set wireguardPort($fixnum.Int64 value) => $_setInt64(11, value); + @$pb.TagNumber(12) + $core.bool hasWireguardPort() => $_has(11); + @$pb.TagNumber(12) + void clearWireguardPort() => $_clearField(12); + + @$pb.TagNumber(13) + $core.String get optionalPreSharedKey => $_getSZ(12); + @$pb.TagNumber(13) + set optionalPreSharedKey($core.String value) => $_setString(12, value); + @$pb.TagNumber(13) + $core.bool hasOptionalPreSharedKey() => $_has(12); + @$pb.TagNumber(13) + void clearOptionalPreSharedKey() => $_clearField(13); + + @$pb.TagNumber(14) + $core.bool get disableAutoConnect => $_getBF(13); + @$pb.TagNumber(14) + set disableAutoConnect($core.bool value) => $_setBool(13, value); + @$pb.TagNumber(14) + $core.bool hasDisableAutoConnect() => $_has(13); + @$pb.TagNumber(14) + void clearDisableAutoConnect() => $_clearField(14); + + @$pb.TagNumber(15) + $core.bool get serverSSHAllowed => $_getBF(14); + @$pb.TagNumber(15) + set serverSSHAllowed($core.bool value) => $_setBool(14, value); + @$pb.TagNumber(15) + $core.bool hasServerSSHAllowed() => $_has(14); + @$pb.TagNumber(15) + void clearServerSSHAllowed() => $_clearField(15); + + @$pb.TagNumber(16) + $core.bool get rosenpassPermissive => $_getBF(15); + @$pb.TagNumber(16) + set rosenpassPermissive($core.bool value) => $_setBool(15, value); + @$pb.TagNumber(16) + $core.bool hasRosenpassPermissive() => $_has(15); + @$pb.TagNumber(16) + void clearRosenpassPermissive() => $_clearField(16); + + @$pb.TagNumber(17) + $pb.PbList<$core.String> get extraIFaceBlacklist => $_getList(16); + + @$pb.TagNumber(18) + $core.bool get networkMonitor => $_getBF(17); + @$pb.TagNumber(18) + set networkMonitor($core.bool value) => $_setBool(17, value); + @$pb.TagNumber(18) + $core.bool hasNetworkMonitor() => $_has(17); + @$pb.TagNumber(18) + void clearNetworkMonitor() => $_clearField(18); + + @$pb.TagNumber(19) + $1.Duration get dnsRouteInterval => $_getN(18); + @$pb.TagNumber(19) + set dnsRouteInterval($1.Duration value) => $_setField(19, value); + @$pb.TagNumber(19) + $core.bool hasDnsRouteInterval() => $_has(18); + @$pb.TagNumber(19) + void clearDnsRouteInterval() => $_clearField(19); + @$pb.TagNumber(19) + $1.Duration ensureDnsRouteInterval() => $_ensure(18); + + @$pb.TagNumber(20) + $core.bool get disableClientRoutes => $_getBF(19); + @$pb.TagNumber(20) + set disableClientRoutes($core.bool value) => $_setBool(19, value); + @$pb.TagNumber(20) + $core.bool hasDisableClientRoutes() => $_has(19); + @$pb.TagNumber(20) + void clearDisableClientRoutes() => $_clearField(20); + + @$pb.TagNumber(21) + $core.bool get disableServerRoutes => $_getBF(20); + @$pb.TagNumber(21) + set disableServerRoutes($core.bool value) => $_setBool(20, value); + @$pb.TagNumber(21) + $core.bool hasDisableServerRoutes() => $_has(20); + @$pb.TagNumber(21) + void clearDisableServerRoutes() => $_clearField(21); + + @$pb.TagNumber(22) + $core.bool get disableDns => $_getBF(21); + @$pb.TagNumber(22) + set disableDns($core.bool value) => $_setBool(21, value); + @$pb.TagNumber(22) + $core.bool hasDisableDns() => $_has(21); + @$pb.TagNumber(22) + void clearDisableDns() => $_clearField(22); + + @$pb.TagNumber(23) + $core.bool get disableFirewall => $_getBF(22); + @$pb.TagNumber(23) + set disableFirewall($core.bool value) => $_setBool(22, value); + @$pb.TagNumber(23) + $core.bool hasDisableFirewall() => $_has(22); + @$pb.TagNumber(23) + void clearDisableFirewall() => $_clearField(23); + + @$pb.TagNumber(24) + $core.bool get blockLanAccess => $_getBF(23); + @$pb.TagNumber(24) + set blockLanAccess($core.bool value) => $_setBool(23, value); + @$pb.TagNumber(24) + $core.bool hasBlockLanAccess() => $_has(23); + @$pb.TagNumber(24) + void clearBlockLanAccess() => $_clearField(24); + + @$pb.TagNumber(25) + $core.bool get disableNotifications => $_getBF(24); + @$pb.TagNumber(25) + set disableNotifications($core.bool value) => $_setBool(24, value); + @$pb.TagNumber(25) + $core.bool hasDisableNotifications() => $_has(24); + @$pb.TagNumber(25) + void clearDisableNotifications() => $_clearField(25); + + @$pb.TagNumber(26) + $pb.PbList<$core.String> get dnsLabels => $_getList(25); + + /// cleanDNSLabels clean map list of DNS labels. + /// This is needed because the generated code + /// omits initialized empty slices due to omitempty tags + @$pb.TagNumber(27) + $core.bool get cleanDNSLabels => $_getBF(26); + @$pb.TagNumber(27) + set cleanDNSLabels($core.bool value) => $_setBool(26, value); + @$pb.TagNumber(27) + $core.bool hasCleanDNSLabels() => $_has(26); + @$pb.TagNumber(27) + void clearCleanDNSLabels() => $_clearField(27); + + @$pb.TagNumber(28) + $core.bool get lazyConnectionEnabled => $_getBF(27); + @$pb.TagNumber(28) + set lazyConnectionEnabled($core.bool value) => $_setBool(27, value); + @$pb.TagNumber(28) + $core.bool hasLazyConnectionEnabled() => $_has(27); + @$pb.TagNumber(28) + void clearLazyConnectionEnabled() => $_clearField(28); + + @$pb.TagNumber(29) + $core.bool get blockInbound => $_getBF(28); + @$pb.TagNumber(29) + set blockInbound($core.bool value) => $_setBool(28, value); + @$pb.TagNumber(29) + $core.bool hasBlockInbound() => $_has(28); + @$pb.TagNumber(29) + void clearBlockInbound() => $_clearField(29); + + @$pb.TagNumber(30) + $core.String get profileName => $_getSZ(29); + @$pb.TagNumber(30) + set profileName($core.String value) => $_setString(29, value); + @$pb.TagNumber(30) + $core.bool hasProfileName() => $_has(29); + @$pb.TagNumber(30) + void clearProfileName() => $_clearField(30); + + @$pb.TagNumber(31) + $core.String get username => $_getSZ(30); + @$pb.TagNumber(31) + set username($core.String value) => $_setString(30, value); + @$pb.TagNumber(31) + $core.bool hasUsername() => $_has(30); + @$pb.TagNumber(31) + void clearUsername() => $_clearField(31); + + @$pb.TagNumber(32) + $fixnum.Int64 get mtu => $_getI64(31); + @$pb.TagNumber(32) + set mtu($fixnum.Int64 value) => $_setInt64(31, value); + @$pb.TagNumber(32) + $core.bool hasMtu() => $_has(31); + @$pb.TagNumber(32) + void clearMtu() => $_clearField(32); + + /// hint is used to pre-fill the email/username field during SSO authentication + @$pb.TagNumber(33) + $core.String get hint => $_getSZ(32); + @$pb.TagNumber(33) + set hint($core.String value) => $_setString(32, value); + @$pb.TagNumber(33) + $core.bool hasHint() => $_has(32); + @$pb.TagNumber(33) + void clearHint() => $_clearField(33); + + @$pb.TagNumber(34) + $core.bool get enableSSHRoot => $_getBF(33); + @$pb.TagNumber(34) + set enableSSHRoot($core.bool value) => $_setBool(33, value); + @$pb.TagNumber(34) + $core.bool hasEnableSSHRoot() => $_has(33); + @$pb.TagNumber(34) + void clearEnableSSHRoot() => $_clearField(34); + + @$pb.TagNumber(35) + $core.bool get enableSSHSFTP => $_getBF(34); + @$pb.TagNumber(35) + set enableSSHSFTP($core.bool value) => $_setBool(34, value); + @$pb.TagNumber(35) + $core.bool hasEnableSSHSFTP() => $_has(34); + @$pb.TagNumber(35) + void clearEnableSSHSFTP() => $_clearField(35); + + @$pb.TagNumber(36) + $core.bool get enableSSHLocalPortForwarding => $_getBF(35); + @$pb.TagNumber(36) + set enableSSHLocalPortForwarding($core.bool value) => $_setBool(35, value); + @$pb.TagNumber(36) + $core.bool hasEnableSSHLocalPortForwarding() => $_has(35); + @$pb.TagNumber(36) + void clearEnableSSHLocalPortForwarding() => $_clearField(36); + + @$pb.TagNumber(37) + $core.bool get enableSSHRemotePortForwarding => $_getBF(36); + @$pb.TagNumber(37) + set enableSSHRemotePortForwarding($core.bool value) => $_setBool(36, value); + @$pb.TagNumber(37) + $core.bool hasEnableSSHRemotePortForwarding() => $_has(36); + @$pb.TagNumber(37) + void clearEnableSSHRemotePortForwarding() => $_clearField(37); + + @$pb.TagNumber(38) + $core.bool get disableSSHAuth => $_getBF(37); + @$pb.TagNumber(38) + set disableSSHAuth($core.bool value) => $_setBool(37, value); + @$pb.TagNumber(38) + $core.bool hasDisableSSHAuth() => $_has(37); + @$pb.TagNumber(38) + void clearDisableSSHAuth() => $_clearField(38); + + @$pb.TagNumber(39) + $core.int get sshJWTCacheTTL => $_getIZ(38); + @$pb.TagNumber(39) + set sshJWTCacheTTL($core.int value) => $_setSignedInt32(38, value); + @$pb.TagNumber(39) + $core.bool hasSshJWTCacheTTL() => $_has(38); + @$pb.TagNumber(39) + void clearSshJWTCacheTTL() => $_clearField(39); +} + +class LoginResponse extends $pb.GeneratedMessage { + factory LoginResponse({ + $core.bool? needsSSOLogin, + $core.String? userCode, + $core.String? verificationURI, + $core.String? verificationURIComplete, + }) { + final result = create(); + if (needsSSOLogin != null) result.needsSSOLogin = needsSSOLogin; + if (userCode != null) result.userCode = userCode; + if (verificationURI != null) result.verificationURI = verificationURI; + if (verificationURIComplete != null) + result.verificationURIComplete = verificationURIComplete; + return result; + } + + LoginResponse._(); + + factory LoginResponse.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory LoginResponse.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'LoginResponse', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..aOB(1, _omitFieldNames ? '' : 'needsSSOLogin', protoName: 'needsSSOLogin') + ..aOS(2, _omitFieldNames ? '' : 'userCode', protoName: 'userCode') + ..aOS(3, _omitFieldNames ? '' : 'verificationURI', + protoName: 'verificationURI') + ..aOS(4, _omitFieldNames ? '' : 'verificationURIComplete', + protoName: 'verificationURIComplete') + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + LoginResponse clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + LoginResponse copyWith(void Function(LoginResponse) updates) => + super.copyWith((message) => updates(message as LoginResponse)) + as LoginResponse; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static LoginResponse create() => LoginResponse._(); + @$core.override + LoginResponse createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static LoginResponse getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static LoginResponse? _defaultInstance; + + @$pb.TagNumber(1) + $core.bool get needsSSOLogin => $_getBF(0); + @$pb.TagNumber(1) + set needsSSOLogin($core.bool value) => $_setBool(0, value); + @$pb.TagNumber(1) + $core.bool hasNeedsSSOLogin() => $_has(0); + @$pb.TagNumber(1) + void clearNeedsSSOLogin() => $_clearField(1); + + @$pb.TagNumber(2) + $core.String get userCode => $_getSZ(1); + @$pb.TagNumber(2) + set userCode($core.String value) => $_setString(1, value); + @$pb.TagNumber(2) + $core.bool hasUserCode() => $_has(1); + @$pb.TagNumber(2) + void clearUserCode() => $_clearField(2); + + @$pb.TagNumber(3) + $core.String get verificationURI => $_getSZ(2); + @$pb.TagNumber(3) + set verificationURI($core.String value) => $_setString(2, value); + @$pb.TagNumber(3) + $core.bool hasVerificationURI() => $_has(2); + @$pb.TagNumber(3) + void clearVerificationURI() => $_clearField(3); + + @$pb.TagNumber(4) + $core.String get verificationURIComplete => $_getSZ(3); + @$pb.TagNumber(4) + set verificationURIComplete($core.String value) => $_setString(3, value); + @$pb.TagNumber(4) + $core.bool hasVerificationURIComplete() => $_has(3); + @$pb.TagNumber(4) + void clearVerificationURIComplete() => $_clearField(4); +} + +class WaitSSOLoginRequest extends $pb.GeneratedMessage { + factory WaitSSOLoginRequest({ + $core.String? userCode, + $core.String? hostname, + }) { + final result = create(); + if (userCode != null) result.userCode = userCode; + if (hostname != null) result.hostname = hostname; + return result; + } + + WaitSSOLoginRequest._(); + + factory WaitSSOLoginRequest.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory WaitSSOLoginRequest.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'WaitSSOLoginRequest', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..aOS(1, _omitFieldNames ? '' : 'userCode', protoName: 'userCode') + ..aOS(2, _omitFieldNames ? '' : 'hostname') + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + WaitSSOLoginRequest clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + WaitSSOLoginRequest copyWith(void Function(WaitSSOLoginRequest) updates) => + super.copyWith((message) => updates(message as WaitSSOLoginRequest)) + as WaitSSOLoginRequest; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static WaitSSOLoginRequest create() => WaitSSOLoginRequest._(); + @$core.override + WaitSSOLoginRequest createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static WaitSSOLoginRequest getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static WaitSSOLoginRequest? _defaultInstance; + + @$pb.TagNumber(1) + $core.String get userCode => $_getSZ(0); + @$pb.TagNumber(1) + set userCode($core.String value) => $_setString(0, value); + @$pb.TagNumber(1) + $core.bool hasUserCode() => $_has(0); + @$pb.TagNumber(1) + void clearUserCode() => $_clearField(1); + + @$pb.TagNumber(2) + $core.String get hostname => $_getSZ(1); + @$pb.TagNumber(2) + set hostname($core.String value) => $_setString(1, value); + @$pb.TagNumber(2) + $core.bool hasHostname() => $_has(1); + @$pb.TagNumber(2) + void clearHostname() => $_clearField(2); +} + +class WaitSSOLoginResponse extends $pb.GeneratedMessage { + factory WaitSSOLoginResponse({ + $core.String? email, + }) { + final result = create(); + if (email != null) result.email = email; + return result; + } + + WaitSSOLoginResponse._(); + + factory WaitSSOLoginResponse.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory WaitSSOLoginResponse.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'WaitSSOLoginResponse', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..aOS(1, _omitFieldNames ? '' : 'email') + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + WaitSSOLoginResponse clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + WaitSSOLoginResponse copyWith(void Function(WaitSSOLoginResponse) updates) => + super.copyWith((message) => updates(message as WaitSSOLoginResponse)) + as WaitSSOLoginResponse; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static WaitSSOLoginResponse create() => WaitSSOLoginResponse._(); + @$core.override + WaitSSOLoginResponse createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static WaitSSOLoginResponse getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static WaitSSOLoginResponse? _defaultInstance; + + @$pb.TagNumber(1) + $core.String get email => $_getSZ(0); + @$pb.TagNumber(1) + set email($core.String value) => $_setString(0, value); + @$pb.TagNumber(1) + $core.bool hasEmail() => $_has(0); + @$pb.TagNumber(1) + void clearEmail() => $_clearField(1); +} + +class UpRequest extends $pb.GeneratedMessage { + factory UpRequest({ + $core.String? profileName, + $core.String? username, + }) { + final result = create(); + if (profileName != null) result.profileName = profileName; + if (username != null) result.username = username; + return result; + } + + UpRequest._(); + + factory UpRequest.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory UpRequest.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'UpRequest', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..aOS(1, _omitFieldNames ? '' : 'profileName', protoName: 'profileName') + ..aOS(2, _omitFieldNames ? '' : 'username') + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + UpRequest clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + UpRequest copyWith(void Function(UpRequest) updates) => + super.copyWith((message) => updates(message as UpRequest)) as UpRequest; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static UpRequest create() => UpRequest._(); + @$core.override + UpRequest createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static UpRequest getDefault() => + _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static UpRequest? _defaultInstance; + + @$pb.TagNumber(1) + $core.String get profileName => $_getSZ(0); + @$pb.TagNumber(1) + set profileName($core.String value) => $_setString(0, value); + @$pb.TagNumber(1) + $core.bool hasProfileName() => $_has(0); + @$pb.TagNumber(1) + void clearProfileName() => $_clearField(1); + + @$pb.TagNumber(2) + $core.String get username => $_getSZ(1); + @$pb.TagNumber(2) + set username($core.String value) => $_setString(1, value); + @$pb.TagNumber(2) + $core.bool hasUsername() => $_has(1); + @$pb.TagNumber(2) + void clearUsername() => $_clearField(2); +} + +class UpResponse extends $pb.GeneratedMessage { + factory UpResponse() => create(); + + UpResponse._(); + + factory UpResponse.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory UpResponse.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'UpResponse', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + UpResponse clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + UpResponse copyWith(void Function(UpResponse) updates) => + super.copyWith((message) => updates(message as UpResponse)) as UpResponse; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static UpResponse create() => UpResponse._(); + @$core.override + UpResponse createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static UpResponse getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static UpResponse? _defaultInstance; +} + +class StatusRequest extends $pb.GeneratedMessage { + factory StatusRequest({ + $core.bool? getFullPeerStatus, + $core.bool? shouldRunProbes, + $core.bool? waitForReady, + }) { + final result = create(); + if (getFullPeerStatus != null) result.getFullPeerStatus = getFullPeerStatus; + if (shouldRunProbes != null) result.shouldRunProbes = shouldRunProbes; + if (waitForReady != null) result.waitForReady = waitForReady; + return result; + } + + StatusRequest._(); + + factory StatusRequest.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory StatusRequest.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'StatusRequest', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..aOB(1, _omitFieldNames ? '' : 'getFullPeerStatus', + protoName: 'getFullPeerStatus') + ..aOB(2, _omitFieldNames ? '' : 'shouldRunProbes', + protoName: 'shouldRunProbes') + ..aOB(3, _omitFieldNames ? '' : 'waitForReady', protoName: 'waitForReady') + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + StatusRequest clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + StatusRequest copyWith(void Function(StatusRequest) updates) => + super.copyWith((message) => updates(message as StatusRequest)) + as StatusRequest; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static StatusRequest create() => StatusRequest._(); + @$core.override + StatusRequest createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static StatusRequest getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static StatusRequest? _defaultInstance; + + @$pb.TagNumber(1) + $core.bool get getFullPeerStatus => $_getBF(0); + @$pb.TagNumber(1) + set getFullPeerStatus($core.bool value) => $_setBool(0, value); + @$pb.TagNumber(1) + $core.bool hasGetFullPeerStatus() => $_has(0); + @$pb.TagNumber(1) + void clearGetFullPeerStatus() => $_clearField(1); + + @$pb.TagNumber(2) + $core.bool get shouldRunProbes => $_getBF(1); + @$pb.TagNumber(2) + set shouldRunProbes($core.bool value) => $_setBool(1, value); + @$pb.TagNumber(2) + $core.bool hasShouldRunProbes() => $_has(1); + @$pb.TagNumber(2) + void clearShouldRunProbes() => $_clearField(2); + + /// the UI do not using this yet, but CLIs could use it to wait until the status is ready + @$pb.TagNumber(3) + $core.bool get waitForReady => $_getBF(2); + @$pb.TagNumber(3) + set waitForReady($core.bool value) => $_setBool(2, value); + @$pb.TagNumber(3) + $core.bool hasWaitForReady() => $_has(2); + @$pb.TagNumber(3) + void clearWaitForReady() => $_clearField(3); +} + +class StatusResponse extends $pb.GeneratedMessage { + factory StatusResponse({ + $core.String? status, + FullStatus? fullStatus, + $core.String? daemonVersion, + }) { + final result = create(); + if (status != null) result.status = status; + if (fullStatus != null) result.fullStatus = fullStatus; + if (daemonVersion != null) result.daemonVersion = daemonVersion; + return result; + } + + StatusResponse._(); + + factory StatusResponse.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory StatusResponse.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'StatusResponse', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..aOS(1, _omitFieldNames ? '' : 'status') + ..aOM(2, _omitFieldNames ? '' : 'fullStatus', + protoName: 'fullStatus', subBuilder: FullStatus.create) + ..aOS(3, _omitFieldNames ? '' : 'daemonVersion', protoName: 'daemonVersion') + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + StatusResponse clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + StatusResponse copyWith(void Function(StatusResponse) updates) => + super.copyWith((message) => updates(message as StatusResponse)) + as StatusResponse; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static StatusResponse create() => StatusResponse._(); + @$core.override + StatusResponse createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static StatusResponse getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static StatusResponse? _defaultInstance; + + /// status of the server. + @$pb.TagNumber(1) + $core.String get status => $_getSZ(0); + @$pb.TagNumber(1) + set status($core.String value) => $_setString(0, value); + @$pb.TagNumber(1) + $core.bool hasStatus() => $_has(0); + @$pb.TagNumber(1) + void clearStatus() => $_clearField(1); + + @$pb.TagNumber(2) + FullStatus get fullStatus => $_getN(1); + @$pb.TagNumber(2) + set fullStatus(FullStatus value) => $_setField(2, value); + @$pb.TagNumber(2) + $core.bool hasFullStatus() => $_has(1); + @$pb.TagNumber(2) + void clearFullStatus() => $_clearField(2); + @$pb.TagNumber(2) + FullStatus ensureFullStatus() => $_ensure(1); + + /// NetBird daemon version + @$pb.TagNumber(3) + $core.String get daemonVersion => $_getSZ(2); + @$pb.TagNumber(3) + set daemonVersion($core.String value) => $_setString(2, value); + @$pb.TagNumber(3) + $core.bool hasDaemonVersion() => $_has(2); + @$pb.TagNumber(3) + void clearDaemonVersion() => $_clearField(3); +} + +class DownRequest extends $pb.GeneratedMessage { + factory DownRequest() => create(); + + DownRequest._(); + + factory DownRequest.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory DownRequest.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'DownRequest', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + DownRequest clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + DownRequest copyWith(void Function(DownRequest) updates) => + super.copyWith((message) => updates(message as DownRequest)) + as DownRequest; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static DownRequest create() => DownRequest._(); + @$core.override + DownRequest createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static DownRequest getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static DownRequest? _defaultInstance; +} + +class DownResponse extends $pb.GeneratedMessage { + factory DownResponse() => create(); + + DownResponse._(); + + factory DownResponse.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory DownResponse.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'DownResponse', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + DownResponse clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + DownResponse copyWith(void Function(DownResponse) updates) => + super.copyWith((message) => updates(message as DownResponse)) + as DownResponse; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static DownResponse create() => DownResponse._(); + @$core.override + DownResponse createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static DownResponse getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static DownResponse? _defaultInstance; +} + +class GetConfigRequest extends $pb.GeneratedMessage { + factory GetConfigRequest({ + $core.String? profileName, + $core.String? username, + }) { + final result = create(); + if (profileName != null) result.profileName = profileName; + if (username != null) result.username = username; + return result; + } + + GetConfigRequest._(); + + factory GetConfigRequest.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory GetConfigRequest.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'GetConfigRequest', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..aOS(1, _omitFieldNames ? '' : 'profileName', protoName: 'profileName') + ..aOS(2, _omitFieldNames ? '' : 'username') + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + GetConfigRequest clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + GetConfigRequest copyWith(void Function(GetConfigRequest) updates) => + super.copyWith((message) => updates(message as GetConfigRequest)) + as GetConfigRequest; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static GetConfigRequest create() => GetConfigRequest._(); + @$core.override + GetConfigRequest createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static GetConfigRequest getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static GetConfigRequest? _defaultInstance; + + @$pb.TagNumber(1) + $core.String get profileName => $_getSZ(0); + @$pb.TagNumber(1) + set profileName($core.String value) => $_setString(0, value); + @$pb.TagNumber(1) + $core.bool hasProfileName() => $_has(0); + @$pb.TagNumber(1) + void clearProfileName() => $_clearField(1); + + @$pb.TagNumber(2) + $core.String get username => $_getSZ(1); + @$pb.TagNumber(2) + set username($core.String value) => $_setString(1, value); + @$pb.TagNumber(2) + $core.bool hasUsername() => $_has(1); + @$pb.TagNumber(2) + void clearUsername() => $_clearField(2); +} + +class GetConfigResponse extends $pb.GeneratedMessage { + factory GetConfigResponse({ + $core.String? managementUrl, + $core.String? configFile, + $core.String? logFile, + $core.String? preSharedKey, + $core.String? adminURL, + $core.String? interfaceName, + $fixnum.Int64? wireguardPort, + $fixnum.Int64? mtu, + $core.bool? disableAutoConnect, + $core.bool? serverSSHAllowed, + $core.bool? rosenpassEnabled, + $core.bool? rosenpassPermissive, + $core.bool? disableNotifications, + $core.bool? lazyConnectionEnabled, + $core.bool? blockInbound, + $core.bool? networkMonitor, + $core.bool? disableDns, + $core.bool? disableClientRoutes, + $core.bool? disableServerRoutes, + $core.bool? blockLanAccess, + $core.bool? enableSSHRoot, + $core.bool? enableSSHLocalPortForwarding, + $core.bool? enableSSHRemotePortForwarding, + $core.bool? enableSSHSFTP, + $core.bool? disableSSHAuth, + $core.int? sshJWTCacheTTL, + }) { + final result = create(); + if (managementUrl != null) result.managementUrl = managementUrl; + if (configFile != null) result.configFile = configFile; + if (logFile != null) result.logFile = logFile; + if (preSharedKey != null) result.preSharedKey = preSharedKey; + if (adminURL != null) result.adminURL = adminURL; + if (interfaceName != null) result.interfaceName = interfaceName; + if (wireguardPort != null) result.wireguardPort = wireguardPort; + if (mtu != null) result.mtu = mtu; + if (disableAutoConnect != null) + result.disableAutoConnect = disableAutoConnect; + if (serverSSHAllowed != null) result.serverSSHAllowed = serverSSHAllowed; + if (rosenpassEnabled != null) result.rosenpassEnabled = rosenpassEnabled; + if (rosenpassPermissive != null) + result.rosenpassPermissive = rosenpassPermissive; + if (disableNotifications != null) + result.disableNotifications = disableNotifications; + if (lazyConnectionEnabled != null) + result.lazyConnectionEnabled = lazyConnectionEnabled; + if (blockInbound != null) result.blockInbound = blockInbound; + if (networkMonitor != null) result.networkMonitor = networkMonitor; + if (disableDns != null) result.disableDns = disableDns; + if (disableClientRoutes != null) + result.disableClientRoutes = disableClientRoutes; + if (disableServerRoutes != null) + result.disableServerRoutes = disableServerRoutes; + if (blockLanAccess != null) result.blockLanAccess = blockLanAccess; + if (enableSSHRoot != null) result.enableSSHRoot = enableSSHRoot; + if (enableSSHLocalPortForwarding != null) + result.enableSSHLocalPortForwarding = enableSSHLocalPortForwarding; + if (enableSSHRemotePortForwarding != null) + result.enableSSHRemotePortForwarding = enableSSHRemotePortForwarding; + if (enableSSHSFTP != null) result.enableSSHSFTP = enableSSHSFTP; + if (disableSSHAuth != null) result.disableSSHAuth = disableSSHAuth; + if (sshJWTCacheTTL != null) result.sshJWTCacheTTL = sshJWTCacheTTL; + return result; + } + + GetConfigResponse._(); + + factory GetConfigResponse.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory GetConfigResponse.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'GetConfigResponse', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..aOS(1, _omitFieldNames ? '' : 'managementUrl', protoName: 'managementUrl') + ..aOS(2, _omitFieldNames ? '' : 'configFile', protoName: 'configFile') + ..aOS(3, _omitFieldNames ? '' : 'logFile', protoName: 'logFile') + ..aOS(4, _omitFieldNames ? '' : 'preSharedKey', protoName: 'preSharedKey') + ..aOS(5, _omitFieldNames ? '' : 'adminURL', protoName: 'adminURL') + ..aOS(6, _omitFieldNames ? '' : 'interfaceName', protoName: 'interfaceName') + ..aInt64(7, _omitFieldNames ? '' : 'wireguardPort', + protoName: 'wireguardPort') + ..aInt64(8, _omitFieldNames ? '' : 'mtu') + ..aOB(9, _omitFieldNames ? '' : 'disableAutoConnect', + protoName: 'disableAutoConnect') + ..aOB(10, _omitFieldNames ? '' : 'serverSSHAllowed', + protoName: 'serverSSHAllowed') + ..aOB(11, _omitFieldNames ? '' : 'rosenpassEnabled', + protoName: 'rosenpassEnabled') + ..aOB(12, _omitFieldNames ? '' : 'rosenpassPermissive', + protoName: 'rosenpassPermissive') + ..aOB(13, _omitFieldNames ? '' : 'disableNotifications') + ..aOB(14, _omitFieldNames ? '' : 'lazyConnectionEnabled', + protoName: 'lazyConnectionEnabled') + ..aOB(15, _omitFieldNames ? '' : 'blockInbound', protoName: 'blockInbound') + ..aOB(16, _omitFieldNames ? '' : 'networkMonitor', + protoName: 'networkMonitor') + ..aOB(17, _omitFieldNames ? '' : 'disableDns') + ..aOB(18, _omitFieldNames ? '' : 'disableClientRoutes') + ..aOB(19, _omitFieldNames ? '' : 'disableServerRoutes') + ..aOB(20, _omitFieldNames ? '' : 'blockLanAccess') + ..aOB(21, _omitFieldNames ? '' : 'enableSSHRoot', + protoName: 'enableSSHRoot') + ..aOB(22, _omitFieldNames ? '' : 'enableSSHLocalPortForwarding', + protoName: 'enableSSHLocalPortForwarding') + ..aOB(23, _omitFieldNames ? '' : 'enableSSHRemotePortForwarding', + protoName: 'enableSSHRemotePortForwarding') + ..aOB(24, _omitFieldNames ? '' : 'enableSSHSFTP', + protoName: 'enableSSHSFTP') + ..aOB(25, _omitFieldNames ? '' : 'disableSSHAuth', + protoName: 'disableSSHAuth') + ..aI(26, _omitFieldNames ? '' : 'sshJWTCacheTTL', + protoName: 'sshJWTCacheTTL') + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + GetConfigResponse clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + GetConfigResponse copyWith(void Function(GetConfigResponse) updates) => + super.copyWith((message) => updates(message as GetConfigResponse)) + as GetConfigResponse; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static GetConfigResponse create() => GetConfigResponse._(); + @$core.override + GetConfigResponse createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static GetConfigResponse getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static GetConfigResponse? _defaultInstance; + + /// managementUrl settings value. + @$pb.TagNumber(1) + $core.String get managementUrl => $_getSZ(0); + @$pb.TagNumber(1) + set managementUrl($core.String value) => $_setString(0, value); + @$pb.TagNumber(1) + $core.bool hasManagementUrl() => $_has(0); + @$pb.TagNumber(1) + void clearManagementUrl() => $_clearField(1); + + /// configFile settings value. + @$pb.TagNumber(2) + $core.String get configFile => $_getSZ(1); + @$pb.TagNumber(2) + set configFile($core.String value) => $_setString(1, value); + @$pb.TagNumber(2) + $core.bool hasConfigFile() => $_has(1); + @$pb.TagNumber(2) + void clearConfigFile() => $_clearField(2); + + /// logFile settings value. + @$pb.TagNumber(3) + $core.String get logFile => $_getSZ(2); + @$pb.TagNumber(3) + set logFile($core.String value) => $_setString(2, value); + @$pb.TagNumber(3) + $core.bool hasLogFile() => $_has(2); + @$pb.TagNumber(3) + void clearLogFile() => $_clearField(3); + + /// preSharedKey settings value. + @$pb.TagNumber(4) + $core.String get preSharedKey => $_getSZ(3); + @$pb.TagNumber(4) + set preSharedKey($core.String value) => $_setString(3, value); + @$pb.TagNumber(4) + $core.bool hasPreSharedKey() => $_has(3); + @$pb.TagNumber(4) + void clearPreSharedKey() => $_clearField(4); + + /// adminURL settings value. + @$pb.TagNumber(5) + $core.String get adminURL => $_getSZ(4); + @$pb.TagNumber(5) + set adminURL($core.String value) => $_setString(4, value); + @$pb.TagNumber(5) + $core.bool hasAdminURL() => $_has(4); + @$pb.TagNumber(5) + void clearAdminURL() => $_clearField(5); + + @$pb.TagNumber(6) + $core.String get interfaceName => $_getSZ(5); + @$pb.TagNumber(6) + set interfaceName($core.String value) => $_setString(5, value); + @$pb.TagNumber(6) + $core.bool hasInterfaceName() => $_has(5); + @$pb.TagNumber(6) + void clearInterfaceName() => $_clearField(6); + + @$pb.TagNumber(7) + $fixnum.Int64 get wireguardPort => $_getI64(6); + @$pb.TagNumber(7) + set wireguardPort($fixnum.Int64 value) => $_setInt64(6, value); + @$pb.TagNumber(7) + $core.bool hasWireguardPort() => $_has(6); + @$pb.TagNumber(7) + void clearWireguardPort() => $_clearField(7); + + @$pb.TagNumber(8) + $fixnum.Int64 get mtu => $_getI64(7); + @$pb.TagNumber(8) + set mtu($fixnum.Int64 value) => $_setInt64(7, value); + @$pb.TagNumber(8) + $core.bool hasMtu() => $_has(7); + @$pb.TagNumber(8) + void clearMtu() => $_clearField(8); + + @$pb.TagNumber(9) + $core.bool get disableAutoConnect => $_getBF(8); + @$pb.TagNumber(9) + set disableAutoConnect($core.bool value) => $_setBool(8, value); + @$pb.TagNumber(9) + $core.bool hasDisableAutoConnect() => $_has(8); + @$pb.TagNumber(9) + void clearDisableAutoConnect() => $_clearField(9); + + @$pb.TagNumber(10) + $core.bool get serverSSHAllowed => $_getBF(9); + @$pb.TagNumber(10) + set serverSSHAllowed($core.bool value) => $_setBool(9, value); + @$pb.TagNumber(10) + $core.bool hasServerSSHAllowed() => $_has(9); + @$pb.TagNumber(10) + void clearServerSSHAllowed() => $_clearField(10); + + @$pb.TagNumber(11) + $core.bool get rosenpassEnabled => $_getBF(10); + @$pb.TagNumber(11) + set rosenpassEnabled($core.bool value) => $_setBool(10, value); + @$pb.TagNumber(11) + $core.bool hasRosenpassEnabled() => $_has(10); + @$pb.TagNumber(11) + void clearRosenpassEnabled() => $_clearField(11); + + @$pb.TagNumber(12) + $core.bool get rosenpassPermissive => $_getBF(11); + @$pb.TagNumber(12) + set rosenpassPermissive($core.bool value) => $_setBool(11, value); + @$pb.TagNumber(12) + $core.bool hasRosenpassPermissive() => $_has(11); + @$pb.TagNumber(12) + void clearRosenpassPermissive() => $_clearField(12); + + @$pb.TagNumber(13) + $core.bool get disableNotifications => $_getBF(12); + @$pb.TagNumber(13) + set disableNotifications($core.bool value) => $_setBool(12, value); + @$pb.TagNumber(13) + $core.bool hasDisableNotifications() => $_has(12); + @$pb.TagNumber(13) + void clearDisableNotifications() => $_clearField(13); + + @$pb.TagNumber(14) + $core.bool get lazyConnectionEnabled => $_getBF(13); + @$pb.TagNumber(14) + set lazyConnectionEnabled($core.bool value) => $_setBool(13, value); + @$pb.TagNumber(14) + $core.bool hasLazyConnectionEnabled() => $_has(13); + @$pb.TagNumber(14) + void clearLazyConnectionEnabled() => $_clearField(14); + + @$pb.TagNumber(15) + $core.bool get blockInbound => $_getBF(14); + @$pb.TagNumber(15) + set blockInbound($core.bool value) => $_setBool(14, value); + @$pb.TagNumber(15) + $core.bool hasBlockInbound() => $_has(14); + @$pb.TagNumber(15) + void clearBlockInbound() => $_clearField(15); + + @$pb.TagNumber(16) + $core.bool get networkMonitor => $_getBF(15); + @$pb.TagNumber(16) + set networkMonitor($core.bool value) => $_setBool(15, value); + @$pb.TagNumber(16) + $core.bool hasNetworkMonitor() => $_has(15); + @$pb.TagNumber(16) + void clearNetworkMonitor() => $_clearField(16); + + @$pb.TagNumber(17) + $core.bool get disableDns => $_getBF(16); + @$pb.TagNumber(17) + set disableDns($core.bool value) => $_setBool(16, value); + @$pb.TagNumber(17) + $core.bool hasDisableDns() => $_has(16); + @$pb.TagNumber(17) + void clearDisableDns() => $_clearField(17); + + @$pb.TagNumber(18) + $core.bool get disableClientRoutes => $_getBF(17); + @$pb.TagNumber(18) + set disableClientRoutes($core.bool value) => $_setBool(17, value); + @$pb.TagNumber(18) + $core.bool hasDisableClientRoutes() => $_has(17); + @$pb.TagNumber(18) + void clearDisableClientRoutes() => $_clearField(18); + + @$pb.TagNumber(19) + $core.bool get disableServerRoutes => $_getBF(18); + @$pb.TagNumber(19) + set disableServerRoutes($core.bool value) => $_setBool(18, value); + @$pb.TagNumber(19) + $core.bool hasDisableServerRoutes() => $_has(18); + @$pb.TagNumber(19) + void clearDisableServerRoutes() => $_clearField(19); + + @$pb.TagNumber(20) + $core.bool get blockLanAccess => $_getBF(19); + @$pb.TagNumber(20) + set blockLanAccess($core.bool value) => $_setBool(19, value); + @$pb.TagNumber(20) + $core.bool hasBlockLanAccess() => $_has(19); + @$pb.TagNumber(20) + void clearBlockLanAccess() => $_clearField(20); + + @$pb.TagNumber(21) + $core.bool get enableSSHRoot => $_getBF(20); + @$pb.TagNumber(21) + set enableSSHRoot($core.bool value) => $_setBool(20, value); + @$pb.TagNumber(21) + $core.bool hasEnableSSHRoot() => $_has(20); + @$pb.TagNumber(21) + void clearEnableSSHRoot() => $_clearField(21); + + @$pb.TagNumber(22) + $core.bool get enableSSHLocalPortForwarding => $_getBF(21); + @$pb.TagNumber(22) + set enableSSHLocalPortForwarding($core.bool value) => $_setBool(21, value); + @$pb.TagNumber(22) + $core.bool hasEnableSSHLocalPortForwarding() => $_has(21); + @$pb.TagNumber(22) + void clearEnableSSHLocalPortForwarding() => $_clearField(22); + + @$pb.TagNumber(23) + $core.bool get enableSSHRemotePortForwarding => $_getBF(22); + @$pb.TagNumber(23) + set enableSSHRemotePortForwarding($core.bool value) => $_setBool(22, value); + @$pb.TagNumber(23) + $core.bool hasEnableSSHRemotePortForwarding() => $_has(22); + @$pb.TagNumber(23) + void clearEnableSSHRemotePortForwarding() => $_clearField(23); + + @$pb.TagNumber(24) + $core.bool get enableSSHSFTP => $_getBF(23); + @$pb.TagNumber(24) + set enableSSHSFTP($core.bool value) => $_setBool(23, value); + @$pb.TagNumber(24) + $core.bool hasEnableSSHSFTP() => $_has(23); + @$pb.TagNumber(24) + void clearEnableSSHSFTP() => $_clearField(24); + + @$pb.TagNumber(25) + $core.bool get disableSSHAuth => $_getBF(24); + @$pb.TagNumber(25) + set disableSSHAuth($core.bool value) => $_setBool(24, value); + @$pb.TagNumber(25) + $core.bool hasDisableSSHAuth() => $_has(24); + @$pb.TagNumber(25) + void clearDisableSSHAuth() => $_clearField(25); + + @$pb.TagNumber(26) + $core.int get sshJWTCacheTTL => $_getIZ(25); + @$pb.TagNumber(26) + set sshJWTCacheTTL($core.int value) => $_setSignedInt32(25, value); + @$pb.TagNumber(26) + $core.bool hasSshJWTCacheTTL() => $_has(25); + @$pb.TagNumber(26) + void clearSshJWTCacheTTL() => $_clearField(26); +} + +/// PeerState contains the latest state of a peer +class PeerState extends $pb.GeneratedMessage { + factory PeerState({ + $core.String? iP, + $core.String? pubKey, + $core.String? connStatus, + $2.Timestamp? connStatusUpdate, + $core.bool? relayed, + $core.String? localIceCandidateType, + $core.String? remoteIceCandidateType, + $core.String? fqdn, + $core.String? localIceCandidateEndpoint, + $core.String? remoteIceCandidateEndpoint, + $2.Timestamp? lastWireguardHandshake, + $fixnum.Int64? bytesRx, + $fixnum.Int64? bytesTx, + $core.bool? rosenpassEnabled, + $core.Iterable<$core.String>? networks, + $1.Duration? latency, + $core.String? relayAddress, + $core.List<$core.int>? sshHostKey, + }) { + final result = create(); + if (iP != null) result.iP = iP; + if (pubKey != null) result.pubKey = pubKey; + if (connStatus != null) result.connStatus = connStatus; + if (connStatusUpdate != null) result.connStatusUpdate = connStatusUpdate; + if (relayed != null) result.relayed = relayed; + if (localIceCandidateType != null) + result.localIceCandidateType = localIceCandidateType; + if (remoteIceCandidateType != null) + result.remoteIceCandidateType = remoteIceCandidateType; + if (fqdn != null) result.fqdn = fqdn; + if (localIceCandidateEndpoint != null) + result.localIceCandidateEndpoint = localIceCandidateEndpoint; + if (remoteIceCandidateEndpoint != null) + result.remoteIceCandidateEndpoint = remoteIceCandidateEndpoint; + if (lastWireguardHandshake != null) + result.lastWireguardHandshake = lastWireguardHandshake; + if (bytesRx != null) result.bytesRx = bytesRx; + if (bytesTx != null) result.bytesTx = bytesTx; + if (rosenpassEnabled != null) result.rosenpassEnabled = rosenpassEnabled; + if (networks != null) result.networks.addAll(networks); + if (latency != null) result.latency = latency; + if (relayAddress != null) result.relayAddress = relayAddress; + if (sshHostKey != null) result.sshHostKey = sshHostKey; + return result; + } + + PeerState._(); + + factory PeerState.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory PeerState.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'PeerState', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..aOS(1, _omitFieldNames ? '' : 'IP', protoName: 'IP') + ..aOS(2, _omitFieldNames ? '' : 'pubKey', protoName: 'pubKey') + ..aOS(3, _omitFieldNames ? '' : 'connStatus', protoName: 'connStatus') + ..aOM<$2.Timestamp>(4, _omitFieldNames ? '' : 'connStatusUpdate', + protoName: 'connStatusUpdate', subBuilder: $2.Timestamp.create) + ..aOB(5, _omitFieldNames ? '' : 'relayed') + ..aOS(7, _omitFieldNames ? '' : 'localIceCandidateType', + protoName: 'localIceCandidateType') + ..aOS(8, _omitFieldNames ? '' : 'remoteIceCandidateType', + protoName: 'remoteIceCandidateType') + ..aOS(9, _omitFieldNames ? '' : 'fqdn') + ..aOS(10, _omitFieldNames ? '' : 'localIceCandidateEndpoint', + protoName: 'localIceCandidateEndpoint') + ..aOS(11, _omitFieldNames ? '' : 'remoteIceCandidateEndpoint', + protoName: 'remoteIceCandidateEndpoint') + ..aOM<$2.Timestamp>(12, _omitFieldNames ? '' : 'lastWireguardHandshake', + protoName: 'lastWireguardHandshake', subBuilder: $2.Timestamp.create) + ..aInt64(13, _omitFieldNames ? '' : 'bytesRx', protoName: 'bytesRx') + ..aInt64(14, _omitFieldNames ? '' : 'bytesTx', protoName: 'bytesTx') + ..aOB(15, _omitFieldNames ? '' : 'rosenpassEnabled', + protoName: 'rosenpassEnabled') + ..pPS(16, _omitFieldNames ? '' : 'networks') + ..aOM<$1.Duration>(17, _omitFieldNames ? '' : 'latency', + subBuilder: $1.Duration.create) + ..aOS(18, _omitFieldNames ? '' : 'relayAddress', protoName: 'relayAddress') + ..a<$core.List<$core.int>>( + 19, _omitFieldNames ? '' : 'sshHostKey', $pb.PbFieldType.OY, + protoName: 'sshHostKey') + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + PeerState clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + PeerState copyWith(void Function(PeerState) updates) => + super.copyWith((message) => updates(message as PeerState)) as PeerState; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static PeerState create() => PeerState._(); + @$core.override + PeerState createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static PeerState getDefault() => + _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static PeerState? _defaultInstance; + + @$pb.TagNumber(1) + $core.String get iP => $_getSZ(0); + @$pb.TagNumber(1) + set iP($core.String value) => $_setString(0, value); + @$pb.TagNumber(1) + $core.bool hasIP() => $_has(0); + @$pb.TagNumber(1) + void clearIP() => $_clearField(1); + + @$pb.TagNumber(2) + $core.String get pubKey => $_getSZ(1); + @$pb.TagNumber(2) + set pubKey($core.String value) => $_setString(1, value); + @$pb.TagNumber(2) + $core.bool hasPubKey() => $_has(1); + @$pb.TagNumber(2) + void clearPubKey() => $_clearField(2); + + @$pb.TagNumber(3) + $core.String get connStatus => $_getSZ(2); + @$pb.TagNumber(3) + set connStatus($core.String value) => $_setString(2, value); + @$pb.TagNumber(3) + $core.bool hasConnStatus() => $_has(2); + @$pb.TagNumber(3) + void clearConnStatus() => $_clearField(3); + + @$pb.TagNumber(4) + $2.Timestamp get connStatusUpdate => $_getN(3); + @$pb.TagNumber(4) + set connStatusUpdate($2.Timestamp value) => $_setField(4, value); + @$pb.TagNumber(4) + $core.bool hasConnStatusUpdate() => $_has(3); + @$pb.TagNumber(4) + void clearConnStatusUpdate() => $_clearField(4); + @$pb.TagNumber(4) + $2.Timestamp ensureConnStatusUpdate() => $_ensure(3); + + @$pb.TagNumber(5) + $core.bool get relayed => $_getBF(4); + @$pb.TagNumber(5) + set relayed($core.bool value) => $_setBool(4, value); + @$pb.TagNumber(5) + $core.bool hasRelayed() => $_has(4); + @$pb.TagNumber(5) + void clearRelayed() => $_clearField(5); + + @$pb.TagNumber(7) + $core.String get localIceCandidateType => $_getSZ(5); + @$pb.TagNumber(7) + set localIceCandidateType($core.String value) => $_setString(5, value); + @$pb.TagNumber(7) + $core.bool hasLocalIceCandidateType() => $_has(5); + @$pb.TagNumber(7) + void clearLocalIceCandidateType() => $_clearField(7); + + @$pb.TagNumber(8) + $core.String get remoteIceCandidateType => $_getSZ(6); + @$pb.TagNumber(8) + set remoteIceCandidateType($core.String value) => $_setString(6, value); + @$pb.TagNumber(8) + $core.bool hasRemoteIceCandidateType() => $_has(6); + @$pb.TagNumber(8) + void clearRemoteIceCandidateType() => $_clearField(8); + + @$pb.TagNumber(9) + $core.String get fqdn => $_getSZ(7); + @$pb.TagNumber(9) + set fqdn($core.String value) => $_setString(7, value); + @$pb.TagNumber(9) + $core.bool hasFqdn() => $_has(7); + @$pb.TagNumber(9) + void clearFqdn() => $_clearField(9); + + @$pb.TagNumber(10) + $core.String get localIceCandidateEndpoint => $_getSZ(8); + @$pb.TagNumber(10) + set localIceCandidateEndpoint($core.String value) => $_setString(8, value); + @$pb.TagNumber(10) + $core.bool hasLocalIceCandidateEndpoint() => $_has(8); + @$pb.TagNumber(10) + void clearLocalIceCandidateEndpoint() => $_clearField(10); + + @$pb.TagNumber(11) + $core.String get remoteIceCandidateEndpoint => $_getSZ(9); + @$pb.TagNumber(11) + set remoteIceCandidateEndpoint($core.String value) => $_setString(9, value); + @$pb.TagNumber(11) + $core.bool hasRemoteIceCandidateEndpoint() => $_has(9); + @$pb.TagNumber(11) + void clearRemoteIceCandidateEndpoint() => $_clearField(11); + + @$pb.TagNumber(12) + $2.Timestamp get lastWireguardHandshake => $_getN(10); + @$pb.TagNumber(12) + set lastWireguardHandshake($2.Timestamp value) => $_setField(12, value); + @$pb.TagNumber(12) + $core.bool hasLastWireguardHandshake() => $_has(10); + @$pb.TagNumber(12) + void clearLastWireguardHandshake() => $_clearField(12); + @$pb.TagNumber(12) + $2.Timestamp ensureLastWireguardHandshake() => $_ensure(10); + + @$pb.TagNumber(13) + $fixnum.Int64 get bytesRx => $_getI64(11); + @$pb.TagNumber(13) + set bytesRx($fixnum.Int64 value) => $_setInt64(11, value); + @$pb.TagNumber(13) + $core.bool hasBytesRx() => $_has(11); + @$pb.TagNumber(13) + void clearBytesRx() => $_clearField(13); + + @$pb.TagNumber(14) + $fixnum.Int64 get bytesTx => $_getI64(12); + @$pb.TagNumber(14) + set bytesTx($fixnum.Int64 value) => $_setInt64(12, value); + @$pb.TagNumber(14) + $core.bool hasBytesTx() => $_has(12); + @$pb.TagNumber(14) + void clearBytesTx() => $_clearField(14); + + @$pb.TagNumber(15) + $core.bool get rosenpassEnabled => $_getBF(13); + @$pb.TagNumber(15) + set rosenpassEnabled($core.bool value) => $_setBool(13, value); + @$pb.TagNumber(15) + $core.bool hasRosenpassEnabled() => $_has(13); + @$pb.TagNumber(15) + void clearRosenpassEnabled() => $_clearField(15); + + @$pb.TagNumber(16) + $pb.PbList<$core.String> get networks => $_getList(14); + + @$pb.TagNumber(17) + $1.Duration get latency => $_getN(15); + @$pb.TagNumber(17) + set latency($1.Duration value) => $_setField(17, value); + @$pb.TagNumber(17) + $core.bool hasLatency() => $_has(15); + @$pb.TagNumber(17) + void clearLatency() => $_clearField(17); + @$pb.TagNumber(17) + $1.Duration ensureLatency() => $_ensure(15); + + @$pb.TagNumber(18) + $core.String get relayAddress => $_getSZ(16); + @$pb.TagNumber(18) + set relayAddress($core.String value) => $_setString(16, value); + @$pb.TagNumber(18) + $core.bool hasRelayAddress() => $_has(16); + @$pb.TagNumber(18) + void clearRelayAddress() => $_clearField(18); + + @$pb.TagNumber(19) + $core.List<$core.int> get sshHostKey => $_getN(17); + @$pb.TagNumber(19) + set sshHostKey($core.List<$core.int> value) => $_setBytes(17, value); + @$pb.TagNumber(19) + $core.bool hasSshHostKey() => $_has(17); + @$pb.TagNumber(19) + void clearSshHostKey() => $_clearField(19); +} + +/// LocalPeerState contains the latest state of the local peer +class LocalPeerState extends $pb.GeneratedMessage { + factory LocalPeerState({ + $core.String? iP, + $core.String? pubKey, + $core.bool? kernelInterface, + $core.String? fqdn, + $core.bool? rosenpassEnabled, + $core.bool? rosenpassPermissive, + $core.Iterable<$core.String>? networks, + }) { + final result = create(); + if (iP != null) result.iP = iP; + if (pubKey != null) result.pubKey = pubKey; + if (kernelInterface != null) result.kernelInterface = kernelInterface; + if (fqdn != null) result.fqdn = fqdn; + if (rosenpassEnabled != null) result.rosenpassEnabled = rosenpassEnabled; + if (rosenpassPermissive != null) + result.rosenpassPermissive = rosenpassPermissive; + if (networks != null) result.networks.addAll(networks); + return result; + } + + LocalPeerState._(); + + factory LocalPeerState.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory LocalPeerState.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'LocalPeerState', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..aOS(1, _omitFieldNames ? '' : 'IP', protoName: 'IP') + ..aOS(2, _omitFieldNames ? '' : 'pubKey', protoName: 'pubKey') + ..aOB(3, _omitFieldNames ? '' : 'kernelInterface', + protoName: 'kernelInterface') + ..aOS(4, _omitFieldNames ? '' : 'fqdn') + ..aOB(5, _omitFieldNames ? '' : 'rosenpassEnabled', + protoName: 'rosenpassEnabled') + ..aOB(6, _omitFieldNames ? '' : 'rosenpassPermissive', + protoName: 'rosenpassPermissive') + ..pPS(7, _omitFieldNames ? '' : 'networks') + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + LocalPeerState clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + LocalPeerState copyWith(void Function(LocalPeerState) updates) => + super.copyWith((message) => updates(message as LocalPeerState)) + as LocalPeerState; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static LocalPeerState create() => LocalPeerState._(); + @$core.override + LocalPeerState createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static LocalPeerState getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static LocalPeerState? _defaultInstance; + + @$pb.TagNumber(1) + $core.String get iP => $_getSZ(0); + @$pb.TagNumber(1) + set iP($core.String value) => $_setString(0, value); + @$pb.TagNumber(1) + $core.bool hasIP() => $_has(0); + @$pb.TagNumber(1) + void clearIP() => $_clearField(1); + + @$pb.TagNumber(2) + $core.String get pubKey => $_getSZ(1); + @$pb.TagNumber(2) + set pubKey($core.String value) => $_setString(1, value); + @$pb.TagNumber(2) + $core.bool hasPubKey() => $_has(1); + @$pb.TagNumber(2) + void clearPubKey() => $_clearField(2); + + @$pb.TagNumber(3) + $core.bool get kernelInterface => $_getBF(2); + @$pb.TagNumber(3) + set kernelInterface($core.bool value) => $_setBool(2, value); + @$pb.TagNumber(3) + $core.bool hasKernelInterface() => $_has(2); + @$pb.TagNumber(3) + void clearKernelInterface() => $_clearField(3); + + @$pb.TagNumber(4) + $core.String get fqdn => $_getSZ(3); + @$pb.TagNumber(4) + set fqdn($core.String value) => $_setString(3, value); + @$pb.TagNumber(4) + $core.bool hasFqdn() => $_has(3); + @$pb.TagNumber(4) + void clearFqdn() => $_clearField(4); + + @$pb.TagNumber(5) + $core.bool get rosenpassEnabled => $_getBF(4); + @$pb.TagNumber(5) + set rosenpassEnabled($core.bool value) => $_setBool(4, value); + @$pb.TagNumber(5) + $core.bool hasRosenpassEnabled() => $_has(4); + @$pb.TagNumber(5) + void clearRosenpassEnabled() => $_clearField(5); + + @$pb.TagNumber(6) + $core.bool get rosenpassPermissive => $_getBF(5); + @$pb.TagNumber(6) + set rosenpassPermissive($core.bool value) => $_setBool(5, value); + @$pb.TagNumber(6) + $core.bool hasRosenpassPermissive() => $_has(5); + @$pb.TagNumber(6) + void clearRosenpassPermissive() => $_clearField(6); + + @$pb.TagNumber(7) + $pb.PbList<$core.String> get networks => $_getList(6); +} + +/// SignalState contains the latest state of a signal connection +class SignalState extends $pb.GeneratedMessage { + factory SignalState({ + $core.String? uRL, + $core.bool? connected, + $core.String? error, + }) { + final result = create(); + if (uRL != null) result.uRL = uRL; + if (connected != null) result.connected = connected; + if (error != null) result.error = error; + return result; + } + + SignalState._(); + + factory SignalState.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory SignalState.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'SignalState', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..aOS(1, _omitFieldNames ? '' : 'URL', protoName: 'URL') + ..aOB(2, _omitFieldNames ? '' : 'connected') + ..aOS(3, _omitFieldNames ? '' : 'error') + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + SignalState clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + SignalState copyWith(void Function(SignalState) updates) => + super.copyWith((message) => updates(message as SignalState)) + as SignalState; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static SignalState create() => SignalState._(); + @$core.override + SignalState createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static SignalState getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static SignalState? _defaultInstance; + + @$pb.TagNumber(1) + $core.String get uRL => $_getSZ(0); + @$pb.TagNumber(1) + set uRL($core.String value) => $_setString(0, value); + @$pb.TagNumber(1) + $core.bool hasURL() => $_has(0); + @$pb.TagNumber(1) + void clearURL() => $_clearField(1); + + @$pb.TagNumber(2) + $core.bool get connected => $_getBF(1); + @$pb.TagNumber(2) + set connected($core.bool value) => $_setBool(1, value); + @$pb.TagNumber(2) + $core.bool hasConnected() => $_has(1); + @$pb.TagNumber(2) + void clearConnected() => $_clearField(2); + + @$pb.TagNumber(3) + $core.String get error => $_getSZ(2); + @$pb.TagNumber(3) + set error($core.String value) => $_setString(2, value); + @$pb.TagNumber(3) + $core.bool hasError() => $_has(2); + @$pb.TagNumber(3) + void clearError() => $_clearField(3); +} + +/// ManagementState contains the latest state of a management connection +class ManagementState extends $pb.GeneratedMessage { + factory ManagementState({ + $core.String? uRL, + $core.bool? connected, + $core.String? error, + }) { + final result = create(); + if (uRL != null) result.uRL = uRL; + if (connected != null) result.connected = connected; + if (error != null) result.error = error; + return result; + } + + ManagementState._(); + + factory ManagementState.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory ManagementState.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'ManagementState', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..aOS(1, _omitFieldNames ? '' : 'URL', protoName: 'URL') + ..aOB(2, _omitFieldNames ? '' : 'connected') + ..aOS(3, _omitFieldNames ? '' : 'error') + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + ManagementState clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + ManagementState copyWith(void Function(ManagementState) updates) => + super.copyWith((message) => updates(message as ManagementState)) + as ManagementState; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static ManagementState create() => ManagementState._(); + @$core.override + ManagementState createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static ManagementState getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static ManagementState? _defaultInstance; + + @$pb.TagNumber(1) + $core.String get uRL => $_getSZ(0); + @$pb.TagNumber(1) + set uRL($core.String value) => $_setString(0, value); + @$pb.TagNumber(1) + $core.bool hasURL() => $_has(0); + @$pb.TagNumber(1) + void clearURL() => $_clearField(1); + + @$pb.TagNumber(2) + $core.bool get connected => $_getBF(1); + @$pb.TagNumber(2) + set connected($core.bool value) => $_setBool(1, value); + @$pb.TagNumber(2) + $core.bool hasConnected() => $_has(1); + @$pb.TagNumber(2) + void clearConnected() => $_clearField(2); + + @$pb.TagNumber(3) + $core.String get error => $_getSZ(2); + @$pb.TagNumber(3) + set error($core.String value) => $_setString(2, value); + @$pb.TagNumber(3) + $core.bool hasError() => $_has(2); + @$pb.TagNumber(3) + void clearError() => $_clearField(3); +} + +/// RelayState contains the latest state of the relay +class RelayState extends $pb.GeneratedMessage { + factory RelayState({ + $core.String? uRI, + $core.bool? available, + $core.String? error, + }) { + final result = create(); + if (uRI != null) result.uRI = uRI; + if (available != null) result.available = available; + if (error != null) result.error = error; + return result; + } + + RelayState._(); + + factory RelayState.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory RelayState.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'RelayState', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..aOS(1, _omitFieldNames ? '' : 'URI', protoName: 'URI') + ..aOB(2, _omitFieldNames ? '' : 'available') + ..aOS(3, _omitFieldNames ? '' : 'error') + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + RelayState clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + RelayState copyWith(void Function(RelayState) updates) => + super.copyWith((message) => updates(message as RelayState)) as RelayState; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static RelayState create() => RelayState._(); + @$core.override + RelayState createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static RelayState getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static RelayState? _defaultInstance; + + @$pb.TagNumber(1) + $core.String get uRI => $_getSZ(0); + @$pb.TagNumber(1) + set uRI($core.String value) => $_setString(0, value); + @$pb.TagNumber(1) + $core.bool hasURI() => $_has(0); + @$pb.TagNumber(1) + void clearURI() => $_clearField(1); + + @$pb.TagNumber(2) + $core.bool get available => $_getBF(1); + @$pb.TagNumber(2) + set available($core.bool value) => $_setBool(1, value); + @$pb.TagNumber(2) + $core.bool hasAvailable() => $_has(1); + @$pb.TagNumber(2) + void clearAvailable() => $_clearField(2); + + @$pb.TagNumber(3) + $core.String get error => $_getSZ(2); + @$pb.TagNumber(3) + set error($core.String value) => $_setString(2, value); + @$pb.TagNumber(3) + $core.bool hasError() => $_has(2); + @$pb.TagNumber(3) + void clearError() => $_clearField(3); +} + +class NSGroupState extends $pb.GeneratedMessage { + factory NSGroupState({ + $core.Iterable<$core.String>? servers, + $core.Iterable<$core.String>? domains, + $core.bool? enabled, + $core.String? error, + }) { + final result = create(); + if (servers != null) result.servers.addAll(servers); + if (domains != null) result.domains.addAll(domains); + if (enabled != null) result.enabled = enabled; + if (error != null) result.error = error; + return result; + } + + NSGroupState._(); + + factory NSGroupState.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory NSGroupState.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'NSGroupState', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..pPS(1, _omitFieldNames ? '' : 'servers') + ..pPS(2, _omitFieldNames ? '' : 'domains') + ..aOB(3, _omitFieldNames ? '' : 'enabled') + ..aOS(4, _omitFieldNames ? '' : 'error') + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + NSGroupState clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + NSGroupState copyWith(void Function(NSGroupState) updates) => + super.copyWith((message) => updates(message as NSGroupState)) + as NSGroupState; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static NSGroupState create() => NSGroupState._(); + @$core.override + NSGroupState createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static NSGroupState getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static NSGroupState? _defaultInstance; + + @$pb.TagNumber(1) + $pb.PbList<$core.String> get servers => $_getList(0); + + @$pb.TagNumber(2) + $pb.PbList<$core.String> get domains => $_getList(1); + + @$pb.TagNumber(3) + $core.bool get enabled => $_getBF(2); + @$pb.TagNumber(3) + set enabled($core.bool value) => $_setBool(2, value); + @$pb.TagNumber(3) + $core.bool hasEnabled() => $_has(2); + @$pb.TagNumber(3) + void clearEnabled() => $_clearField(3); + + @$pb.TagNumber(4) + $core.String get error => $_getSZ(3); + @$pb.TagNumber(4) + set error($core.String value) => $_setString(3, value); + @$pb.TagNumber(4) + $core.bool hasError() => $_has(3); + @$pb.TagNumber(4) + void clearError() => $_clearField(4); +} + +/// SSHSessionInfo contains information about an active SSH session +class SSHSessionInfo extends $pb.GeneratedMessage { + factory SSHSessionInfo({ + $core.String? username, + $core.String? remoteAddress, + $core.String? command, + $core.String? jwtUsername, + $core.Iterable<$core.String>? portForwards, + }) { + final result = create(); + if (username != null) result.username = username; + if (remoteAddress != null) result.remoteAddress = remoteAddress; + if (command != null) result.command = command; + if (jwtUsername != null) result.jwtUsername = jwtUsername; + if (portForwards != null) result.portForwards.addAll(portForwards); + return result; + } + + SSHSessionInfo._(); + + factory SSHSessionInfo.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory SSHSessionInfo.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'SSHSessionInfo', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..aOS(1, _omitFieldNames ? '' : 'username') + ..aOS(2, _omitFieldNames ? '' : 'remoteAddress', protoName: 'remoteAddress') + ..aOS(3, _omitFieldNames ? '' : 'command') + ..aOS(4, _omitFieldNames ? '' : 'jwtUsername', protoName: 'jwtUsername') + ..pPS(5, _omitFieldNames ? '' : 'portForwards', protoName: 'portForwards') + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + SSHSessionInfo clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + SSHSessionInfo copyWith(void Function(SSHSessionInfo) updates) => + super.copyWith((message) => updates(message as SSHSessionInfo)) + as SSHSessionInfo; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static SSHSessionInfo create() => SSHSessionInfo._(); + @$core.override + SSHSessionInfo createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static SSHSessionInfo getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static SSHSessionInfo? _defaultInstance; + + @$pb.TagNumber(1) + $core.String get username => $_getSZ(0); + @$pb.TagNumber(1) + set username($core.String value) => $_setString(0, value); + @$pb.TagNumber(1) + $core.bool hasUsername() => $_has(0); + @$pb.TagNumber(1) + void clearUsername() => $_clearField(1); + + @$pb.TagNumber(2) + $core.String get remoteAddress => $_getSZ(1); + @$pb.TagNumber(2) + set remoteAddress($core.String value) => $_setString(1, value); + @$pb.TagNumber(2) + $core.bool hasRemoteAddress() => $_has(1); + @$pb.TagNumber(2) + void clearRemoteAddress() => $_clearField(2); + + @$pb.TagNumber(3) + $core.String get command => $_getSZ(2); + @$pb.TagNumber(3) + set command($core.String value) => $_setString(2, value); + @$pb.TagNumber(3) + $core.bool hasCommand() => $_has(2); + @$pb.TagNumber(3) + void clearCommand() => $_clearField(3); + + @$pb.TagNumber(4) + $core.String get jwtUsername => $_getSZ(3); + @$pb.TagNumber(4) + set jwtUsername($core.String value) => $_setString(3, value); + @$pb.TagNumber(4) + $core.bool hasJwtUsername() => $_has(3); + @$pb.TagNumber(4) + void clearJwtUsername() => $_clearField(4); + + @$pb.TagNumber(5) + $pb.PbList<$core.String> get portForwards => $_getList(4); +} + +/// SSHServerState contains the latest state of the SSH server +class SSHServerState extends $pb.GeneratedMessage { + factory SSHServerState({ + $core.bool? enabled, + $core.Iterable? sessions, + }) { + final result = create(); + if (enabled != null) result.enabled = enabled; + if (sessions != null) result.sessions.addAll(sessions); + return result; + } + + SSHServerState._(); + + factory SSHServerState.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory SSHServerState.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'SSHServerState', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..aOB(1, _omitFieldNames ? '' : 'enabled') + ..pPM(2, _omitFieldNames ? '' : 'sessions', + subBuilder: SSHSessionInfo.create) + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + SSHServerState clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + SSHServerState copyWith(void Function(SSHServerState) updates) => + super.copyWith((message) => updates(message as SSHServerState)) + as SSHServerState; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static SSHServerState create() => SSHServerState._(); + @$core.override + SSHServerState createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static SSHServerState getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static SSHServerState? _defaultInstance; + + @$pb.TagNumber(1) + $core.bool get enabled => $_getBF(0); + @$pb.TagNumber(1) + set enabled($core.bool value) => $_setBool(0, value); + @$pb.TagNumber(1) + $core.bool hasEnabled() => $_has(0); + @$pb.TagNumber(1) + void clearEnabled() => $_clearField(1); + + @$pb.TagNumber(2) + $pb.PbList get sessions => $_getList(1); +} + +/// FullStatus contains the full state held by the Status instance +class FullStatus extends $pb.GeneratedMessage { + factory FullStatus({ + ManagementState? managementState, + SignalState? signalState, + LocalPeerState? localPeerState, + $core.Iterable? peers, + $core.Iterable? relays, + $core.Iterable? dnsServers, + $core.Iterable? events, + $core.int? numberOfForwardingRules, + $core.bool? lazyConnectionEnabled, + SSHServerState? sshServerState, + }) { + final result = create(); + if (managementState != null) result.managementState = managementState; + if (signalState != null) result.signalState = signalState; + if (localPeerState != null) result.localPeerState = localPeerState; + if (peers != null) result.peers.addAll(peers); + if (relays != null) result.relays.addAll(relays); + if (dnsServers != null) result.dnsServers.addAll(dnsServers); + if (events != null) result.events.addAll(events); + if (numberOfForwardingRules != null) + result.numberOfForwardingRules = numberOfForwardingRules; + if (lazyConnectionEnabled != null) + result.lazyConnectionEnabled = lazyConnectionEnabled; + if (sshServerState != null) result.sshServerState = sshServerState; + return result; + } + + FullStatus._(); + + factory FullStatus.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory FullStatus.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'FullStatus', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..aOM(1, _omitFieldNames ? '' : 'managementState', + protoName: 'managementState', subBuilder: ManagementState.create) + ..aOM(2, _omitFieldNames ? '' : 'signalState', + protoName: 'signalState', subBuilder: SignalState.create) + ..aOM(3, _omitFieldNames ? '' : 'localPeerState', + protoName: 'localPeerState', subBuilder: LocalPeerState.create) + ..pPM(4, _omitFieldNames ? '' : 'peers', + subBuilder: PeerState.create) + ..pPM(5, _omitFieldNames ? '' : 'relays', + subBuilder: RelayState.create) + ..pPM(6, _omitFieldNames ? '' : 'dnsServers', + subBuilder: NSGroupState.create) + ..pPM(7, _omitFieldNames ? '' : 'events', + subBuilder: SystemEvent.create) + ..aI(8, _omitFieldNames ? '' : 'NumberOfForwardingRules', + protoName: 'NumberOfForwardingRules') + ..aOB(9, _omitFieldNames ? '' : 'lazyConnectionEnabled', + protoName: 'lazyConnectionEnabled') + ..aOM(10, _omitFieldNames ? '' : 'sshServerState', + protoName: 'sshServerState', subBuilder: SSHServerState.create) + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + FullStatus clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + FullStatus copyWith(void Function(FullStatus) updates) => + super.copyWith((message) => updates(message as FullStatus)) as FullStatus; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static FullStatus create() => FullStatus._(); + @$core.override + FullStatus createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static FullStatus getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static FullStatus? _defaultInstance; + + @$pb.TagNumber(1) + ManagementState get managementState => $_getN(0); + @$pb.TagNumber(1) + set managementState(ManagementState value) => $_setField(1, value); + @$pb.TagNumber(1) + $core.bool hasManagementState() => $_has(0); + @$pb.TagNumber(1) + void clearManagementState() => $_clearField(1); + @$pb.TagNumber(1) + ManagementState ensureManagementState() => $_ensure(0); + + @$pb.TagNumber(2) + SignalState get signalState => $_getN(1); + @$pb.TagNumber(2) + set signalState(SignalState value) => $_setField(2, value); + @$pb.TagNumber(2) + $core.bool hasSignalState() => $_has(1); + @$pb.TagNumber(2) + void clearSignalState() => $_clearField(2); + @$pb.TagNumber(2) + SignalState ensureSignalState() => $_ensure(1); + + @$pb.TagNumber(3) + LocalPeerState get localPeerState => $_getN(2); + @$pb.TagNumber(3) + set localPeerState(LocalPeerState value) => $_setField(3, value); + @$pb.TagNumber(3) + $core.bool hasLocalPeerState() => $_has(2); + @$pb.TagNumber(3) + void clearLocalPeerState() => $_clearField(3); + @$pb.TagNumber(3) + LocalPeerState ensureLocalPeerState() => $_ensure(2); + + @$pb.TagNumber(4) + $pb.PbList get peers => $_getList(3); + + @$pb.TagNumber(5) + $pb.PbList get relays => $_getList(4); + + @$pb.TagNumber(6) + $pb.PbList get dnsServers => $_getList(5); + + @$pb.TagNumber(7) + $pb.PbList get events => $_getList(6); + + @$pb.TagNumber(8) + $core.int get numberOfForwardingRules => $_getIZ(7); + @$pb.TagNumber(8) + set numberOfForwardingRules($core.int value) => $_setSignedInt32(7, value); + @$pb.TagNumber(8) + $core.bool hasNumberOfForwardingRules() => $_has(7); + @$pb.TagNumber(8) + void clearNumberOfForwardingRules() => $_clearField(8); + + @$pb.TagNumber(9) + $core.bool get lazyConnectionEnabled => $_getBF(8); + @$pb.TagNumber(9) + set lazyConnectionEnabled($core.bool value) => $_setBool(8, value); + @$pb.TagNumber(9) + $core.bool hasLazyConnectionEnabled() => $_has(8); + @$pb.TagNumber(9) + void clearLazyConnectionEnabled() => $_clearField(9); + + @$pb.TagNumber(10) + SSHServerState get sshServerState => $_getN(9); + @$pb.TagNumber(10) + set sshServerState(SSHServerState value) => $_setField(10, value); + @$pb.TagNumber(10) + $core.bool hasSshServerState() => $_has(9); + @$pb.TagNumber(10) + void clearSshServerState() => $_clearField(10); + @$pb.TagNumber(10) + SSHServerState ensureSshServerState() => $_ensure(9); +} + +/// Networks +class ListNetworksRequest extends $pb.GeneratedMessage { + factory ListNetworksRequest() => create(); + + ListNetworksRequest._(); + + factory ListNetworksRequest.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory ListNetworksRequest.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'ListNetworksRequest', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + ListNetworksRequest clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + ListNetworksRequest copyWith(void Function(ListNetworksRequest) updates) => + super.copyWith((message) => updates(message as ListNetworksRequest)) + as ListNetworksRequest; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static ListNetworksRequest create() => ListNetworksRequest._(); + @$core.override + ListNetworksRequest createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static ListNetworksRequest getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static ListNetworksRequest? _defaultInstance; +} + +class ListNetworksResponse extends $pb.GeneratedMessage { + factory ListNetworksResponse({ + $core.Iterable? routes, + }) { + final result = create(); + if (routes != null) result.routes.addAll(routes); + return result; + } + + ListNetworksResponse._(); + + factory ListNetworksResponse.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory ListNetworksResponse.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'ListNetworksResponse', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..pPM(1, _omitFieldNames ? '' : 'routes', + subBuilder: Network.create) + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + ListNetworksResponse clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + ListNetworksResponse copyWith(void Function(ListNetworksResponse) updates) => + super.copyWith((message) => updates(message as ListNetworksResponse)) + as ListNetworksResponse; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static ListNetworksResponse create() => ListNetworksResponse._(); + @$core.override + ListNetworksResponse createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static ListNetworksResponse getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static ListNetworksResponse? _defaultInstance; + + @$pb.TagNumber(1) + $pb.PbList get routes => $_getList(0); +} + +class SelectNetworksRequest extends $pb.GeneratedMessage { + factory SelectNetworksRequest({ + $core.Iterable<$core.String>? networkIDs, + $core.bool? append, + $core.bool? all, + }) { + final result = create(); + if (networkIDs != null) result.networkIDs.addAll(networkIDs); + if (append != null) result.append = append; + if (all != null) result.all = all; + return result; + } + + SelectNetworksRequest._(); + + factory SelectNetworksRequest.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory SelectNetworksRequest.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'SelectNetworksRequest', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..pPS(1, _omitFieldNames ? '' : 'networkIDs', protoName: 'networkIDs') + ..aOB(2, _omitFieldNames ? '' : 'append') + ..aOB(3, _omitFieldNames ? '' : 'all') + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + SelectNetworksRequest clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + SelectNetworksRequest copyWith( + void Function(SelectNetworksRequest) updates) => + super.copyWith((message) => updates(message as SelectNetworksRequest)) + as SelectNetworksRequest; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static SelectNetworksRequest create() => SelectNetworksRequest._(); + @$core.override + SelectNetworksRequest createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static SelectNetworksRequest getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static SelectNetworksRequest? _defaultInstance; + + @$pb.TagNumber(1) + $pb.PbList<$core.String> get networkIDs => $_getList(0); + + @$pb.TagNumber(2) + $core.bool get append => $_getBF(1); + @$pb.TagNumber(2) + set append($core.bool value) => $_setBool(1, value); + @$pb.TagNumber(2) + $core.bool hasAppend() => $_has(1); + @$pb.TagNumber(2) + void clearAppend() => $_clearField(2); + + @$pb.TagNumber(3) + $core.bool get all => $_getBF(2); + @$pb.TagNumber(3) + set all($core.bool value) => $_setBool(2, value); + @$pb.TagNumber(3) + $core.bool hasAll() => $_has(2); + @$pb.TagNumber(3) + void clearAll() => $_clearField(3); +} + +class SelectNetworksResponse extends $pb.GeneratedMessage { + factory SelectNetworksResponse() => create(); + + SelectNetworksResponse._(); + + factory SelectNetworksResponse.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory SelectNetworksResponse.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'SelectNetworksResponse', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + SelectNetworksResponse clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + SelectNetworksResponse copyWith( + void Function(SelectNetworksResponse) updates) => + super.copyWith((message) => updates(message as SelectNetworksResponse)) + as SelectNetworksResponse; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static SelectNetworksResponse create() => SelectNetworksResponse._(); + @$core.override + SelectNetworksResponse createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static SelectNetworksResponse getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static SelectNetworksResponse? _defaultInstance; +} + +class IPList extends $pb.GeneratedMessage { + factory IPList({ + $core.Iterable<$core.String>? ips, + }) { + final result = create(); + if (ips != null) result.ips.addAll(ips); + return result; + } + + IPList._(); + + factory IPList.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory IPList.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'IPList', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..pPS(1, _omitFieldNames ? '' : 'ips') + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + IPList clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + IPList copyWith(void Function(IPList) updates) => + super.copyWith((message) => updates(message as IPList)) as IPList; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static IPList create() => IPList._(); + @$core.override + IPList createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static IPList getDefault() => + _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static IPList? _defaultInstance; + + @$pb.TagNumber(1) + $pb.PbList<$core.String> get ips => $_getList(0); +} + +class Network extends $pb.GeneratedMessage { + factory Network({ + $core.String? iD, + $core.String? range, + $core.bool? selected, + $core.Iterable<$core.String>? domains, + $core.Iterable<$core.MapEntry<$core.String, IPList>>? resolvedIPs, + }) { + final result = create(); + if (iD != null) result.iD = iD; + if (range != null) result.range = range; + if (selected != null) result.selected = selected; + if (domains != null) result.domains.addAll(domains); + if (resolvedIPs != null) result.resolvedIPs.addEntries(resolvedIPs); + return result; + } + + Network._(); + + factory Network.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory Network.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'Network', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..aOS(1, _omitFieldNames ? '' : 'ID', protoName: 'ID') + ..aOS(2, _omitFieldNames ? '' : 'range') + ..aOB(3, _omitFieldNames ? '' : 'selected') + ..pPS(4, _omitFieldNames ? '' : 'domains') + ..m<$core.String, IPList>(5, _omitFieldNames ? '' : 'resolvedIPs', + protoName: 'resolvedIPs', + entryClassName: 'Network.ResolvedIPsEntry', + keyFieldType: $pb.PbFieldType.OS, + valueFieldType: $pb.PbFieldType.OM, + valueCreator: IPList.create, + valueDefaultOrMaker: IPList.getDefault, + packageName: const $pb.PackageName('daemon')) + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + Network clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + Network copyWith(void Function(Network) updates) => + super.copyWith((message) => updates(message as Network)) as Network; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static Network create() => Network._(); + @$core.override + Network createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static Network getDefault() => + _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static Network? _defaultInstance; + + @$pb.TagNumber(1) + $core.String get iD => $_getSZ(0); + @$pb.TagNumber(1) + set iD($core.String value) => $_setString(0, value); + @$pb.TagNumber(1) + $core.bool hasID() => $_has(0); + @$pb.TagNumber(1) + void clearID() => $_clearField(1); + + @$pb.TagNumber(2) + $core.String get range => $_getSZ(1); + @$pb.TagNumber(2) + set range($core.String value) => $_setString(1, value); + @$pb.TagNumber(2) + $core.bool hasRange() => $_has(1); + @$pb.TagNumber(2) + void clearRange() => $_clearField(2); + + @$pb.TagNumber(3) + $core.bool get selected => $_getBF(2); + @$pb.TagNumber(3) + set selected($core.bool value) => $_setBool(2, value); + @$pb.TagNumber(3) + $core.bool hasSelected() => $_has(2); + @$pb.TagNumber(3) + void clearSelected() => $_clearField(3); + + @$pb.TagNumber(4) + $pb.PbList<$core.String> get domains => $_getList(3); + + @$pb.TagNumber(5) + $pb.PbMap<$core.String, IPList> get resolvedIPs => $_getMap(4); +} + +class PortInfo_Range extends $pb.GeneratedMessage { + factory PortInfo_Range({ + $core.int? start, + $core.int? end, + }) { + final result = create(); + if (start != null) result.start = start; + if (end != null) result.end = end; + return result; + } + + PortInfo_Range._(); + + factory PortInfo_Range.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory PortInfo_Range.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'PortInfo.Range', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..aI(1, _omitFieldNames ? '' : 'start', fieldType: $pb.PbFieldType.OU3) + ..aI(2, _omitFieldNames ? '' : 'end', fieldType: $pb.PbFieldType.OU3) + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + PortInfo_Range clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + PortInfo_Range copyWith(void Function(PortInfo_Range) updates) => + super.copyWith((message) => updates(message as PortInfo_Range)) + as PortInfo_Range; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static PortInfo_Range create() => PortInfo_Range._(); + @$core.override + PortInfo_Range createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static PortInfo_Range getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static PortInfo_Range? _defaultInstance; + + @$pb.TagNumber(1) + $core.int get start => $_getIZ(0); + @$pb.TagNumber(1) + set start($core.int value) => $_setUnsignedInt32(0, value); + @$pb.TagNumber(1) + $core.bool hasStart() => $_has(0); + @$pb.TagNumber(1) + void clearStart() => $_clearField(1); + + @$pb.TagNumber(2) + $core.int get end => $_getIZ(1); + @$pb.TagNumber(2) + set end($core.int value) => $_setUnsignedInt32(1, value); + @$pb.TagNumber(2) + $core.bool hasEnd() => $_has(1); + @$pb.TagNumber(2) + void clearEnd() => $_clearField(2); +} + +enum PortInfo_PortSelection { port, range, notSet } + +/// ForwardingRules +class PortInfo extends $pb.GeneratedMessage { + factory PortInfo({ + $core.int? port, + PortInfo_Range? range, + }) { + final result = create(); + if (port != null) result.port = port; + if (range != null) result.range = range; + return result; + } + + PortInfo._(); + + factory PortInfo.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory PortInfo.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static const $core.Map<$core.int, PortInfo_PortSelection> + _PortInfo_PortSelectionByTag = { + 1: PortInfo_PortSelection.port, + 2: PortInfo_PortSelection.range, + 0: PortInfo_PortSelection.notSet + }; + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'PortInfo', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..oo(0, [1, 2]) + ..aI(1, _omitFieldNames ? '' : 'port', fieldType: $pb.PbFieldType.OU3) + ..aOM(2, _omitFieldNames ? '' : 'range', + subBuilder: PortInfo_Range.create) + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + PortInfo clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + PortInfo copyWith(void Function(PortInfo) updates) => + super.copyWith((message) => updates(message as PortInfo)) as PortInfo; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static PortInfo create() => PortInfo._(); + @$core.override + PortInfo createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static PortInfo getDefault() => + _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static PortInfo? _defaultInstance; + + @$pb.TagNumber(1) + @$pb.TagNumber(2) + PortInfo_PortSelection whichPortSelection() => + _PortInfo_PortSelectionByTag[$_whichOneof(0)]!; + @$pb.TagNumber(1) + @$pb.TagNumber(2) + void clearPortSelection() => $_clearField($_whichOneof(0)); + + @$pb.TagNumber(1) + $core.int get port => $_getIZ(0); + @$pb.TagNumber(1) + set port($core.int value) => $_setUnsignedInt32(0, value); + @$pb.TagNumber(1) + $core.bool hasPort() => $_has(0); + @$pb.TagNumber(1) + void clearPort() => $_clearField(1); + + @$pb.TagNumber(2) + PortInfo_Range get range => $_getN(1); + @$pb.TagNumber(2) + set range(PortInfo_Range value) => $_setField(2, value); + @$pb.TagNumber(2) + $core.bool hasRange() => $_has(1); + @$pb.TagNumber(2) + void clearRange() => $_clearField(2); + @$pb.TagNumber(2) + PortInfo_Range ensureRange() => $_ensure(1); +} + +class ForwardingRule extends $pb.GeneratedMessage { + factory ForwardingRule({ + $core.String? protocol, + PortInfo? destinationPort, + $core.String? translatedAddress, + $core.String? translatedHostname, + PortInfo? translatedPort, + }) { + final result = create(); + if (protocol != null) result.protocol = protocol; + if (destinationPort != null) result.destinationPort = destinationPort; + if (translatedAddress != null) result.translatedAddress = translatedAddress; + if (translatedHostname != null) + result.translatedHostname = translatedHostname; + if (translatedPort != null) result.translatedPort = translatedPort; + return result; + } + + ForwardingRule._(); + + factory ForwardingRule.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory ForwardingRule.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'ForwardingRule', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..aOS(1, _omitFieldNames ? '' : 'protocol') + ..aOM(2, _omitFieldNames ? '' : 'destinationPort', + protoName: 'destinationPort', subBuilder: PortInfo.create) + ..aOS(3, _omitFieldNames ? '' : 'translatedAddress', + protoName: 'translatedAddress') + ..aOS(4, _omitFieldNames ? '' : 'translatedHostname', + protoName: 'translatedHostname') + ..aOM(5, _omitFieldNames ? '' : 'translatedPort', + protoName: 'translatedPort', subBuilder: PortInfo.create) + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + ForwardingRule clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + ForwardingRule copyWith(void Function(ForwardingRule) updates) => + super.copyWith((message) => updates(message as ForwardingRule)) + as ForwardingRule; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static ForwardingRule create() => ForwardingRule._(); + @$core.override + ForwardingRule createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static ForwardingRule getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static ForwardingRule? _defaultInstance; + + @$pb.TagNumber(1) + $core.String get protocol => $_getSZ(0); + @$pb.TagNumber(1) + set protocol($core.String value) => $_setString(0, value); + @$pb.TagNumber(1) + $core.bool hasProtocol() => $_has(0); + @$pb.TagNumber(1) + void clearProtocol() => $_clearField(1); + + @$pb.TagNumber(2) + PortInfo get destinationPort => $_getN(1); + @$pb.TagNumber(2) + set destinationPort(PortInfo value) => $_setField(2, value); + @$pb.TagNumber(2) + $core.bool hasDestinationPort() => $_has(1); + @$pb.TagNumber(2) + void clearDestinationPort() => $_clearField(2); + @$pb.TagNumber(2) + PortInfo ensureDestinationPort() => $_ensure(1); + + @$pb.TagNumber(3) + $core.String get translatedAddress => $_getSZ(2); + @$pb.TagNumber(3) + set translatedAddress($core.String value) => $_setString(2, value); + @$pb.TagNumber(3) + $core.bool hasTranslatedAddress() => $_has(2); + @$pb.TagNumber(3) + void clearTranslatedAddress() => $_clearField(3); + + @$pb.TagNumber(4) + $core.String get translatedHostname => $_getSZ(3); + @$pb.TagNumber(4) + set translatedHostname($core.String value) => $_setString(3, value); + @$pb.TagNumber(4) + $core.bool hasTranslatedHostname() => $_has(3); + @$pb.TagNumber(4) + void clearTranslatedHostname() => $_clearField(4); + + @$pb.TagNumber(5) + PortInfo get translatedPort => $_getN(4); + @$pb.TagNumber(5) + set translatedPort(PortInfo value) => $_setField(5, value); + @$pb.TagNumber(5) + $core.bool hasTranslatedPort() => $_has(4); + @$pb.TagNumber(5) + void clearTranslatedPort() => $_clearField(5); + @$pb.TagNumber(5) + PortInfo ensureTranslatedPort() => $_ensure(4); +} + +class ForwardingRulesResponse extends $pb.GeneratedMessage { + factory ForwardingRulesResponse({ + $core.Iterable? rules, + }) { + final result = create(); + if (rules != null) result.rules.addAll(rules); + return result; + } + + ForwardingRulesResponse._(); + + factory ForwardingRulesResponse.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory ForwardingRulesResponse.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'ForwardingRulesResponse', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..pPM(1, _omitFieldNames ? '' : 'rules', + subBuilder: ForwardingRule.create) + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + ForwardingRulesResponse clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + ForwardingRulesResponse copyWith( + void Function(ForwardingRulesResponse) updates) => + super.copyWith((message) => updates(message as ForwardingRulesResponse)) + as ForwardingRulesResponse; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static ForwardingRulesResponse create() => ForwardingRulesResponse._(); + @$core.override + ForwardingRulesResponse createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static ForwardingRulesResponse getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static ForwardingRulesResponse? _defaultInstance; + + @$pb.TagNumber(1) + $pb.PbList get rules => $_getList(0); +} + +/// DebugBundler +class DebugBundleRequest extends $pb.GeneratedMessage { + factory DebugBundleRequest({ + $core.bool? anonymize, + $core.bool? systemInfo, + $core.String? uploadURL, + $core.int? logFileCount, + }) { + final result = create(); + if (anonymize != null) result.anonymize = anonymize; + if (systemInfo != null) result.systemInfo = systemInfo; + if (uploadURL != null) result.uploadURL = uploadURL; + if (logFileCount != null) result.logFileCount = logFileCount; + return result; + } + + DebugBundleRequest._(); + + factory DebugBundleRequest.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory DebugBundleRequest.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'DebugBundleRequest', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..aOB(1, _omitFieldNames ? '' : 'anonymize') + ..aOB(3, _omitFieldNames ? '' : 'systemInfo', protoName: 'systemInfo') + ..aOS(4, _omitFieldNames ? '' : 'uploadURL', protoName: 'uploadURL') + ..aI(5, _omitFieldNames ? '' : 'logFileCount', + protoName: 'logFileCount', fieldType: $pb.PbFieldType.OU3) + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + DebugBundleRequest clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + DebugBundleRequest copyWith(void Function(DebugBundleRequest) updates) => + super.copyWith((message) => updates(message as DebugBundleRequest)) + as DebugBundleRequest; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static DebugBundleRequest create() => DebugBundleRequest._(); + @$core.override + DebugBundleRequest createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static DebugBundleRequest getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static DebugBundleRequest? _defaultInstance; + + @$pb.TagNumber(1) + $core.bool get anonymize => $_getBF(0); + @$pb.TagNumber(1) + set anonymize($core.bool value) => $_setBool(0, value); + @$pb.TagNumber(1) + $core.bool hasAnonymize() => $_has(0); + @$pb.TagNumber(1) + void clearAnonymize() => $_clearField(1); + + @$pb.TagNumber(3) + $core.bool get systemInfo => $_getBF(1); + @$pb.TagNumber(3) + set systemInfo($core.bool value) => $_setBool(1, value); + @$pb.TagNumber(3) + $core.bool hasSystemInfo() => $_has(1); + @$pb.TagNumber(3) + void clearSystemInfo() => $_clearField(3); + + @$pb.TagNumber(4) + $core.String get uploadURL => $_getSZ(2); + @$pb.TagNumber(4) + set uploadURL($core.String value) => $_setString(2, value); + @$pb.TagNumber(4) + $core.bool hasUploadURL() => $_has(2); + @$pb.TagNumber(4) + void clearUploadURL() => $_clearField(4); + + @$pb.TagNumber(5) + $core.int get logFileCount => $_getIZ(3); + @$pb.TagNumber(5) + set logFileCount($core.int value) => $_setUnsignedInt32(3, value); + @$pb.TagNumber(5) + $core.bool hasLogFileCount() => $_has(3); + @$pb.TagNumber(5) + void clearLogFileCount() => $_clearField(5); +} + +class DebugBundleResponse extends $pb.GeneratedMessage { + factory DebugBundleResponse({ + $core.String? path, + $core.String? uploadedKey, + $core.String? uploadFailureReason, + }) { + final result = create(); + if (path != null) result.path = path; + if (uploadedKey != null) result.uploadedKey = uploadedKey; + if (uploadFailureReason != null) + result.uploadFailureReason = uploadFailureReason; + return result; + } + + DebugBundleResponse._(); + + factory DebugBundleResponse.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory DebugBundleResponse.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'DebugBundleResponse', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..aOS(1, _omitFieldNames ? '' : 'path') + ..aOS(2, _omitFieldNames ? '' : 'uploadedKey', protoName: 'uploadedKey') + ..aOS(3, _omitFieldNames ? '' : 'uploadFailureReason', + protoName: 'uploadFailureReason') + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + DebugBundleResponse clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + DebugBundleResponse copyWith(void Function(DebugBundleResponse) updates) => + super.copyWith((message) => updates(message as DebugBundleResponse)) + as DebugBundleResponse; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static DebugBundleResponse create() => DebugBundleResponse._(); + @$core.override + DebugBundleResponse createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static DebugBundleResponse getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static DebugBundleResponse? _defaultInstance; + + @$pb.TagNumber(1) + $core.String get path => $_getSZ(0); + @$pb.TagNumber(1) + set path($core.String value) => $_setString(0, value); + @$pb.TagNumber(1) + $core.bool hasPath() => $_has(0); + @$pb.TagNumber(1) + void clearPath() => $_clearField(1); + + @$pb.TagNumber(2) + $core.String get uploadedKey => $_getSZ(1); + @$pb.TagNumber(2) + set uploadedKey($core.String value) => $_setString(1, value); + @$pb.TagNumber(2) + $core.bool hasUploadedKey() => $_has(1); + @$pb.TagNumber(2) + void clearUploadedKey() => $_clearField(2); + + @$pb.TagNumber(3) + $core.String get uploadFailureReason => $_getSZ(2); + @$pb.TagNumber(3) + set uploadFailureReason($core.String value) => $_setString(2, value); + @$pb.TagNumber(3) + $core.bool hasUploadFailureReason() => $_has(2); + @$pb.TagNumber(3) + void clearUploadFailureReason() => $_clearField(3); +} + +class GetLogLevelRequest extends $pb.GeneratedMessage { + factory GetLogLevelRequest() => create(); + + GetLogLevelRequest._(); + + factory GetLogLevelRequest.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory GetLogLevelRequest.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'GetLogLevelRequest', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + GetLogLevelRequest clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + GetLogLevelRequest copyWith(void Function(GetLogLevelRequest) updates) => + super.copyWith((message) => updates(message as GetLogLevelRequest)) + as GetLogLevelRequest; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static GetLogLevelRequest create() => GetLogLevelRequest._(); + @$core.override + GetLogLevelRequest createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static GetLogLevelRequest getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static GetLogLevelRequest? _defaultInstance; +} + +class GetLogLevelResponse extends $pb.GeneratedMessage { + factory GetLogLevelResponse({ + LogLevel? level, + }) { + final result = create(); + if (level != null) result.level = level; + return result; + } + + GetLogLevelResponse._(); + + factory GetLogLevelResponse.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory GetLogLevelResponse.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'GetLogLevelResponse', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..aE(1, _omitFieldNames ? '' : 'level', + enumValues: LogLevel.values) + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + GetLogLevelResponse clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + GetLogLevelResponse copyWith(void Function(GetLogLevelResponse) updates) => + super.copyWith((message) => updates(message as GetLogLevelResponse)) + as GetLogLevelResponse; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static GetLogLevelResponse create() => GetLogLevelResponse._(); + @$core.override + GetLogLevelResponse createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static GetLogLevelResponse getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static GetLogLevelResponse? _defaultInstance; + + @$pb.TagNumber(1) + LogLevel get level => $_getN(0); + @$pb.TagNumber(1) + set level(LogLevel value) => $_setField(1, value); + @$pb.TagNumber(1) + $core.bool hasLevel() => $_has(0); + @$pb.TagNumber(1) + void clearLevel() => $_clearField(1); +} + +class SetLogLevelRequest extends $pb.GeneratedMessage { + factory SetLogLevelRequest({ + LogLevel? level, + }) { + final result = create(); + if (level != null) result.level = level; + return result; + } + + SetLogLevelRequest._(); + + factory SetLogLevelRequest.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory SetLogLevelRequest.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'SetLogLevelRequest', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..aE(1, _omitFieldNames ? '' : 'level', + enumValues: LogLevel.values) + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + SetLogLevelRequest clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + SetLogLevelRequest copyWith(void Function(SetLogLevelRequest) updates) => + super.copyWith((message) => updates(message as SetLogLevelRequest)) + as SetLogLevelRequest; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static SetLogLevelRequest create() => SetLogLevelRequest._(); + @$core.override + SetLogLevelRequest createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static SetLogLevelRequest getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static SetLogLevelRequest? _defaultInstance; + + @$pb.TagNumber(1) + LogLevel get level => $_getN(0); + @$pb.TagNumber(1) + set level(LogLevel value) => $_setField(1, value); + @$pb.TagNumber(1) + $core.bool hasLevel() => $_has(0); + @$pb.TagNumber(1) + void clearLevel() => $_clearField(1); +} + +class SetLogLevelResponse extends $pb.GeneratedMessage { + factory SetLogLevelResponse() => create(); + + SetLogLevelResponse._(); + + factory SetLogLevelResponse.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory SetLogLevelResponse.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'SetLogLevelResponse', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + SetLogLevelResponse clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + SetLogLevelResponse copyWith(void Function(SetLogLevelResponse) updates) => + super.copyWith((message) => updates(message as SetLogLevelResponse)) + as SetLogLevelResponse; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static SetLogLevelResponse create() => SetLogLevelResponse._(); + @$core.override + SetLogLevelResponse createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static SetLogLevelResponse getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static SetLogLevelResponse? _defaultInstance; +} + +/// State represents a daemon state entry +class State extends $pb.GeneratedMessage { + factory State({ + $core.String? name, + }) { + final result = create(); + if (name != null) result.name = name; + return result; + } + + State._(); + + factory State.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory State.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'State', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..aOS(1, _omitFieldNames ? '' : 'name') + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + State clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + State copyWith(void Function(State) updates) => + super.copyWith((message) => updates(message as State)) as State; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static State create() => State._(); + @$core.override + State createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static State getDefault() => + _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static State? _defaultInstance; + + @$pb.TagNumber(1) + $core.String get name => $_getSZ(0); + @$pb.TagNumber(1) + set name($core.String value) => $_setString(0, value); + @$pb.TagNumber(1) + $core.bool hasName() => $_has(0); + @$pb.TagNumber(1) + void clearName() => $_clearField(1); +} + +/// ListStatesRequest is empty as it requires no parameters +class ListStatesRequest extends $pb.GeneratedMessage { + factory ListStatesRequest() => create(); + + ListStatesRequest._(); + + factory ListStatesRequest.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory ListStatesRequest.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'ListStatesRequest', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + ListStatesRequest clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + ListStatesRequest copyWith(void Function(ListStatesRequest) updates) => + super.copyWith((message) => updates(message as ListStatesRequest)) + as ListStatesRequest; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static ListStatesRequest create() => ListStatesRequest._(); + @$core.override + ListStatesRequest createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static ListStatesRequest getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static ListStatesRequest? _defaultInstance; +} + +/// ListStatesResponse contains a list of states +class ListStatesResponse extends $pb.GeneratedMessage { + factory ListStatesResponse({ + $core.Iterable? states, + }) { + final result = create(); + if (states != null) result.states.addAll(states); + return result; + } + + ListStatesResponse._(); + + factory ListStatesResponse.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory ListStatesResponse.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'ListStatesResponse', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..pPM(1, _omitFieldNames ? '' : 'states', subBuilder: State.create) + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + ListStatesResponse clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + ListStatesResponse copyWith(void Function(ListStatesResponse) updates) => + super.copyWith((message) => updates(message as ListStatesResponse)) + as ListStatesResponse; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static ListStatesResponse create() => ListStatesResponse._(); + @$core.override + ListStatesResponse createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static ListStatesResponse getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static ListStatesResponse? _defaultInstance; + + @$pb.TagNumber(1) + $pb.PbList get states => $_getList(0); +} + +/// CleanStateRequest for cleaning states +class CleanStateRequest extends $pb.GeneratedMessage { + factory CleanStateRequest({ + $core.String? stateName, + $core.bool? all, + }) { + final result = create(); + if (stateName != null) result.stateName = stateName; + if (all != null) result.all = all; + return result; + } + + CleanStateRequest._(); + + factory CleanStateRequest.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory CleanStateRequest.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'CleanStateRequest', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..aOS(1, _omitFieldNames ? '' : 'stateName') + ..aOB(2, _omitFieldNames ? '' : 'all') + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + CleanStateRequest clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + CleanStateRequest copyWith(void Function(CleanStateRequest) updates) => + super.copyWith((message) => updates(message as CleanStateRequest)) + as CleanStateRequest; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static CleanStateRequest create() => CleanStateRequest._(); + @$core.override + CleanStateRequest createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static CleanStateRequest getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static CleanStateRequest? _defaultInstance; + + @$pb.TagNumber(1) + $core.String get stateName => $_getSZ(0); + @$pb.TagNumber(1) + set stateName($core.String value) => $_setString(0, value); + @$pb.TagNumber(1) + $core.bool hasStateName() => $_has(0); + @$pb.TagNumber(1) + void clearStateName() => $_clearField(1); + + @$pb.TagNumber(2) + $core.bool get all => $_getBF(1); + @$pb.TagNumber(2) + set all($core.bool value) => $_setBool(1, value); + @$pb.TagNumber(2) + $core.bool hasAll() => $_has(1); + @$pb.TagNumber(2) + void clearAll() => $_clearField(2); +} + +/// CleanStateResponse contains the result of the clean operation +class CleanStateResponse extends $pb.GeneratedMessage { + factory CleanStateResponse({ + $core.int? cleanedStates, + }) { + final result = create(); + if (cleanedStates != null) result.cleanedStates = cleanedStates; + return result; + } + + CleanStateResponse._(); + + factory CleanStateResponse.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory CleanStateResponse.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'CleanStateResponse', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..aI(1, _omitFieldNames ? '' : 'cleanedStates') + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + CleanStateResponse clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + CleanStateResponse copyWith(void Function(CleanStateResponse) updates) => + super.copyWith((message) => updates(message as CleanStateResponse)) + as CleanStateResponse; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static CleanStateResponse create() => CleanStateResponse._(); + @$core.override + CleanStateResponse createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static CleanStateResponse getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static CleanStateResponse? _defaultInstance; + + @$pb.TagNumber(1) + $core.int get cleanedStates => $_getIZ(0); + @$pb.TagNumber(1) + set cleanedStates($core.int value) => $_setSignedInt32(0, value); + @$pb.TagNumber(1) + $core.bool hasCleanedStates() => $_has(0); + @$pb.TagNumber(1) + void clearCleanedStates() => $_clearField(1); +} + +/// DeleteStateRequest for deleting states +class DeleteStateRequest extends $pb.GeneratedMessage { + factory DeleteStateRequest({ + $core.String? stateName, + $core.bool? all, + }) { + final result = create(); + if (stateName != null) result.stateName = stateName; + if (all != null) result.all = all; + return result; + } + + DeleteStateRequest._(); + + factory DeleteStateRequest.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory DeleteStateRequest.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'DeleteStateRequest', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..aOS(1, _omitFieldNames ? '' : 'stateName') + ..aOB(2, _omitFieldNames ? '' : 'all') + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + DeleteStateRequest clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + DeleteStateRequest copyWith(void Function(DeleteStateRequest) updates) => + super.copyWith((message) => updates(message as DeleteStateRequest)) + as DeleteStateRequest; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static DeleteStateRequest create() => DeleteStateRequest._(); + @$core.override + DeleteStateRequest createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static DeleteStateRequest getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static DeleteStateRequest? _defaultInstance; + + @$pb.TagNumber(1) + $core.String get stateName => $_getSZ(0); + @$pb.TagNumber(1) + set stateName($core.String value) => $_setString(0, value); + @$pb.TagNumber(1) + $core.bool hasStateName() => $_has(0); + @$pb.TagNumber(1) + void clearStateName() => $_clearField(1); + + @$pb.TagNumber(2) + $core.bool get all => $_getBF(1); + @$pb.TagNumber(2) + set all($core.bool value) => $_setBool(1, value); + @$pb.TagNumber(2) + $core.bool hasAll() => $_has(1); + @$pb.TagNumber(2) + void clearAll() => $_clearField(2); +} + +/// DeleteStateResponse contains the result of the delete operation +class DeleteStateResponse extends $pb.GeneratedMessage { + factory DeleteStateResponse({ + $core.int? deletedStates, + }) { + final result = create(); + if (deletedStates != null) result.deletedStates = deletedStates; + return result; + } + + DeleteStateResponse._(); + + factory DeleteStateResponse.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory DeleteStateResponse.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'DeleteStateResponse', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..aI(1, _omitFieldNames ? '' : 'deletedStates') + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + DeleteStateResponse clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + DeleteStateResponse copyWith(void Function(DeleteStateResponse) updates) => + super.copyWith((message) => updates(message as DeleteStateResponse)) + as DeleteStateResponse; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static DeleteStateResponse create() => DeleteStateResponse._(); + @$core.override + DeleteStateResponse createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static DeleteStateResponse getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static DeleteStateResponse? _defaultInstance; + + @$pb.TagNumber(1) + $core.int get deletedStates => $_getIZ(0); + @$pb.TagNumber(1) + set deletedStates($core.int value) => $_setSignedInt32(0, value); + @$pb.TagNumber(1) + $core.bool hasDeletedStates() => $_has(0); + @$pb.TagNumber(1) + void clearDeletedStates() => $_clearField(1); +} + +class SetSyncResponsePersistenceRequest extends $pb.GeneratedMessage { + factory SetSyncResponsePersistenceRequest({ + $core.bool? enabled, + }) { + final result = create(); + if (enabled != null) result.enabled = enabled; + return result; + } + + SetSyncResponsePersistenceRequest._(); + + factory SetSyncResponsePersistenceRequest.fromBuffer( + $core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory SetSyncResponsePersistenceRequest.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'SetSyncResponsePersistenceRequest', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..aOB(1, _omitFieldNames ? '' : 'enabled') + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + SetSyncResponsePersistenceRequest clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + SetSyncResponsePersistenceRequest copyWith( + void Function(SetSyncResponsePersistenceRequest) updates) => + super.copyWith((message) => + updates(message as SetSyncResponsePersistenceRequest)) + as SetSyncResponsePersistenceRequest; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static SetSyncResponsePersistenceRequest create() => + SetSyncResponsePersistenceRequest._(); + @$core.override + SetSyncResponsePersistenceRequest createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static SetSyncResponsePersistenceRequest getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor( + create); + static SetSyncResponsePersistenceRequest? _defaultInstance; + + @$pb.TagNumber(1) + $core.bool get enabled => $_getBF(0); + @$pb.TagNumber(1) + set enabled($core.bool value) => $_setBool(0, value); + @$pb.TagNumber(1) + $core.bool hasEnabled() => $_has(0); + @$pb.TagNumber(1) + void clearEnabled() => $_clearField(1); +} + +class SetSyncResponsePersistenceResponse extends $pb.GeneratedMessage { + factory SetSyncResponsePersistenceResponse() => create(); + + SetSyncResponsePersistenceResponse._(); + + factory SetSyncResponsePersistenceResponse.fromBuffer( + $core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory SetSyncResponsePersistenceResponse.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'SetSyncResponsePersistenceResponse', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + SetSyncResponsePersistenceResponse clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + SetSyncResponsePersistenceResponse copyWith( + void Function(SetSyncResponsePersistenceResponse) updates) => + super.copyWith((message) => + updates(message as SetSyncResponsePersistenceResponse)) + as SetSyncResponsePersistenceResponse; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static SetSyncResponsePersistenceResponse create() => + SetSyncResponsePersistenceResponse._(); + @$core.override + SetSyncResponsePersistenceResponse createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static SetSyncResponsePersistenceResponse getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor( + create); + static SetSyncResponsePersistenceResponse? _defaultInstance; +} + +class TCPFlags extends $pb.GeneratedMessage { + factory TCPFlags({ + $core.bool? syn, + $core.bool? ack, + $core.bool? fin, + $core.bool? rst, + $core.bool? psh, + $core.bool? urg, + }) { + final result = create(); + if (syn != null) result.syn = syn; + if (ack != null) result.ack = ack; + if (fin != null) result.fin = fin; + if (rst != null) result.rst = rst; + if (psh != null) result.psh = psh; + if (urg != null) result.urg = urg; + return result; + } + + TCPFlags._(); + + factory TCPFlags.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory TCPFlags.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'TCPFlags', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..aOB(1, _omitFieldNames ? '' : 'syn') + ..aOB(2, _omitFieldNames ? '' : 'ack') + ..aOB(3, _omitFieldNames ? '' : 'fin') + ..aOB(4, _omitFieldNames ? '' : 'rst') + ..aOB(5, _omitFieldNames ? '' : 'psh') + ..aOB(6, _omitFieldNames ? '' : 'urg') + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + TCPFlags clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + TCPFlags copyWith(void Function(TCPFlags) updates) => + super.copyWith((message) => updates(message as TCPFlags)) as TCPFlags; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static TCPFlags create() => TCPFlags._(); + @$core.override + TCPFlags createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static TCPFlags getDefault() => + _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static TCPFlags? _defaultInstance; + + @$pb.TagNumber(1) + $core.bool get syn => $_getBF(0); + @$pb.TagNumber(1) + set syn($core.bool value) => $_setBool(0, value); + @$pb.TagNumber(1) + $core.bool hasSyn() => $_has(0); + @$pb.TagNumber(1) + void clearSyn() => $_clearField(1); + + @$pb.TagNumber(2) + $core.bool get ack => $_getBF(1); + @$pb.TagNumber(2) + set ack($core.bool value) => $_setBool(1, value); + @$pb.TagNumber(2) + $core.bool hasAck() => $_has(1); + @$pb.TagNumber(2) + void clearAck() => $_clearField(2); + + @$pb.TagNumber(3) + $core.bool get fin => $_getBF(2); + @$pb.TagNumber(3) + set fin($core.bool value) => $_setBool(2, value); + @$pb.TagNumber(3) + $core.bool hasFin() => $_has(2); + @$pb.TagNumber(3) + void clearFin() => $_clearField(3); + + @$pb.TagNumber(4) + $core.bool get rst => $_getBF(3); + @$pb.TagNumber(4) + set rst($core.bool value) => $_setBool(3, value); + @$pb.TagNumber(4) + $core.bool hasRst() => $_has(3); + @$pb.TagNumber(4) + void clearRst() => $_clearField(4); + + @$pb.TagNumber(5) + $core.bool get psh => $_getBF(4); + @$pb.TagNumber(5) + set psh($core.bool value) => $_setBool(4, value); + @$pb.TagNumber(5) + $core.bool hasPsh() => $_has(4); + @$pb.TagNumber(5) + void clearPsh() => $_clearField(5); + + @$pb.TagNumber(6) + $core.bool get urg => $_getBF(5); + @$pb.TagNumber(6) + set urg($core.bool value) => $_setBool(5, value); + @$pb.TagNumber(6) + $core.bool hasUrg() => $_has(5); + @$pb.TagNumber(6) + void clearUrg() => $_clearField(6); +} + +class TracePacketRequest extends $pb.GeneratedMessage { + factory TracePacketRequest({ + $core.String? sourceIp, + $core.String? destinationIp, + $core.String? protocol, + $core.int? sourcePort, + $core.int? destinationPort, + $core.String? direction, + TCPFlags? tcpFlags, + $core.int? icmpType, + $core.int? icmpCode, + }) { + final result = create(); + if (sourceIp != null) result.sourceIp = sourceIp; + if (destinationIp != null) result.destinationIp = destinationIp; + if (protocol != null) result.protocol = protocol; + if (sourcePort != null) result.sourcePort = sourcePort; + if (destinationPort != null) result.destinationPort = destinationPort; + if (direction != null) result.direction = direction; + if (tcpFlags != null) result.tcpFlags = tcpFlags; + if (icmpType != null) result.icmpType = icmpType; + if (icmpCode != null) result.icmpCode = icmpCode; + return result; + } + + TracePacketRequest._(); + + factory TracePacketRequest.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory TracePacketRequest.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'TracePacketRequest', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..aOS(1, _omitFieldNames ? '' : 'sourceIp') + ..aOS(2, _omitFieldNames ? '' : 'destinationIp') + ..aOS(3, _omitFieldNames ? '' : 'protocol') + ..aI(4, _omitFieldNames ? '' : 'sourcePort', fieldType: $pb.PbFieldType.OU3) + ..aI(5, _omitFieldNames ? '' : 'destinationPort', + fieldType: $pb.PbFieldType.OU3) + ..aOS(6, _omitFieldNames ? '' : 'direction') + ..aOM(7, _omitFieldNames ? '' : 'tcpFlags', + subBuilder: TCPFlags.create) + ..aI(8, _omitFieldNames ? '' : 'icmpType', fieldType: $pb.PbFieldType.OU3) + ..aI(9, _omitFieldNames ? '' : 'icmpCode', fieldType: $pb.PbFieldType.OU3) + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + TracePacketRequest clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + TracePacketRequest copyWith(void Function(TracePacketRequest) updates) => + super.copyWith((message) => updates(message as TracePacketRequest)) + as TracePacketRequest; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static TracePacketRequest create() => TracePacketRequest._(); + @$core.override + TracePacketRequest createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static TracePacketRequest getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static TracePacketRequest? _defaultInstance; + + @$pb.TagNumber(1) + $core.String get sourceIp => $_getSZ(0); + @$pb.TagNumber(1) + set sourceIp($core.String value) => $_setString(0, value); + @$pb.TagNumber(1) + $core.bool hasSourceIp() => $_has(0); + @$pb.TagNumber(1) + void clearSourceIp() => $_clearField(1); + + @$pb.TagNumber(2) + $core.String get destinationIp => $_getSZ(1); + @$pb.TagNumber(2) + set destinationIp($core.String value) => $_setString(1, value); + @$pb.TagNumber(2) + $core.bool hasDestinationIp() => $_has(1); + @$pb.TagNumber(2) + void clearDestinationIp() => $_clearField(2); + + @$pb.TagNumber(3) + $core.String get protocol => $_getSZ(2); + @$pb.TagNumber(3) + set protocol($core.String value) => $_setString(2, value); + @$pb.TagNumber(3) + $core.bool hasProtocol() => $_has(2); + @$pb.TagNumber(3) + void clearProtocol() => $_clearField(3); + + @$pb.TagNumber(4) + $core.int get sourcePort => $_getIZ(3); + @$pb.TagNumber(4) + set sourcePort($core.int value) => $_setUnsignedInt32(3, value); + @$pb.TagNumber(4) + $core.bool hasSourcePort() => $_has(3); + @$pb.TagNumber(4) + void clearSourcePort() => $_clearField(4); + + @$pb.TagNumber(5) + $core.int get destinationPort => $_getIZ(4); + @$pb.TagNumber(5) + set destinationPort($core.int value) => $_setUnsignedInt32(4, value); + @$pb.TagNumber(5) + $core.bool hasDestinationPort() => $_has(4); + @$pb.TagNumber(5) + void clearDestinationPort() => $_clearField(5); + + @$pb.TagNumber(6) + $core.String get direction => $_getSZ(5); + @$pb.TagNumber(6) + set direction($core.String value) => $_setString(5, value); + @$pb.TagNumber(6) + $core.bool hasDirection() => $_has(5); + @$pb.TagNumber(6) + void clearDirection() => $_clearField(6); + + @$pb.TagNumber(7) + TCPFlags get tcpFlags => $_getN(6); + @$pb.TagNumber(7) + set tcpFlags(TCPFlags value) => $_setField(7, value); + @$pb.TagNumber(7) + $core.bool hasTcpFlags() => $_has(6); + @$pb.TagNumber(7) + void clearTcpFlags() => $_clearField(7); + @$pb.TagNumber(7) + TCPFlags ensureTcpFlags() => $_ensure(6); + + @$pb.TagNumber(8) + $core.int get icmpType => $_getIZ(7); + @$pb.TagNumber(8) + set icmpType($core.int value) => $_setUnsignedInt32(7, value); + @$pb.TagNumber(8) + $core.bool hasIcmpType() => $_has(7); + @$pb.TagNumber(8) + void clearIcmpType() => $_clearField(8); + + @$pb.TagNumber(9) + $core.int get icmpCode => $_getIZ(8); + @$pb.TagNumber(9) + set icmpCode($core.int value) => $_setUnsignedInt32(8, value); + @$pb.TagNumber(9) + $core.bool hasIcmpCode() => $_has(8); + @$pb.TagNumber(9) + void clearIcmpCode() => $_clearField(9); +} + +class TraceStage extends $pb.GeneratedMessage { + factory TraceStage({ + $core.String? name, + $core.String? message, + $core.bool? allowed, + $core.String? forwardingDetails, + }) { + final result = create(); + if (name != null) result.name = name; + if (message != null) result.message = message; + if (allowed != null) result.allowed = allowed; + if (forwardingDetails != null) result.forwardingDetails = forwardingDetails; + return result; + } + + TraceStage._(); + + factory TraceStage.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory TraceStage.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'TraceStage', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..aOS(1, _omitFieldNames ? '' : 'name') + ..aOS(2, _omitFieldNames ? '' : 'message') + ..aOB(3, _omitFieldNames ? '' : 'allowed') + ..aOS(4, _omitFieldNames ? '' : 'forwardingDetails') + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + TraceStage clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + TraceStage copyWith(void Function(TraceStage) updates) => + super.copyWith((message) => updates(message as TraceStage)) as TraceStage; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static TraceStage create() => TraceStage._(); + @$core.override + TraceStage createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static TraceStage getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static TraceStage? _defaultInstance; + + @$pb.TagNumber(1) + $core.String get name => $_getSZ(0); + @$pb.TagNumber(1) + set name($core.String value) => $_setString(0, value); + @$pb.TagNumber(1) + $core.bool hasName() => $_has(0); + @$pb.TagNumber(1) + void clearName() => $_clearField(1); + + @$pb.TagNumber(2) + $core.String get message => $_getSZ(1); + @$pb.TagNumber(2) + set message($core.String value) => $_setString(1, value); + @$pb.TagNumber(2) + $core.bool hasMessage() => $_has(1); + @$pb.TagNumber(2) + void clearMessage() => $_clearField(2); + + @$pb.TagNumber(3) + $core.bool get allowed => $_getBF(2); + @$pb.TagNumber(3) + set allowed($core.bool value) => $_setBool(2, value); + @$pb.TagNumber(3) + $core.bool hasAllowed() => $_has(2); + @$pb.TagNumber(3) + void clearAllowed() => $_clearField(3); + + @$pb.TagNumber(4) + $core.String get forwardingDetails => $_getSZ(3); + @$pb.TagNumber(4) + set forwardingDetails($core.String value) => $_setString(3, value); + @$pb.TagNumber(4) + $core.bool hasForwardingDetails() => $_has(3); + @$pb.TagNumber(4) + void clearForwardingDetails() => $_clearField(4); +} + +class TracePacketResponse extends $pb.GeneratedMessage { + factory TracePacketResponse({ + $core.Iterable? stages, + $core.bool? finalDisposition, + }) { + final result = create(); + if (stages != null) result.stages.addAll(stages); + if (finalDisposition != null) result.finalDisposition = finalDisposition; + return result; + } + + TracePacketResponse._(); + + factory TracePacketResponse.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory TracePacketResponse.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'TracePacketResponse', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..pPM(1, _omitFieldNames ? '' : 'stages', + subBuilder: TraceStage.create) + ..aOB(2, _omitFieldNames ? '' : 'finalDisposition') + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + TracePacketResponse clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + TracePacketResponse copyWith(void Function(TracePacketResponse) updates) => + super.copyWith((message) => updates(message as TracePacketResponse)) + as TracePacketResponse; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static TracePacketResponse create() => TracePacketResponse._(); + @$core.override + TracePacketResponse createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static TracePacketResponse getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static TracePacketResponse? _defaultInstance; + + @$pb.TagNumber(1) + $pb.PbList get stages => $_getList(0); + + @$pb.TagNumber(2) + $core.bool get finalDisposition => $_getBF(1); + @$pb.TagNumber(2) + set finalDisposition($core.bool value) => $_setBool(1, value); + @$pb.TagNumber(2) + $core.bool hasFinalDisposition() => $_has(1); + @$pb.TagNumber(2) + void clearFinalDisposition() => $_clearField(2); +} + +class SubscribeRequest extends $pb.GeneratedMessage { + factory SubscribeRequest() => create(); + + SubscribeRequest._(); + + factory SubscribeRequest.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory SubscribeRequest.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'SubscribeRequest', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + SubscribeRequest clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + SubscribeRequest copyWith(void Function(SubscribeRequest) updates) => + super.copyWith((message) => updates(message as SubscribeRequest)) + as SubscribeRequest; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static SubscribeRequest create() => SubscribeRequest._(); + @$core.override + SubscribeRequest createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static SubscribeRequest getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static SubscribeRequest? _defaultInstance; +} + +class SystemEvent extends $pb.GeneratedMessage { + factory SystemEvent({ + $core.String? id, + SystemEvent_Severity? severity, + SystemEvent_Category? category, + $core.String? message, + $core.String? userMessage, + $2.Timestamp? timestamp, + $core.Iterable<$core.MapEntry<$core.String, $core.String>>? metadata, + }) { + final result = create(); + if (id != null) result.id = id; + if (severity != null) result.severity = severity; + if (category != null) result.category = category; + if (message != null) result.message = message; + if (userMessage != null) result.userMessage = userMessage; + if (timestamp != null) result.timestamp = timestamp; + if (metadata != null) result.metadata.addEntries(metadata); + return result; + } + + SystemEvent._(); + + factory SystemEvent.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory SystemEvent.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'SystemEvent', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..aOS(1, _omitFieldNames ? '' : 'id') + ..aE(2, _omitFieldNames ? '' : 'severity', + enumValues: SystemEvent_Severity.values) + ..aE(3, _omitFieldNames ? '' : 'category', + enumValues: SystemEvent_Category.values) + ..aOS(4, _omitFieldNames ? '' : 'message') + ..aOS(5, _omitFieldNames ? '' : 'userMessage', protoName: 'userMessage') + ..aOM<$2.Timestamp>(6, _omitFieldNames ? '' : 'timestamp', + subBuilder: $2.Timestamp.create) + ..m<$core.String, $core.String>(7, _omitFieldNames ? '' : 'metadata', + entryClassName: 'SystemEvent.MetadataEntry', + keyFieldType: $pb.PbFieldType.OS, + valueFieldType: $pb.PbFieldType.OS, + packageName: const $pb.PackageName('daemon')) + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + SystemEvent clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + SystemEvent copyWith(void Function(SystemEvent) updates) => + super.copyWith((message) => updates(message as SystemEvent)) + as SystemEvent; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static SystemEvent create() => SystemEvent._(); + @$core.override + SystemEvent createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static SystemEvent getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static SystemEvent? _defaultInstance; + + @$pb.TagNumber(1) + $core.String get id => $_getSZ(0); + @$pb.TagNumber(1) + set id($core.String value) => $_setString(0, value); + @$pb.TagNumber(1) + $core.bool hasId() => $_has(0); + @$pb.TagNumber(1) + void clearId() => $_clearField(1); + + @$pb.TagNumber(2) + SystemEvent_Severity get severity => $_getN(1); + @$pb.TagNumber(2) + set severity(SystemEvent_Severity value) => $_setField(2, value); + @$pb.TagNumber(2) + $core.bool hasSeverity() => $_has(1); + @$pb.TagNumber(2) + void clearSeverity() => $_clearField(2); + + @$pb.TagNumber(3) + SystemEvent_Category get category => $_getN(2); + @$pb.TagNumber(3) + set category(SystemEvent_Category value) => $_setField(3, value); + @$pb.TagNumber(3) + $core.bool hasCategory() => $_has(2); + @$pb.TagNumber(3) + void clearCategory() => $_clearField(3); + + @$pb.TagNumber(4) + $core.String get message => $_getSZ(3); + @$pb.TagNumber(4) + set message($core.String value) => $_setString(3, value); + @$pb.TagNumber(4) + $core.bool hasMessage() => $_has(3); + @$pb.TagNumber(4) + void clearMessage() => $_clearField(4); + + @$pb.TagNumber(5) + $core.String get userMessage => $_getSZ(4); + @$pb.TagNumber(5) + set userMessage($core.String value) => $_setString(4, value); + @$pb.TagNumber(5) + $core.bool hasUserMessage() => $_has(4); + @$pb.TagNumber(5) + void clearUserMessage() => $_clearField(5); + + @$pb.TagNumber(6) + $2.Timestamp get timestamp => $_getN(5); + @$pb.TagNumber(6) + set timestamp($2.Timestamp value) => $_setField(6, value); + @$pb.TagNumber(6) + $core.bool hasTimestamp() => $_has(5); + @$pb.TagNumber(6) + void clearTimestamp() => $_clearField(6); + @$pb.TagNumber(6) + $2.Timestamp ensureTimestamp() => $_ensure(5); + + @$pb.TagNumber(7) + $pb.PbMap<$core.String, $core.String> get metadata => $_getMap(6); +} + +class GetEventsRequest extends $pb.GeneratedMessage { + factory GetEventsRequest() => create(); + + GetEventsRequest._(); + + factory GetEventsRequest.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory GetEventsRequest.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'GetEventsRequest', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + GetEventsRequest clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + GetEventsRequest copyWith(void Function(GetEventsRequest) updates) => + super.copyWith((message) => updates(message as GetEventsRequest)) + as GetEventsRequest; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static GetEventsRequest create() => GetEventsRequest._(); + @$core.override + GetEventsRequest createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static GetEventsRequest getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static GetEventsRequest? _defaultInstance; +} + +class GetEventsResponse extends $pb.GeneratedMessage { + factory GetEventsResponse({ + $core.Iterable? events, + }) { + final result = create(); + if (events != null) result.events.addAll(events); + return result; + } + + GetEventsResponse._(); + + factory GetEventsResponse.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory GetEventsResponse.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'GetEventsResponse', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..pPM(1, _omitFieldNames ? '' : 'events', + subBuilder: SystemEvent.create) + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + GetEventsResponse clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + GetEventsResponse copyWith(void Function(GetEventsResponse) updates) => + super.copyWith((message) => updates(message as GetEventsResponse)) + as GetEventsResponse; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static GetEventsResponse create() => GetEventsResponse._(); + @$core.override + GetEventsResponse createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static GetEventsResponse getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static GetEventsResponse? _defaultInstance; + + @$pb.TagNumber(1) + $pb.PbList get events => $_getList(0); +} + +class SwitchProfileRequest extends $pb.GeneratedMessage { + factory SwitchProfileRequest({ + $core.String? profileName, + $core.String? username, + }) { + final result = create(); + if (profileName != null) result.profileName = profileName; + if (username != null) result.username = username; + return result; + } + + SwitchProfileRequest._(); + + factory SwitchProfileRequest.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory SwitchProfileRequest.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'SwitchProfileRequest', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..aOS(1, _omitFieldNames ? '' : 'profileName', protoName: 'profileName') + ..aOS(2, _omitFieldNames ? '' : 'username') + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + SwitchProfileRequest clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + SwitchProfileRequest copyWith(void Function(SwitchProfileRequest) updates) => + super.copyWith((message) => updates(message as SwitchProfileRequest)) + as SwitchProfileRequest; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static SwitchProfileRequest create() => SwitchProfileRequest._(); + @$core.override + SwitchProfileRequest createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static SwitchProfileRequest getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static SwitchProfileRequest? _defaultInstance; + + @$pb.TagNumber(1) + $core.String get profileName => $_getSZ(0); + @$pb.TagNumber(1) + set profileName($core.String value) => $_setString(0, value); + @$pb.TagNumber(1) + $core.bool hasProfileName() => $_has(0); + @$pb.TagNumber(1) + void clearProfileName() => $_clearField(1); + + @$pb.TagNumber(2) + $core.String get username => $_getSZ(1); + @$pb.TagNumber(2) + set username($core.String value) => $_setString(1, value); + @$pb.TagNumber(2) + $core.bool hasUsername() => $_has(1); + @$pb.TagNumber(2) + void clearUsername() => $_clearField(2); +} + +class SwitchProfileResponse extends $pb.GeneratedMessage { + factory SwitchProfileResponse() => create(); + + SwitchProfileResponse._(); + + factory SwitchProfileResponse.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory SwitchProfileResponse.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'SwitchProfileResponse', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + SwitchProfileResponse clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + SwitchProfileResponse copyWith( + void Function(SwitchProfileResponse) updates) => + super.copyWith((message) => updates(message as SwitchProfileResponse)) + as SwitchProfileResponse; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static SwitchProfileResponse create() => SwitchProfileResponse._(); + @$core.override + SwitchProfileResponse createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static SwitchProfileResponse getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static SwitchProfileResponse? _defaultInstance; +} + +class SetConfigRequest extends $pb.GeneratedMessage { + factory SetConfigRequest({ + $core.String? username, + $core.String? profileName, + $core.String? managementUrl, + $core.String? adminURL, + $core.bool? rosenpassEnabled, + $core.String? interfaceName, + $fixnum.Int64? wireguardPort, + $core.String? optionalPreSharedKey, + $core.bool? disableAutoConnect, + $core.bool? serverSSHAllowed, + $core.bool? rosenpassPermissive, + $core.bool? networkMonitor, + $core.bool? disableClientRoutes, + $core.bool? disableServerRoutes, + $core.bool? disableDns, + $core.bool? disableFirewall, + $core.bool? blockLanAccess, + $core.bool? disableNotifications, + $core.bool? lazyConnectionEnabled, + $core.bool? blockInbound, + $core.Iterable<$core.String>? natExternalIPs, + $core.bool? cleanNATExternalIPs, + $core.List<$core.int>? customDNSAddress, + $core.Iterable<$core.String>? extraIFaceBlacklist, + $core.Iterable<$core.String>? dnsLabels, + $core.bool? cleanDNSLabels, + $1.Duration? dnsRouteInterval, + $fixnum.Int64? mtu, + $core.bool? enableSSHRoot, + $core.bool? enableSSHSFTP, + $core.bool? enableSSHLocalPortForwarding, + $core.bool? enableSSHRemotePortForwarding, + $core.bool? disableSSHAuth, + $core.int? sshJWTCacheTTL, + }) { + final result = create(); + if (username != null) result.username = username; + if (profileName != null) result.profileName = profileName; + if (managementUrl != null) result.managementUrl = managementUrl; + if (adminURL != null) result.adminURL = adminURL; + if (rosenpassEnabled != null) result.rosenpassEnabled = rosenpassEnabled; + if (interfaceName != null) result.interfaceName = interfaceName; + if (wireguardPort != null) result.wireguardPort = wireguardPort; + if (optionalPreSharedKey != null) + result.optionalPreSharedKey = optionalPreSharedKey; + if (disableAutoConnect != null) + result.disableAutoConnect = disableAutoConnect; + if (serverSSHAllowed != null) result.serverSSHAllowed = serverSSHAllowed; + if (rosenpassPermissive != null) + result.rosenpassPermissive = rosenpassPermissive; + if (networkMonitor != null) result.networkMonitor = networkMonitor; + if (disableClientRoutes != null) + result.disableClientRoutes = disableClientRoutes; + if (disableServerRoutes != null) + result.disableServerRoutes = disableServerRoutes; + if (disableDns != null) result.disableDns = disableDns; + if (disableFirewall != null) result.disableFirewall = disableFirewall; + if (blockLanAccess != null) result.blockLanAccess = blockLanAccess; + if (disableNotifications != null) + result.disableNotifications = disableNotifications; + if (lazyConnectionEnabled != null) + result.lazyConnectionEnabled = lazyConnectionEnabled; + if (blockInbound != null) result.blockInbound = blockInbound; + if (natExternalIPs != null) result.natExternalIPs.addAll(natExternalIPs); + if (cleanNATExternalIPs != null) + result.cleanNATExternalIPs = cleanNATExternalIPs; + if (customDNSAddress != null) result.customDNSAddress = customDNSAddress; + if (extraIFaceBlacklist != null) + result.extraIFaceBlacklist.addAll(extraIFaceBlacklist); + if (dnsLabels != null) result.dnsLabels.addAll(dnsLabels); + if (cleanDNSLabels != null) result.cleanDNSLabels = cleanDNSLabels; + if (dnsRouteInterval != null) result.dnsRouteInterval = dnsRouteInterval; + if (mtu != null) result.mtu = mtu; + if (enableSSHRoot != null) result.enableSSHRoot = enableSSHRoot; + if (enableSSHSFTP != null) result.enableSSHSFTP = enableSSHSFTP; + if (enableSSHLocalPortForwarding != null) + result.enableSSHLocalPortForwarding = enableSSHLocalPortForwarding; + if (enableSSHRemotePortForwarding != null) + result.enableSSHRemotePortForwarding = enableSSHRemotePortForwarding; + if (disableSSHAuth != null) result.disableSSHAuth = disableSSHAuth; + if (sshJWTCacheTTL != null) result.sshJWTCacheTTL = sshJWTCacheTTL; + return result; + } + + SetConfigRequest._(); + + factory SetConfigRequest.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory SetConfigRequest.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'SetConfigRequest', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..aOS(1, _omitFieldNames ? '' : 'username') + ..aOS(2, _omitFieldNames ? '' : 'profileName', protoName: 'profileName') + ..aOS(3, _omitFieldNames ? '' : 'managementUrl', protoName: 'managementUrl') + ..aOS(4, _omitFieldNames ? '' : 'adminURL', protoName: 'adminURL') + ..aOB(5, _omitFieldNames ? '' : 'rosenpassEnabled', + protoName: 'rosenpassEnabled') + ..aOS(6, _omitFieldNames ? '' : 'interfaceName', protoName: 'interfaceName') + ..aInt64(7, _omitFieldNames ? '' : 'wireguardPort', + protoName: 'wireguardPort') + ..aOS(8, _omitFieldNames ? '' : 'optionalPreSharedKey', + protoName: 'optionalPreSharedKey') + ..aOB(9, _omitFieldNames ? '' : 'disableAutoConnect', + protoName: 'disableAutoConnect') + ..aOB(10, _omitFieldNames ? '' : 'serverSSHAllowed', + protoName: 'serverSSHAllowed') + ..aOB(11, _omitFieldNames ? '' : 'rosenpassPermissive', + protoName: 'rosenpassPermissive') + ..aOB(12, _omitFieldNames ? '' : 'networkMonitor', + protoName: 'networkMonitor') + ..aOB(13, _omitFieldNames ? '' : 'disableClientRoutes') + ..aOB(14, _omitFieldNames ? '' : 'disableServerRoutes') + ..aOB(15, _omitFieldNames ? '' : 'disableDns') + ..aOB(16, _omitFieldNames ? '' : 'disableFirewall') + ..aOB(17, _omitFieldNames ? '' : 'blockLanAccess') + ..aOB(18, _omitFieldNames ? '' : 'disableNotifications') + ..aOB(19, _omitFieldNames ? '' : 'lazyConnectionEnabled', + protoName: 'lazyConnectionEnabled') + ..aOB(20, _omitFieldNames ? '' : 'blockInbound') + ..pPS(21, _omitFieldNames ? '' : 'natExternalIPs', + protoName: 'natExternalIPs') + ..aOB(22, _omitFieldNames ? '' : 'cleanNATExternalIPs', + protoName: 'cleanNATExternalIPs') + ..a<$core.List<$core.int>>( + 23, _omitFieldNames ? '' : 'customDNSAddress', $pb.PbFieldType.OY, + protoName: 'customDNSAddress') + ..pPS(24, _omitFieldNames ? '' : 'extraIFaceBlacklist', + protoName: 'extraIFaceBlacklist') + ..pPS(25, _omitFieldNames ? '' : 'dnsLabels') + ..aOB(26, _omitFieldNames ? '' : 'cleanDNSLabels', + protoName: 'cleanDNSLabels') + ..aOM<$1.Duration>(27, _omitFieldNames ? '' : 'dnsRouteInterval', + protoName: 'dnsRouteInterval', subBuilder: $1.Duration.create) + ..aInt64(28, _omitFieldNames ? '' : 'mtu') + ..aOB(29, _omitFieldNames ? '' : 'enableSSHRoot', + protoName: 'enableSSHRoot') + ..aOB(30, _omitFieldNames ? '' : 'enableSSHSFTP', + protoName: 'enableSSHSFTP') + ..aOB(31, _omitFieldNames ? '' : 'enableSSHLocalPortForwarding', + protoName: 'enableSSHLocalPortForwarding') + ..aOB(32, _omitFieldNames ? '' : 'enableSSHRemotePortForwarding', + protoName: 'enableSSHRemotePortForwarding') + ..aOB(33, _omitFieldNames ? '' : 'disableSSHAuth', + protoName: 'disableSSHAuth') + ..aI(34, _omitFieldNames ? '' : 'sshJWTCacheTTL', + protoName: 'sshJWTCacheTTL') + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + SetConfigRequest clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + SetConfigRequest copyWith(void Function(SetConfigRequest) updates) => + super.copyWith((message) => updates(message as SetConfigRequest)) + as SetConfigRequest; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static SetConfigRequest create() => SetConfigRequest._(); + @$core.override + SetConfigRequest createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static SetConfigRequest getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static SetConfigRequest? _defaultInstance; + + @$pb.TagNumber(1) + $core.String get username => $_getSZ(0); + @$pb.TagNumber(1) + set username($core.String value) => $_setString(0, value); + @$pb.TagNumber(1) + $core.bool hasUsername() => $_has(0); + @$pb.TagNumber(1) + void clearUsername() => $_clearField(1); + + @$pb.TagNumber(2) + $core.String get profileName => $_getSZ(1); + @$pb.TagNumber(2) + set profileName($core.String value) => $_setString(1, value); + @$pb.TagNumber(2) + $core.bool hasProfileName() => $_has(1); + @$pb.TagNumber(2) + void clearProfileName() => $_clearField(2); + + /// managementUrl to authenticate. + @$pb.TagNumber(3) + $core.String get managementUrl => $_getSZ(2); + @$pb.TagNumber(3) + set managementUrl($core.String value) => $_setString(2, value); + @$pb.TagNumber(3) + $core.bool hasManagementUrl() => $_has(2); + @$pb.TagNumber(3) + void clearManagementUrl() => $_clearField(3); + + /// adminUrl to manage keys. + @$pb.TagNumber(4) + $core.String get adminURL => $_getSZ(3); + @$pb.TagNumber(4) + set adminURL($core.String value) => $_setString(3, value); + @$pb.TagNumber(4) + $core.bool hasAdminURL() => $_has(3); + @$pb.TagNumber(4) + void clearAdminURL() => $_clearField(4); + + @$pb.TagNumber(5) + $core.bool get rosenpassEnabled => $_getBF(4); + @$pb.TagNumber(5) + set rosenpassEnabled($core.bool value) => $_setBool(4, value); + @$pb.TagNumber(5) + $core.bool hasRosenpassEnabled() => $_has(4); + @$pb.TagNumber(5) + void clearRosenpassEnabled() => $_clearField(5); + + @$pb.TagNumber(6) + $core.String get interfaceName => $_getSZ(5); + @$pb.TagNumber(6) + set interfaceName($core.String value) => $_setString(5, value); + @$pb.TagNumber(6) + $core.bool hasInterfaceName() => $_has(5); + @$pb.TagNumber(6) + void clearInterfaceName() => $_clearField(6); + + @$pb.TagNumber(7) + $fixnum.Int64 get wireguardPort => $_getI64(6); + @$pb.TagNumber(7) + set wireguardPort($fixnum.Int64 value) => $_setInt64(6, value); + @$pb.TagNumber(7) + $core.bool hasWireguardPort() => $_has(6); + @$pb.TagNumber(7) + void clearWireguardPort() => $_clearField(7); + + @$pb.TagNumber(8) + $core.String get optionalPreSharedKey => $_getSZ(7); + @$pb.TagNumber(8) + set optionalPreSharedKey($core.String value) => $_setString(7, value); + @$pb.TagNumber(8) + $core.bool hasOptionalPreSharedKey() => $_has(7); + @$pb.TagNumber(8) + void clearOptionalPreSharedKey() => $_clearField(8); + + @$pb.TagNumber(9) + $core.bool get disableAutoConnect => $_getBF(8); + @$pb.TagNumber(9) + set disableAutoConnect($core.bool value) => $_setBool(8, value); + @$pb.TagNumber(9) + $core.bool hasDisableAutoConnect() => $_has(8); + @$pb.TagNumber(9) + void clearDisableAutoConnect() => $_clearField(9); + + @$pb.TagNumber(10) + $core.bool get serverSSHAllowed => $_getBF(9); + @$pb.TagNumber(10) + set serverSSHAllowed($core.bool value) => $_setBool(9, value); + @$pb.TagNumber(10) + $core.bool hasServerSSHAllowed() => $_has(9); + @$pb.TagNumber(10) + void clearServerSSHAllowed() => $_clearField(10); + + @$pb.TagNumber(11) + $core.bool get rosenpassPermissive => $_getBF(10); + @$pb.TagNumber(11) + set rosenpassPermissive($core.bool value) => $_setBool(10, value); + @$pb.TagNumber(11) + $core.bool hasRosenpassPermissive() => $_has(10); + @$pb.TagNumber(11) + void clearRosenpassPermissive() => $_clearField(11); + + @$pb.TagNumber(12) + $core.bool get networkMonitor => $_getBF(11); + @$pb.TagNumber(12) + set networkMonitor($core.bool value) => $_setBool(11, value); + @$pb.TagNumber(12) + $core.bool hasNetworkMonitor() => $_has(11); + @$pb.TagNumber(12) + void clearNetworkMonitor() => $_clearField(12); + + @$pb.TagNumber(13) + $core.bool get disableClientRoutes => $_getBF(12); + @$pb.TagNumber(13) + set disableClientRoutes($core.bool value) => $_setBool(12, value); + @$pb.TagNumber(13) + $core.bool hasDisableClientRoutes() => $_has(12); + @$pb.TagNumber(13) + void clearDisableClientRoutes() => $_clearField(13); + + @$pb.TagNumber(14) + $core.bool get disableServerRoutes => $_getBF(13); + @$pb.TagNumber(14) + set disableServerRoutes($core.bool value) => $_setBool(13, value); + @$pb.TagNumber(14) + $core.bool hasDisableServerRoutes() => $_has(13); + @$pb.TagNumber(14) + void clearDisableServerRoutes() => $_clearField(14); + + @$pb.TagNumber(15) + $core.bool get disableDns => $_getBF(14); + @$pb.TagNumber(15) + set disableDns($core.bool value) => $_setBool(14, value); + @$pb.TagNumber(15) + $core.bool hasDisableDns() => $_has(14); + @$pb.TagNumber(15) + void clearDisableDns() => $_clearField(15); + + @$pb.TagNumber(16) + $core.bool get disableFirewall => $_getBF(15); + @$pb.TagNumber(16) + set disableFirewall($core.bool value) => $_setBool(15, value); + @$pb.TagNumber(16) + $core.bool hasDisableFirewall() => $_has(15); + @$pb.TagNumber(16) + void clearDisableFirewall() => $_clearField(16); + + @$pb.TagNumber(17) + $core.bool get blockLanAccess => $_getBF(16); + @$pb.TagNumber(17) + set blockLanAccess($core.bool value) => $_setBool(16, value); + @$pb.TagNumber(17) + $core.bool hasBlockLanAccess() => $_has(16); + @$pb.TagNumber(17) + void clearBlockLanAccess() => $_clearField(17); + + @$pb.TagNumber(18) + $core.bool get disableNotifications => $_getBF(17); + @$pb.TagNumber(18) + set disableNotifications($core.bool value) => $_setBool(17, value); + @$pb.TagNumber(18) + $core.bool hasDisableNotifications() => $_has(17); + @$pb.TagNumber(18) + void clearDisableNotifications() => $_clearField(18); + + @$pb.TagNumber(19) + $core.bool get lazyConnectionEnabled => $_getBF(18); + @$pb.TagNumber(19) + set lazyConnectionEnabled($core.bool value) => $_setBool(18, value); + @$pb.TagNumber(19) + $core.bool hasLazyConnectionEnabled() => $_has(18); + @$pb.TagNumber(19) + void clearLazyConnectionEnabled() => $_clearField(19); + + @$pb.TagNumber(20) + $core.bool get blockInbound => $_getBF(19); + @$pb.TagNumber(20) + set blockInbound($core.bool value) => $_setBool(19, value); + @$pb.TagNumber(20) + $core.bool hasBlockInbound() => $_has(19); + @$pb.TagNumber(20) + void clearBlockInbound() => $_clearField(20); + + @$pb.TagNumber(21) + $pb.PbList<$core.String> get natExternalIPs => $_getList(20); + + @$pb.TagNumber(22) + $core.bool get cleanNATExternalIPs => $_getBF(21); + @$pb.TagNumber(22) + set cleanNATExternalIPs($core.bool value) => $_setBool(21, value); + @$pb.TagNumber(22) + $core.bool hasCleanNATExternalIPs() => $_has(21); + @$pb.TagNumber(22) + void clearCleanNATExternalIPs() => $_clearField(22); + + @$pb.TagNumber(23) + $core.List<$core.int> get customDNSAddress => $_getN(22); + @$pb.TagNumber(23) + set customDNSAddress($core.List<$core.int> value) => $_setBytes(22, value); + @$pb.TagNumber(23) + $core.bool hasCustomDNSAddress() => $_has(22); + @$pb.TagNumber(23) + void clearCustomDNSAddress() => $_clearField(23); + + @$pb.TagNumber(24) + $pb.PbList<$core.String> get extraIFaceBlacklist => $_getList(23); + + @$pb.TagNumber(25) + $pb.PbList<$core.String> get dnsLabels => $_getList(24); + + /// cleanDNSLabels clean map list of DNS labels. + @$pb.TagNumber(26) + $core.bool get cleanDNSLabels => $_getBF(25); + @$pb.TagNumber(26) + set cleanDNSLabels($core.bool value) => $_setBool(25, value); + @$pb.TagNumber(26) + $core.bool hasCleanDNSLabels() => $_has(25); + @$pb.TagNumber(26) + void clearCleanDNSLabels() => $_clearField(26); + + @$pb.TagNumber(27) + $1.Duration get dnsRouteInterval => $_getN(26); + @$pb.TagNumber(27) + set dnsRouteInterval($1.Duration value) => $_setField(27, value); + @$pb.TagNumber(27) + $core.bool hasDnsRouteInterval() => $_has(26); + @$pb.TagNumber(27) + void clearDnsRouteInterval() => $_clearField(27); + @$pb.TagNumber(27) + $1.Duration ensureDnsRouteInterval() => $_ensure(26); + + @$pb.TagNumber(28) + $fixnum.Int64 get mtu => $_getI64(27); + @$pb.TagNumber(28) + set mtu($fixnum.Int64 value) => $_setInt64(27, value); + @$pb.TagNumber(28) + $core.bool hasMtu() => $_has(27); + @$pb.TagNumber(28) + void clearMtu() => $_clearField(28); + + @$pb.TagNumber(29) + $core.bool get enableSSHRoot => $_getBF(28); + @$pb.TagNumber(29) + set enableSSHRoot($core.bool value) => $_setBool(28, value); + @$pb.TagNumber(29) + $core.bool hasEnableSSHRoot() => $_has(28); + @$pb.TagNumber(29) + void clearEnableSSHRoot() => $_clearField(29); + + @$pb.TagNumber(30) + $core.bool get enableSSHSFTP => $_getBF(29); + @$pb.TagNumber(30) + set enableSSHSFTP($core.bool value) => $_setBool(29, value); + @$pb.TagNumber(30) + $core.bool hasEnableSSHSFTP() => $_has(29); + @$pb.TagNumber(30) + void clearEnableSSHSFTP() => $_clearField(30); + + @$pb.TagNumber(31) + $core.bool get enableSSHLocalPortForwarding => $_getBF(30); + @$pb.TagNumber(31) + set enableSSHLocalPortForwarding($core.bool value) => $_setBool(30, value); + @$pb.TagNumber(31) + $core.bool hasEnableSSHLocalPortForwarding() => $_has(30); + @$pb.TagNumber(31) + void clearEnableSSHLocalPortForwarding() => $_clearField(31); + + @$pb.TagNumber(32) + $core.bool get enableSSHRemotePortForwarding => $_getBF(31); + @$pb.TagNumber(32) + set enableSSHRemotePortForwarding($core.bool value) => $_setBool(31, value); + @$pb.TagNumber(32) + $core.bool hasEnableSSHRemotePortForwarding() => $_has(31); + @$pb.TagNumber(32) + void clearEnableSSHRemotePortForwarding() => $_clearField(32); + + @$pb.TagNumber(33) + $core.bool get disableSSHAuth => $_getBF(32); + @$pb.TagNumber(33) + set disableSSHAuth($core.bool value) => $_setBool(32, value); + @$pb.TagNumber(33) + $core.bool hasDisableSSHAuth() => $_has(32); + @$pb.TagNumber(33) + void clearDisableSSHAuth() => $_clearField(33); + + @$pb.TagNumber(34) + $core.int get sshJWTCacheTTL => $_getIZ(33); + @$pb.TagNumber(34) + set sshJWTCacheTTL($core.int value) => $_setSignedInt32(33, value); + @$pb.TagNumber(34) + $core.bool hasSshJWTCacheTTL() => $_has(33); + @$pb.TagNumber(34) + void clearSshJWTCacheTTL() => $_clearField(34); +} + +class SetConfigResponse extends $pb.GeneratedMessage { + factory SetConfigResponse() => create(); + + SetConfigResponse._(); + + factory SetConfigResponse.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory SetConfigResponse.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'SetConfigResponse', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + SetConfigResponse clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + SetConfigResponse copyWith(void Function(SetConfigResponse) updates) => + super.copyWith((message) => updates(message as SetConfigResponse)) + as SetConfigResponse; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static SetConfigResponse create() => SetConfigResponse._(); + @$core.override + SetConfigResponse createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static SetConfigResponse getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static SetConfigResponse? _defaultInstance; +} + +class AddProfileRequest extends $pb.GeneratedMessage { + factory AddProfileRequest({ + $core.String? username, + $core.String? profileName, + }) { + final result = create(); + if (username != null) result.username = username; + if (profileName != null) result.profileName = profileName; + return result; + } + + AddProfileRequest._(); + + factory AddProfileRequest.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory AddProfileRequest.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'AddProfileRequest', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..aOS(1, _omitFieldNames ? '' : 'username') + ..aOS(2, _omitFieldNames ? '' : 'profileName', protoName: 'profileName') + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + AddProfileRequest clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + AddProfileRequest copyWith(void Function(AddProfileRequest) updates) => + super.copyWith((message) => updates(message as AddProfileRequest)) + as AddProfileRequest; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static AddProfileRequest create() => AddProfileRequest._(); + @$core.override + AddProfileRequest createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static AddProfileRequest getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static AddProfileRequest? _defaultInstance; + + @$pb.TagNumber(1) + $core.String get username => $_getSZ(0); + @$pb.TagNumber(1) + set username($core.String value) => $_setString(0, value); + @$pb.TagNumber(1) + $core.bool hasUsername() => $_has(0); + @$pb.TagNumber(1) + void clearUsername() => $_clearField(1); + + @$pb.TagNumber(2) + $core.String get profileName => $_getSZ(1); + @$pb.TagNumber(2) + set profileName($core.String value) => $_setString(1, value); + @$pb.TagNumber(2) + $core.bool hasProfileName() => $_has(1); + @$pb.TagNumber(2) + void clearProfileName() => $_clearField(2); +} + +class AddProfileResponse extends $pb.GeneratedMessage { + factory AddProfileResponse() => create(); + + AddProfileResponse._(); + + factory AddProfileResponse.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory AddProfileResponse.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'AddProfileResponse', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + AddProfileResponse clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + AddProfileResponse copyWith(void Function(AddProfileResponse) updates) => + super.copyWith((message) => updates(message as AddProfileResponse)) + as AddProfileResponse; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static AddProfileResponse create() => AddProfileResponse._(); + @$core.override + AddProfileResponse createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static AddProfileResponse getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static AddProfileResponse? _defaultInstance; +} + +class RemoveProfileRequest extends $pb.GeneratedMessage { + factory RemoveProfileRequest({ + $core.String? username, + $core.String? profileName, + }) { + final result = create(); + if (username != null) result.username = username; + if (profileName != null) result.profileName = profileName; + return result; + } + + RemoveProfileRequest._(); + + factory RemoveProfileRequest.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory RemoveProfileRequest.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'RemoveProfileRequest', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..aOS(1, _omitFieldNames ? '' : 'username') + ..aOS(2, _omitFieldNames ? '' : 'profileName', protoName: 'profileName') + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + RemoveProfileRequest clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + RemoveProfileRequest copyWith(void Function(RemoveProfileRequest) updates) => + super.copyWith((message) => updates(message as RemoveProfileRequest)) + as RemoveProfileRequest; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static RemoveProfileRequest create() => RemoveProfileRequest._(); + @$core.override + RemoveProfileRequest createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static RemoveProfileRequest getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static RemoveProfileRequest? _defaultInstance; + + @$pb.TagNumber(1) + $core.String get username => $_getSZ(0); + @$pb.TagNumber(1) + set username($core.String value) => $_setString(0, value); + @$pb.TagNumber(1) + $core.bool hasUsername() => $_has(0); + @$pb.TagNumber(1) + void clearUsername() => $_clearField(1); + + @$pb.TagNumber(2) + $core.String get profileName => $_getSZ(1); + @$pb.TagNumber(2) + set profileName($core.String value) => $_setString(1, value); + @$pb.TagNumber(2) + $core.bool hasProfileName() => $_has(1); + @$pb.TagNumber(2) + void clearProfileName() => $_clearField(2); +} + +class RemoveProfileResponse extends $pb.GeneratedMessage { + factory RemoveProfileResponse() => create(); + + RemoveProfileResponse._(); + + factory RemoveProfileResponse.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory RemoveProfileResponse.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'RemoveProfileResponse', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + RemoveProfileResponse clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + RemoveProfileResponse copyWith( + void Function(RemoveProfileResponse) updates) => + super.copyWith((message) => updates(message as RemoveProfileResponse)) + as RemoveProfileResponse; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static RemoveProfileResponse create() => RemoveProfileResponse._(); + @$core.override + RemoveProfileResponse createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static RemoveProfileResponse getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static RemoveProfileResponse? _defaultInstance; +} + +class ListProfilesRequest extends $pb.GeneratedMessage { + factory ListProfilesRequest({ + $core.String? username, + }) { + final result = create(); + if (username != null) result.username = username; + return result; + } + + ListProfilesRequest._(); + + factory ListProfilesRequest.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory ListProfilesRequest.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'ListProfilesRequest', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..aOS(1, _omitFieldNames ? '' : 'username') + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + ListProfilesRequest clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + ListProfilesRequest copyWith(void Function(ListProfilesRequest) updates) => + super.copyWith((message) => updates(message as ListProfilesRequest)) + as ListProfilesRequest; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static ListProfilesRequest create() => ListProfilesRequest._(); + @$core.override + ListProfilesRequest createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static ListProfilesRequest getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static ListProfilesRequest? _defaultInstance; + + @$pb.TagNumber(1) + $core.String get username => $_getSZ(0); + @$pb.TagNumber(1) + set username($core.String value) => $_setString(0, value); + @$pb.TagNumber(1) + $core.bool hasUsername() => $_has(0); + @$pb.TagNumber(1) + void clearUsername() => $_clearField(1); +} + +class ListProfilesResponse extends $pb.GeneratedMessage { + factory ListProfilesResponse({ + $core.Iterable? profiles, + }) { + final result = create(); + if (profiles != null) result.profiles.addAll(profiles); + return result; + } + + ListProfilesResponse._(); + + factory ListProfilesResponse.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory ListProfilesResponse.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'ListProfilesResponse', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..pPM(1, _omitFieldNames ? '' : 'profiles', + subBuilder: Profile.create) + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + ListProfilesResponse clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + ListProfilesResponse copyWith(void Function(ListProfilesResponse) updates) => + super.copyWith((message) => updates(message as ListProfilesResponse)) + as ListProfilesResponse; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static ListProfilesResponse create() => ListProfilesResponse._(); + @$core.override + ListProfilesResponse createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static ListProfilesResponse getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static ListProfilesResponse? _defaultInstance; + + @$pb.TagNumber(1) + $pb.PbList get profiles => $_getList(0); +} + +class Profile extends $pb.GeneratedMessage { + factory Profile({ + $core.String? name, + $core.bool? isActive, + }) { + final result = create(); + if (name != null) result.name = name; + if (isActive != null) result.isActive = isActive; + return result; + } + + Profile._(); + + factory Profile.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory Profile.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'Profile', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..aOS(1, _omitFieldNames ? '' : 'name') + ..aOB(2, _omitFieldNames ? '' : 'isActive') + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + Profile clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + Profile copyWith(void Function(Profile) updates) => + super.copyWith((message) => updates(message as Profile)) as Profile; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static Profile create() => Profile._(); + @$core.override + Profile createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static Profile getDefault() => + _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static Profile? _defaultInstance; + + @$pb.TagNumber(1) + $core.String get name => $_getSZ(0); + @$pb.TagNumber(1) + set name($core.String value) => $_setString(0, value); + @$pb.TagNumber(1) + $core.bool hasName() => $_has(0); + @$pb.TagNumber(1) + void clearName() => $_clearField(1); + + @$pb.TagNumber(2) + $core.bool get isActive => $_getBF(1); + @$pb.TagNumber(2) + set isActive($core.bool value) => $_setBool(1, value); + @$pb.TagNumber(2) + $core.bool hasIsActive() => $_has(1); + @$pb.TagNumber(2) + void clearIsActive() => $_clearField(2); +} + +class GetActiveProfileRequest extends $pb.GeneratedMessage { + factory GetActiveProfileRequest() => create(); + + GetActiveProfileRequest._(); + + factory GetActiveProfileRequest.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory GetActiveProfileRequest.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'GetActiveProfileRequest', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + GetActiveProfileRequest clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + GetActiveProfileRequest copyWith( + void Function(GetActiveProfileRequest) updates) => + super.copyWith((message) => updates(message as GetActiveProfileRequest)) + as GetActiveProfileRequest; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static GetActiveProfileRequest create() => GetActiveProfileRequest._(); + @$core.override + GetActiveProfileRequest createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static GetActiveProfileRequest getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static GetActiveProfileRequest? _defaultInstance; +} + +class GetActiveProfileResponse extends $pb.GeneratedMessage { + factory GetActiveProfileResponse({ + $core.String? profileName, + $core.String? username, + }) { + final result = create(); + if (profileName != null) result.profileName = profileName; + if (username != null) result.username = username; + return result; + } + + GetActiveProfileResponse._(); + + factory GetActiveProfileResponse.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory GetActiveProfileResponse.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'GetActiveProfileResponse', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..aOS(1, _omitFieldNames ? '' : 'profileName', protoName: 'profileName') + ..aOS(2, _omitFieldNames ? '' : 'username') + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + GetActiveProfileResponse clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + GetActiveProfileResponse copyWith( + void Function(GetActiveProfileResponse) updates) => + super.copyWith((message) => updates(message as GetActiveProfileResponse)) + as GetActiveProfileResponse; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static GetActiveProfileResponse create() => GetActiveProfileResponse._(); + @$core.override + GetActiveProfileResponse createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static GetActiveProfileResponse getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static GetActiveProfileResponse? _defaultInstance; + + @$pb.TagNumber(1) + $core.String get profileName => $_getSZ(0); + @$pb.TagNumber(1) + set profileName($core.String value) => $_setString(0, value); + @$pb.TagNumber(1) + $core.bool hasProfileName() => $_has(0); + @$pb.TagNumber(1) + void clearProfileName() => $_clearField(1); + + @$pb.TagNumber(2) + $core.String get username => $_getSZ(1); + @$pb.TagNumber(2) + set username($core.String value) => $_setString(1, value); + @$pb.TagNumber(2) + $core.bool hasUsername() => $_has(1); + @$pb.TagNumber(2) + void clearUsername() => $_clearField(2); +} + +class LogoutRequest extends $pb.GeneratedMessage { + factory LogoutRequest({ + $core.String? profileName, + $core.String? username, + }) { + final result = create(); + if (profileName != null) result.profileName = profileName; + if (username != null) result.username = username; + return result; + } + + LogoutRequest._(); + + factory LogoutRequest.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory LogoutRequest.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'LogoutRequest', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..aOS(1, _omitFieldNames ? '' : 'profileName', protoName: 'profileName') + ..aOS(2, _omitFieldNames ? '' : 'username') + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + LogoutRequest clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + LogoutRequest copyWith(void Function(LogoutRequest) updates) => + super.copyWith((message) => updates(message as LogoutRequest)) + as LogoutRequest; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static LogoutRequest create() => LogoutRequest._(); + @$core.override + LogoutRequest createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static LogoutRequest getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static LogoutRequest? _defaultInstance; + + @$pb.TagNumber(1) + $core.String get profileName => $_getSZ(0); + @$pb.TagNumber(1) + set profileName($core.String value) => $_setString(0, value); + @$pb.TagNumber(1) + $core.bool hasProfileName() => $_has(0); + @$pb.TagNumber(1) + void clearProfileName() => $_clearField(1); + + @$pb.TagNumber(2) + $core.String get username => $_getSZ(1); + @$pb.TagNumber(2) + set username($core.String value) => $_setString(1, value); + @$pb.TagNumber(2) + $core.bool hasUsername() => $_has(1); + @$pb.TagNumber(2) + void clearUsername() => $_clearField(2); +} + +class LogoutResponse extends $pb.GeneratedMessage { + factory LogoutResponse() => create(); + + LogoutResponse._(); + + factory LogoutResponse.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory LogoutResponse.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'LogoutResponse', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + LogoutResponse clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + LogoutResponse copyWith(void Function(LogoutResponse) updates) => + super.copyWith((message) => updates(message as LogoutResponse)) + as LogoutResponse; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static LogoutResponse create() => LogoutResponse._(); + @$core.override + LogoutResponse createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static LogoutResponse getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static LogoutResponse? _defaultInstance; +} + +class GetFeaturesRequest extends $pb.GeneratedMessage { + factory GetFeaturesRequest() => create(); + + GetFeaturesRequest._(); + + factory GetFeaturesRequest.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory GetFeaturesRequest.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'GetFeaturesRequest', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + GetFeaturesRequest clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + GetFeaturesRequest copyWith(void Function(GetFeaturesRequest) updates) => + super.copyWith((message) => updates(message as GetFeaturesRequest)) + as GetFeaturesRequest; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static GetFeaturesRequest create() => GetFeaturesRequest._(); + @$core.override + GetFeaturesRequest createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static GetFeaturesRequest getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static GetFeaturesRequest? _defaultInstance; +} + +class GetFeaturesResponse extends $pb.GeneratedMessage { + factory GetFeaturesResponse({ + $core.bool? disableProfiles, + $core.bool? disableUpdateSettings, + $core.bool? disableNetworks, + }) { + final result = create(); + if (disableProfiles != null) result.disableProfiles = disableProfiles; + if (disableUpdateSettings != null) + result.disableUpdateSettings = disableUpdateSettings; + if (disableNetworks != null) result.disableNetworks = disableNetworks; + return result; + } + + GetFeaturesResponse._(); + + factory GetFeaturesResponse.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory GetFeaturesResponse.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'GetFeaturesResponse', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..aOB(1, _omitFieldNames ? '' : 'disableProfiles') + ..aOB(2, _omitFieldNames ? '' : 'disableUpdateSettings') + ..aOB(3, _omitFieldNames ? '' : 'disableNetworks') + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + GetFeaturesResponse clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + GetFeaturesResponse copyWith(void Function(GetFeaturesResponse) updates) => + super.copyWith((message) => updates(message as GetFeaturesResponse)) + as GetFeaturesResponse; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static GetFeaturesResponse create() => GetFeaturesResponse._(); + @$core.override + GetFeaturesResponse createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static GetFeaturesResponse getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static GetFeaturesResponse? _defaultInstance; + + @$pb.TagNumber(1) + $core.bool get disableProfiles => $_getBF(0); + @$pb.TagNumber(1) + set disableProfiles($core.bool value) => $_setBool(0, value); + @$pb.TagNumber(1) + $core.bool hasDisableProfiles() => $_has(0); + @$pb.TagNumber(1) + void clearDisableProfiles() => $_clearField(1); + + @$pb.TagNumber(2) + $core.bool get disableUpdateSettings => $_getBF(1); + @$pb.TagNumber(2) + set disableUpdateSettings($core.bool value) => $_setBool(1, value); + @$pb.TagNumber(2) + $core.bool hasDisableUpdateSettings() => $_has(1); + @$pb.TagNumber(2) + void clearDisableUpdateSettings() => $_clearField(2); + + @$pb.TagNumber(3) + $core.bool get disableNetworks => $_getBF(2); + @$pb.TagNumber(3) + set disableNetworks($core.bool value) => $_setBool(2, value); + @$pb.TagNumber(3) + $core.bool hasDisableNetworks() => $_has(2); + @$pb.TagNumber(3) + void clearDisableNetworks() => $_clearField(3); +} + +class TriggerUpdateRequest extends $pb.GeneratedMessage { + factory TriggerUpdateRequest() => create(); + + TriggerUpdateRequest._(); + + factory TriggerUpdateRequest.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory TriggerUpdateRequest.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'TriggerUpdateRequest', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + TriggerUpdateRequest clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + TriggerUpdateRequest copyWith(void Function(TriggerUpdateRequest) updates) => + super.copyWith((message) => updates(message as TriggerUpdateRequest)) + as TriggerUpdateRequest; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static TriggerUpdateRequest create() => TriggerUpdateRequest._(); + @$core.override + TriggerUpdateRequest createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static TriggerUpdateRequest getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static TriggerUpdateRequest? _defaultInstance; +} + +class TriggerUpdateResponse extends $pb.GeneratedMessage { + factory TriggerUpdateResponse({ + $core.bool? success, + $core.String? errorMsg, + }) { + final result = create(); + if (success != null) result.success = success; + if (errorMsg != null) result.errorMsg = errorMsg; + return result; + } + + TriggerUpdateResponse._(); + + factory TriggerUpdateResponse.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory TriggerUpdateResponse.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'TriggerUpdateResponse', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..aOB(1, _omitFieldNames ? '' : 'success') + ..aOS(2, _omitFieldNames ? '' : 'errorMsg', protoName: 'errorMsg') + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + TriggerUpdateResponse clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + TriggerUpdateResponse copyWith( + void Function(TriggerUpdateResponse) updates) => + super.copyWith((message) => updates(message as TriggerUpdateResponse)) + as TriggerUpdateResponse; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static TriggerUpdateResponse create() => TriggerUpdateResponse._(); + @$core.override + TriggerUpdateResponse createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static TriggerUpdateResponse getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static TriggerUpdateResponse? _defaultInstance; + + @$pb.TagNumber(1) + $core.bool get success => $_getBF(0); + @$pb.TagNumber(1) + set success($core.bool value) => $_setBool(0, value); + @$pb.TagNumber(1) + $core.bool hasSuccess() => $_has(0); + @$pb.TagNumber(1) + void clearSuccess() => $_clearField(1); + + @$pb.TagNumber(2) + $core.String get errorMsg => $_getSZ(1); + @$pb.TagNumber(2) + set errorMsg($core.String value) => $_setString(1, value); + @$pb.TagNumber(2) + $core.bool hasErrorMsg() => $_has(1); + @$pb.TagNumber(2) + void clearErrorMsg() => $_clearField(2); +} + +/// GetPeerSSHHostKeyRequest for retrieving SSH host key for a specific peer +class GetPeerSSHHostKeyRequest extends $pb.GeneratedMessage { + factory GetPeerSSHHostKeyRequest({ + $core.String? peerAddress, + }) { + final result = create(); + if (peerAddress != null) result.peerAddress = peerAddress; + return result; + } + + GetPeerSSHHostKeyRequest._(); + + factory GetPeerSSHHostKeyRequest.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory GetPeerSSHHostKeyRequest.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'GetPeerSSHHostKeyRequest', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..aOS(1, _omitFieldNames ? '' : 'peerAddress', protoName: 'peerAddress') + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + GetPeerSSHHostKeyRequest clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + GetPeerSSHHostKeyRequest copyWith( + void Function(GetPeerSSHHostKeyRequest) updates) => + super.copyWith((message) => updates(message as GetPeerSSHHostKeyRequest)) + as GetPeerSSHHostKeyRequest; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static GetPeerSSHHostKeyRequest create() => GetPeerSSHHostKeyRequest._(); + @$core.override + GetPeerSSHHostKeyRequest createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static GetPeerSSHHostKeyRequest getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static GetPeerSSHHostKeyRequest? _defaultInstance; + + /// peer IP address or FQDN to get SSH host key for + @$pb.TagNumber(1) + $core.String get peerAddress => $_getSZ(0); + @$pb.TagNumber(1) + set peerAddress($core.String value) => $_setString(0, value); + @$pb.TagNumber(1) + $core.bool hasPeerAddress() => $_has(0); + @$pb.TagNumber(1) + void clearPeerAddress() => $_clearField(1); +} + +/// GetPeerSSHHostKeyResponse contains the SSH host key for the requested peer +class GetPeerSSHHostKeyResponse extends $pb.GeneratedMessage { + factory GetPeerSSHHostKeyResponse({ + $core.List<$core.int>? sshHostKey, + $core.String? peerIP, + $core.String? peerFQDN, + $core.bool? found, + }) { + final result = create(); + if (sshHostKey != null) result.sshHostKey = sshHostKey; + if (peerIP != null) result.peerIP = peerIP; + if (peerFQDN != null) result.peerFQDN = peerFQDN; + if (found != null) result.found = found; + return result; + } + + GetPeerSSHHostKeyResponse._(); + + factory GetPeerSSHHostKeyResponse.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory GetPeerSSHHostKeyResponse.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'GetPeerSSHHostKeyResponse', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..a<$core.List<$core.int>>( + 1, _omitFieldNames ? '' : 'sshHostKey', $pb.PbFieldType.OY, + protoName: 'sshHostKey') + ..aOS(2, _omitFieldNames ? '' : 'peerIP', protoName: 'peerIP') + ..aOS(3, _omitFieldNames ? '' : 'peerFQDN', protoName: 'peerFQDN') + ..aOB(4, _omitFieldNames ? '' : 'found') + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + GetPeerSSHHostKeyResponse clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + GetPeerSSHHostKeyResponse copyWith( + void Function(GetPeerSSHHostKeyResponse) updates) => + super.copyWith((message) => updates(message as GetPeerSSHHostKeyResponse)) + as GetPeerSSHHostKeyResponse; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static GetPeerSSHHostKeyResponse create() => GetPeerSSHHostKeyResponse._(); + @$core.override + GetPeerSSHHostKeyResponse createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static GetPeerSSHHostKeyResponse getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static GetPeerSSHHostKeyResponse? _defaultInstance; + + /// SSH host key in SSH public key format (e.g., "ssh-ed25519 AAAAC3... hostname") + @$pb.TagNumber(1) + $core.List<$core.int> get sshHostKey => $_getN(0); + @$pb.TagNumber(1) + set sshHostKey($core.List<$core.int> value) => $_setBytes(0, value); + @$pb.TagNumber(1) + $core.bool hasSshHostKey() => $_has(0); + @$pb.TagNumber(1) + void clearSshHostKey() => $_clearField(1); + + /// peer IP address + @$pb.TagNumber(2) + $core.String get peerIP => $_getSZ(1); + @$pb.TagNumber(2) + set peerIP($core.String value) => $_setString(1, value); + @$pb.TagNumber(2) + $core.bool hasPeerIP() => $_has(1); + @$pb.TagNumber(2) + void clearPeerIP() => $_clearField(2); + + /// peer FQDN + @$pb.TagNumber(3) + $core.String get peerFQDN => $_getSZ(2); + @$pb.TagNumber(3) + set peerFQDN($core.String value) => $_setString(2, value); + @$pb.TagNumber(3) + $core.bool hasPeerFQDN() => $_has(2); + @$pb.TagNumber(3) + void clearPeerFQDN() => $_clearField(3); + + /// indicates if the SSH host key was found + @$pb.TagNumber(4) + $core.bool get found => $_getBF(3); + @$pb.TagNumber(4) + set found($core.bool value) => $_setBool(3, value); + @$pb.TagNumber(4) + $core.bool hasFound() => $_has(3); + @$pb.TagNumber(4) + void clearFound() => $_clearField(4); +} + +/// RequestJWTAuthRequest for initiating JWT authentication flow +class RequestJWTAuthRequest extends $pb.GeneratedMessage { + factory RequestJWTAuthRequest({ + $core.String? hint, + }) { + final result = create(); + if (hint != null) result.hint = hint; + return result; + } + + RequestJWTAuthRequest._(); + + factory RequestJWTAuthRequest.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory RequestJWTAuthRequest.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'RequestJWTAuthRequest', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..aOS(1, _omitFieldNames ? '' : 'hint') + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + RequestJWTAuthRequest clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + RequestJWTAuthRequest copyWith( + void Function(RequestJWTAuthRequest) updates) => + super.copyWith((message) => updates(message as RequestJWTAuthRequest)) + as RequestJWTAuthRequest; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static RequestJWTAuthRequest create() => RequestJWTAuthRequest._(); + @$core.override + RequestJWTAuthRequest createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static RequestJWTAuthRequest getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static RequestJWTAuthRequest? _defaultInstance; + + /// hint for OIDC login_hint parameter (typically email address) + @$pb.TagNumber(1) + $core.String get hint => $_getSZ(0); + @$pb.TagNumber(1) + set hint($core.String value) => $_setString(0, value); + @$pb.TagNumber(1) + $core.bool hasHint() => $_has(0); + @$pb.TagNumber(1) + void clearHint() => $_clearField(1); +} + +/// RequestJWTAuthResponse contains authentication flow information +class RequestJWTAuthResponse extends $pb.GeneratedMessage { + factory RequestJWTAuthResponse({ + $core.String? verificationURI, + $core.String? verificationURIComplete, + $core.String? userCode, + $core.String? deviceCode, + $fixnum.Int64? expiresIn, + $core.String? cachedToken, + $fixnum.Int64? maxTokenAge, + }) { + final result = create(); + if (verificationURI != null) result.verificationURI = verificationURI; + if (verificationURIComplete != null) + result.verificationURIComplete = verificationURIComplete; + if (userCode != null) result.userCode = userCode; + if (deviceCode != null) result.deviceCode = deviceCode; + if (expiresIn != null) result.expiresIn = expiresIn; + if (cachedToken != null) result.cachedToken = cachedToken; + if (maxTokenAge != null) result.maxTokenAge = maxTokenAge; + return result; + } + + RequestJWTAuthResponse._(); + + factory RequestJWTAuthResponse.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory RequestJWTAuthResponse.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'RequestJWTAuthResponse', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..aOS(1, _omitFieldNames ? '' : 'verificationURI', + protoName: 'verificationURI') + ..aOS(2, _omitFieldNames ? '' : 'verificationURIComplete', + protoName: 'verificationURIComplete') + ..aOS(3, _omitFieldNames ? '' : 'userCode', protoName: 'userCode') + ..aOS(4, _omitFieldNames ? '' : 'deviceCode', protoName: 'deviceCode') + ..aInt64(5, _omitFieldNames ? '' : 'expiresIn', protoName: 'expiresIn') + ..aOS(6, _omitFieldNames ? '' : 'cachedToken', protoName: 'cachedToken') + ..aInt64(7, _omitFieldNames ? '' : 'maxTokenAge', protoName: 'maxTokenAge') + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + RequestJWTAuthResponse clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + RequestJWTAuthResponse copyWith( + void Function(RequestJWTAuthResponse) updates) => + super.copyWith((message) => updates(message as RequestJWTAuthResponse)) + as RequestJWTAuthResponse; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static RequestJWTAuthResponse create() => RequestJWTAuthResponse._(); + @$core.override + RequestJWTAuthResponse createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static RequestJWTAuthResponse getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static RequestJWTAuthResponse? _defaultInstance; + + /// verification URI for user authentication + @$pb.TagNumber(1) + $core.String get verificationURI => $_getSZ(0); + @$pb.TagNumber(1) + set verificationURI($core.String value) => $_setString(0, value); + @$pb.TagNumber(1) + $core.bool hasVerificationURI() => $_has(0); + @$pb.TagNumber(1) + void clearVerificationURI() => $_clearField(1); + + /// complete verification URI (with embedded user code) + @$pb.TagNumber(2) + $core.String get verificationURIComplete => $_getSZ(1); + @$pb.TagNumber(2) + set verificationURIComplete($core.String value) => $_setString(1, value); + @$pb.TagNumber(2) + $core.bool hasVerificationURIComplete() => $_has(1); + @$pb.TagNumber(2) + void clearVerificationURIComplete() => $_clearField(2); + + /// user code to enter on verification URI + @$pb.TagNumber(3) + $core.String get userCode => $_getSZ(2); + @$pb.TagNumber(3) + set userCode($core.String value) => $_setString(2, value); + @$pb.TagNumber(3) + $core.bool hasUserCode() => $_has(2); + @$pb.TagNumber(3) + void clearUserCode() => $_clearField(3); + + /// device code for polling + @$pb.TagNumber(4) + $core.String get deviceCode => $_getSZ(3); + @$pb.TagNumber(4) + set deviceCode($core.String value) => $_setString(3, value); + @$pb.TagNumber(4) + $core.bool hasDeviceCode() => $_has(3); + @$pb.TagNumber(4) + void clearDeviceCode() => $_clearField(4); + + /// expiration time in seconds + @$pb.TagNumber(5) + $fixnum.Int64 get expiresIn => $_getI64(4); + @$pb.TagNumber(5) + set expiresIn($fixnum.Int64 value) => $_setInt64(4, value); + @$pb.TagNumber(5) + $core.bool hasExpiresIn() => $_has(4); + @$pb.TagNumber(5) + void clearExpiresIn() => $_clearField(5); + + /// if a cached token is available, it will be returned here + @$pb.TagNumber(6) + $core.String get cachedToken => $_getSZ(5); + @$pb.TagNumber(6) + set cachedToken($core.String value) => $_setString(5, value); + @$pb.TagNumber(6) + $core.bool hasCachedToken() => $_has(5); + @$pb.TagNumber(6) + void clearCachedToken() => $_clearField(6); + + /// maximum age of JWT tokens in seconds (from management server) + @$pb.TagNumber(7) + $fixnum.Int64 get maxTokenAge => $_getI64(6); + @$pb.TagNumber(7) + set maxTokenAge($fixnum.Int64 value) => $_setInt64(6, value); + @$pb.TagNumber(7) + $core.bool hasMaxTokenAge() => $_has(6); + @$pb.TagNumber(7) + void clearMaxTokenAge() => $_clearField(7); +} + +/// WaitJWTTokenRequest for waiting for authentication completion +class WaitJWTTokenRequest extends $pb.GeneratedMessage { + factory WaitJWTTokenRequest({ + $core.String? deviceCode, + $core.String? userCode, + }) { + final result = create(); + if (deviceCode != null) result.deviceCode = deviceCode; + if (userCode != null) result.userCode = userCode; + return result; + } + + WaitJWTTokenRequest._(); + + factory WaitJWTTokenRequest.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory WaitJWTTokenRequest.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'WaitJWTTokenRequest', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..aOS(1, _omitFieldNames ? '' : 'deviceCode', protoName: 'deviceCode') + ..aOS(2, _omitFieldNames ? '' : 'userCode', protoName: 'userCode') + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + WaitJWTTokenRequest clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + WaitJWTTokenRequest copyWith(void Function(WaitJWTTokenRequest) updates) => + super.copyWith((message) => updates(message as WaitJWTTokenRequest)) + as WaitJWTTokenRequest; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static WaitJWTTokenRequest create() => WaitJWTTokenRequest._(); + @$core.override + WaitJWTTokenRequest createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static WaitJWTTokenRequest getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static WaitJWTTokenRequest? _defaultInstance; + + /// device code from RequestJWTAuthResponse + @$pb.TagNumber(1) + $core.String get deviceCode => $_getSZ(0); + @$pb.TagNumber(1) + set deviceCode($core.String value) => $_setString(0, value); + @$pb.TagNumber(1) + $core.bool hasDeviceCode() => $_has(0); + @$pb.TagNumber(1) + void clearDeviceCode() => $_clearField(1); + + /// user code for verification + @$pb.TagNumber(2) + $core.String get userCode => $_getSZ(1); + @$pb.TagNumber(2) + set userCode($core.String value) => $_setString(1, value); + @$pb.TagNumber(2) + $core.bool hasUserCode() => $_has(1); + @$pb.TagNumber(2) + void clearUserCode() => $_clearField(2); +} + +/// WaitJWTTokenResponse contains the JWT token after authentication +class WaitJWTTokenResponse extends $pb.GeneratedMessage { + factory WaitJWTTokenResponse({ + $core.String? token, + $core.String? tokenType, + $fixnum.Int64? expiresIn, + }) { + final result = create(); + if (token != null) result.token = token; + if (tokenType != null) result.tokenType = tokenType; + if (expiresIn != null) result.expiresIn = expiresIn; + return result; + } + + WaitJWTTokenResponse._(); + + factory WaitJWTTokenResponse.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory WaitJWTTokenResponse.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'WaitJWTTokenResponse', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..aOS(1, _omitFieldNames ? '' : 'token') + ..aOS(2, _omitFieldNames ? '' : 'tokenType', protoName: 'tokenType') + ..aInt64(3, _omitFieldNames ? '' : 'expiresIn', protoName: 'expiresIn') + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + WaitJWTTokenResponse clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + WaitJWTTokenResponse copyWith(void Function(WaitJWTTokenResponse) updates) => + super.copyWith((message) => updates(message as WaitJWTTokenResponse)) + as WaitJWTTokenResponse; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static WaitJWTTokenResponse create() => WaitJWTTokenResponse._(); + @$core.override + WaitJWTTokenResponse createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static WaitJWTTokenResponse getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static WaitJWTTokenResponse? _defaultInstance; + + /// JWT token (access token or ID token) + @$pb.TagNumber(1) + $core.String get token => $_getSZ(0); + @$pb.TagNumber(1) + set token($core.String value) => $_setString(0, value); + @$pb.TagNumber(1) + $core.bool hasToken() => $_has(0); + @$pb.TagNumber(1) + void clearToken() => $_clearField(1); + + /// token type (e.g., "Bearer") + @$pb.TagNumber(2) + $core.String get tokenType => $_getSZ(1); + @$pb.TagNumber(2) + set tokenType($core.String value) => $_setString(1, value); + @$pb.TagNumber(2) + $core.bool hasTokenType() => $_has(1); + @$pb.TagNumber(2) + void clearTokenType() => $_clearField(2); + + /// expiration time in seconds + @$pb.TagNumber(3) + $fixnum.Int64 get expiresIn => $_getI64(2); + @$pb.TagNumber(3) + set expiresIn($fixnum.Int64 value) => $_setInt64(2, value); + @$pb.TagNumber(3) + $core.bool hasExpiresIn() => $_has(2); + @$pb.TagNumber(3) + void clearExpiresIn() => $_clearField(3); +} + +/// StartCPUProfileRequest for starting CPU profiling +class StartCPUProfileRequest extends $pb.GeneratedMessage { + factory StartCPUProfileRequest() => create(); + + StartCPUProfileRequest._(); + + factory StartCPUProfileRequest.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory StartCPUProfileRequest.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'StartCPUProfileRequest', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + StartCPUProfileRequest clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + StartCPUProfileRequest copyWith( + void Function(StartCPUProfileRequest) updates) => + super.copyWith((message) => updates(message as StartCPUProfileRequest)) + as StartCPUProfileRequest; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static StartCPUProfileRequest create() => StartCPUProfileRequest._(); + @$core.override + StartCPUProfileRequest createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static StartCPUProfileRequest getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static StartCPUProfileRequest? _defaultInstance; +} + +/// StartCPUProfileResponse confirms CPU profiling has started +class StartCPUProfileResponse extends $pb.GeneratedMessage { + factory StartCPUProfileResponse() => create(); + + StartCPUProfileResponse._(); + + factory StartCPUProfileResponse.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory StartCPUProfileResponse.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'StartCPUProfileResponse', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + StartCPUProfileResponse clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + StartCPUProfileResponse copyWith( + void Function(StartCPUProfileResponse) updates) => + super.copyWith((message) => updates(message as StartCPUProfileResponse)) + as StartCPUProfileResponse; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static StartCPUProfileResponse create() => StartCPUProfileResponse._(); + @$core.override + StartCPUProfileResponse createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static StartCPUProfileResponse getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static StartCPUProfileResponse? _defaultInstance; +} + +/// StopCPUProfileRequest for stopping CPU profiling +class StopCPUProfileRequest extends $pb.GeneratedMessage { + factory StopCPUProfileRequest() => create(); + + StopCPUProfileRequest._(); + + factory StopCPUProfileRequest.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory StopCPUProfileRequest.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'StopCPUProfileRequest', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + StopCPUProfileRequest clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + StopCPUProfileRequest copyWith( + void Function(StopCPUProfileRequest) updates) => + super.copyWith((message) => updates(message as StopCPUProfileRequest)) + as StopCPUProfileRequest; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static StopCPUProfileRequest create() => StopCPUProfileRequest._(); + @$core.override + StopCPUProfileRequest createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static StopCPUProfileRequest getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static StopCPUProfileRequest? _defaultInstance; +} + +/// StopCPUProfileResponse confirms CPU profiling has stopped +class StopCPUProfileResponse extends $pb.GeneratedMessage { + factory StopCPUProfileResponse() => create(); + + StopCPUProfileResponse._(); + + factory StopCPUProfileResponse.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory StopCPUProfileResponse.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'StopCPUProfileResponse', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + StopCPUProfileResponse clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + StopCPUProfileResponse copyWith( + void Function(StopCPUProfileResponse) updates) => + super.copyWith((message) => updates(message as StopCPUProfileResponse)) + as StopCPUProfileResponse; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static StopCPUProfileResponse create() => StopCPUProfileResponse._(); + @$core.override + StopCPUProfileResponse createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static StopCPUProfileResponse getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static StopCPUProfileResponse? _defaultInstance; +} + +class InstallerResultRequest extends $pb.GeneratedMessage { + factory InstallerResultRequest() => create(); + + InstallerResultRequest._(); + + factory InstallerResultRequest.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory InstallerResultRequest.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'InstallerResultRequest', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + InstallerResultRequest clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + InstallerResultRequest copyWith( + void Function(InstallerResultRequest) updates) => + super.copyWith((message) => updates(message as InstallerResultRequest)) + as InstallerResultRequest; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static InstallerResultRequest create() => InstallerResultRequest._(); + @$core.override + InstallerResultRequest createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static InstallerResultRequest getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static InstallerResultRequest? _defaultInstance; +} + +class InstallerResultResponse extends $pb.GeneratedMessage { + factory InstallerResultResponse({ + $core.bool? success, + $core.String? errorMsg, + }) { + final result = create(); + if (success != null) result.success = success; + if (errorMsg != null) result.errorMsg = errorMsg; + return result; + } + + InstallerResultResponse._(); + + factory InstallerResultResponse.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory InstallerResultResponse.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'InstallerResultResponse', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..aOB(1, _omitFieldNames ? '' : 'success') + ..aOS(2, _omitFieldNames ? '' : 'errorMsg', protoName: 'errorMsg') + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + InstallerResultResponse clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + InstallerResultResponse copyWith( + void Function(InstallerResultResponse) updates) => + super.copyWith((message) => updates(message as InstallerResultResponse)) + as InstallerResultResponse; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static InstallerResultResponse create() => InstallerResultResponse._(); + @$core.override + InstallerResultResponse createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static InstallerResultResponse getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static InstallerResultResponse? _defaultInstance; + + @$pb.TagNumber(1) + $core.bool get success => $_getBF(0); + @$pb.TagNumber(1) + set success($core.bool value) => $_setBool(0, value); + @$pb.TagNumber(1) + $core.bool hasSuccess() => $_has(0); + @$pb.TagNumber(1) + void clearSuccess() => $_clearField(1); + + @$pb.TagNumber(2) + $core.String get errorMsg => $_getSZ(1); + @$pb.TagNumber(2) + set errorMsg($core.String value) => $_setString(1, value); + @$pb.TagNumber(2) + $core.bool hasErrorMsg() => $_has(1); + @$pb.TagNumber(2) + void clearErrorMsg() => $_clearField(2); +} + +class ExposeServiceRequest extends $pb.GeneratedMessage { + factory ExposeServiceRequest({ + $core.int? port, + ExposeProtocol? protocol, + $core.String? pin, + $core.String? password, + $core.Iterable<$core.String>? userGroups, + $core.String? domain, + $core.String? namePrefix, + $core.int? listenPort, + }) { + final result = create(); + if (port != null) result.port = port; + if (protocol != null) result.protocol = protocol; + if (pin != null) result.pin = pin; + if (password != null) result.password = password; + if (userGroups != null) result.userGroups.addAll(userGroups); + if (domain != null) result.domain = domain; + if (namePrefix != null) result.namePrefix = namePrefix; + if (listenPort != null) result.listenPort = listenPort; + return result; + } + + ExposeServiceRequest._(); + + factory ExposeServiceRequest.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory ExposeServiceRequest.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'ExposeServiceRequest', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..aI(1, _omitFieldNames ? '' : 'port', fieldType: $pb.PbFieldType.OU3) + ..aE(2, _omitFieldNames ? '' : 'protocol', + enumValues: ExposeProtocol.values) + ..aOS(3, _omitFieldNames ? '' : 'pin') + ..aOS(4, _omitFieldNames ? '' : 'password') + ..pPS(5, _omitFieldNames ? '' : 'userGroups') + ..aOS(6, _omitFieldNames ? '' : 'domain') + ..aOS(7, _omitFieldNames ? '' : 'namePrefix') + ..aI(8, _omitFieldNames ? '' : 'listenPort', fieldType: $pb.PbFieldType.OU3) + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + ExposeServiceRequest clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + ExposeServiceRequest copyWith(void Function(ExposeServiceRequest) updates) => + super.copyWith((message) => updates(message as ExposeServiceRequest)) + as ExposeServiceRequest; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static ExposeServiceRequest create() => ExposeServiceRequest._(); + @$core.override + ExposeServiceRequest createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static ExposeServiceRequest getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static ExposeServiceRequest? _defaultInstance; + + @$pb.TagNumber(1) + $core.int get port => $_getIZ(0); + @$pb.TagNumber(1) + set port($core.int value) => $_setUnsignedInt32(0, value); + @$pb.TagNumber(1) + $core.bool hasPort() => $_has(0); + @$pb.TagNumber(1) + void clearPort() => $_clearField(1); + + @$pb.TagNumber(2) + ExposeProtocol get protocol => $_getN(1); + @$pb.TagNumber(2) + set protocol(ExposeProtocol value) => $_setField(2, value); + @$pb.TagNumber(2) + $core.bool hasProtocol() => $_has(1); + @$pb.TagNumber(2) + void clearProtocol() => $_clearField(2); + + @$pb.TagNumber(3) + $core.String get pin => $_getSZ(2); + @$pb.TagNumber(3) + set pin($core.String value) => $_setString(2, value); + @$pb.TagNumber(3) + $core.bool hasPin() => $_has(2); + @$pb.TagNumber(3) + void clearPin() => $_clearField(3); + + @$pb.TagNumber(4) + $core.String get password => $_getSZ(3); + @$pb.TagNumber(4) + set password($core.String value) => $_setString(3, value); + @$pb.TagNumber(4) + $core.bool hasPassword() => $_has(3); + @$pb.TagNumber(4) + void clearPassword() => $_clearField(4); + + @$pb.TagNumber(5) + $pb.PbList<$core.String> get userGroups => $_getList(4); + + @$pb.TagNumber(6) + $core.String get domain => $_getSZ(5); + @$pb.TagNumber(6) + set domain($core.String value) => $_setString(5, value); + @$pb.TagNumber(6) + $core.bool hasDomain() => $_has(5); + @$pb.TagNumber(6) + void clearDomain() => $_clearField(6); + + @$pb.TagNumber(7) + $core.String get namePrefix => $_getSZ(6); + @$pb.TagNumber(7) + set namePrefix($core.String value) => $_setString(6, value); + @$pb.TagNumber(7) + $core.bool hasNamePrefix() => $_has(6); + @$pb.TagNumber(7) + void clearNamePrefix() => $_clearField(7); + + @$pb.TagNumber(8) + $core.int get listenPort => $_getIZ(7); + @$pb.TagNumber(8) + set listenPort($core.int value) => $_setUnsignedInt32(7, value); + @$pb.TagNumber(8) + $core.bool hasListenPort() => $_has(7); + @$pb.TagNumber(8) + void clearListenPort() => $_clearField(8); +} + +enum ExposeServiceEvent_Event { ready, notSet } + +class ExposeServiceEvent extends $pb.GeneratedMessage { + factory ExposeServiceEvent({ + ExposeServiceReady? ready, + }) { + final result = create(); + if (ready != null) result.ready = ready; + return result; + } + + ExposeServiceEvent._(); + + factory ExposeServiceEvent.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory ExposeServiceEvent.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static const $core.Map<$core.int, ExposeServiceEvent_Event> + _ExposeServiceEvent_EventByTag = { + 1: ExposeServiceEvent_Event.ready, + 0: ExposeServiceEvent_Event.notSet + }; + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'ExposeServiceEvent', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..oo(0, [1]) + ..aOM(1, _omitFieldNames ? '' : 'ready', + subBuilder: ExposeServiceReady.create) + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + ExposeServiceEvent clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + ExposeServiceEvent copyWith(void Function(ExposeServiceEvent) updates) => + super.copyWith((message) => updates(message as ExposeServiceEvent)) + as ExposeServiceEvent; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static ExposeServiceEvent create() => ExposeServiceEvent._(); + @$core.override + ExposeServiceEvent createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static ExposeServiceEvent getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static ExposeServiceEvent? _defaultInstance; + + @$pb.TagNumber(1) + ExposeServiceEvent_Event whichEvent() => + _ExposeServiceEvent_EventByTag[$_whichOneof(0)]!; + @$pb.TagNumber(1) + void clearEvent() => $_clearField($_whichOneof(0)); + + @$pb.TagNumber(1) + ExposeServiceReady get ready => $_getN(0); + @$pb.TagNumber(1) + set ready(ExposeServiceReady value) => $_setField(1, value); + @$pb.TagNumber(1) + $core.bool hasReady() => $_has(0); + @$pb.TagNumber(1) + void clearReady() => $_clearField(1); + @$pb.TagNumber(1) + ExposeServiceReady ensureReady() => $_ensure(0); +} + +class ExposeServiceReady extends $pb.GeneratedMessage { + factory ExposeServiceReady({ + $core.String? serviceName, + $core.String? serviceUrl, + $core.String? domain, + $core.bool? portAutoAssigned, + }) { + final result = create(); + if (serviceName != null) result.serviceName = serviceName; + if (serviceUrl != null) result.serviceUrl = serviceUrl; + if (domain != null) result.domain = domain; + if (portAutoAssigned != null) result.portAutoAssigned = portAutoAssigned; + return result; + } + + ExposeServiceReady._(); + + factory ExposeServiceReady.fromBuffer($core.List<$core.int> data, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(data, registry); + factory ExposeServiceReady.fromJson($core.String json, + [$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) => + create()..mergeFromJson(json, registry); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo( + _omitMessageNames ? '' : 'ExposeServiceReady', + package: const $pb.PackageName(_omitMessageNames ? '' : 'daemon'), + createEmptyInstance: create) + ..aOS(1, _omitFieldNames ? '' : 'serviceName') + ..aOS(2, _omitFieldNames ? '' : 'serviceUrl') + ..aOS(3, _omitFieldNames ? '' : 'domain') + ..aOB(4, _omitFieldNames ? '' : 'portAutoAssigned') + ..hasRequiredFields = false; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + ExposeServiceReady clone() => deepCopy(); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + ExposeServiceReady copyWith(void Function(ExposeServiceReady) updates) => + super.copyWith((message) => updates(message as ExposeServiceReady)) + as ExposeServiceReady; + + @$core.override + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static ExposeServiceReady create() => ExposeServiceReady._(); + @$core.override + ExposeServiceReady createEmptyInstance() => create(); + @$core.pragma('dart2js:noInline') + static ExposeServiceReady getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static ExposeServiceReady? _defaultInstance; + + @$pb.TagNumber(1) + $core.String get serviceName => $_getSZ(0); + @$pb.TagNumber(1) + set serviceName($core.String value) => $_setString(0, value); + @$pb.TagNumber(1) + $core.bool hasServiceName() => $_has(0); + @$pb.TagNumber(1) + void clearServiceName() => $_clearField(1); + + @$pb.TagNumber(2) + $core.String get serviceUrl => $_getSZ(1); + @$pb.TagNumber(2) + set serviceUrl($core.String value) => $_setString(1, value); + @$pb.TagNumber(2) + $core.bool hasServiceUrl() => $_has(1); + @$pb.TagNumber(2) + void clearServiceUrl() => $_clearField(2); + + @$pb.TagNumber(3) + $core.String get domain => $_getSZ(2); + @$pb.TagNumber(3) + set domain($core.String value) => $_setString(2, value); + @$pb.TagNumber(3) + $core.bool hasDomain() => $_has(2); + @$pb.TagNumber(3) + void clearDomain() => $_clearField(3); + + @$pb.TagNumber(4) + $core.bool get portAutoAssigned => $_getBF(3); + @$pb.TagNumber(4) + set portAutoAssigned($core.bool value) => $_setBool(3, value); + @$pb.TagNumber(4) + $core.bool hasPortAutoAssigned() => $_has(3); + @$pb.TagNumber(4) + void clearPortAutoAssigned() => $_clearField(4); +} + +const $core.bool _omitFieldNames = + $core.bool.fromEnvironment('protobuf.omit_field_names'); +const $core.bool _omitMessageNames = + $core.bool.fromEnvironment('protobuf.omit_message_names'); diff --git a/client/flutter_ui/lib/src/generated/daemon.pbenum.dart b/client/flutter_ui/lib/src/generated/daemon.pbenum.dart new file mode 100644 index 000000000..bd2be46b4 --- /dev/null +++ b/client/flutter_ui/lib/src/generated/daemon.pbenum.dart @@ -0,0 +1,153 @@ +// This is a generated file - do not edit. +// +// Generated from daemon.proto. + +// @dart = 3.3 + +// ignore_for_file: annotate_overrides, camel_case_types, comment_references +// ignore_for_file: constant_identifier_names +// ignore_for_file: curly_braces_in_flow_control_structures +// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes +// ignore_for_file: non_constant_identifier_names, prefer_relative_imports + +import 'dart:core' as $core; + +import 'package:protobuf/protobuf.dart' as $pb; + +class LogLevel extends $pb.ProtobufEnum { + static const LogLevel UNKNOWN = + LogLevel._(0, _omitEnumNames ? '' : 'UNKNOWN'); + static const LogLevel PANIC = LogLevel._(1, _omitEnumNames ? '' : 'PANIC'); + static const LogLevel FATAL = LogLevel._(2, _omitEnumNames ? '' : 'FATAL'); + static const LogLevel ERROR = LogLevel._(3, _omitEnumNames ? '' : 'ERROR'); + static const LogLevel WARN = LogLevel._(4, _omitEnumNames ? '' : 'WARN'); + static const LogLevel INFO = LogLevel._(5, _omitEnumNames ? '' : 'INFO'); + static const LogLevel DEBUG = LogLevel._(6, _omitEnumNames ? '' : 'DEBUG'); + static const LogLevel TRACE = LogLevel._(7, _omitEnumNames ? '' : 'TRACE'); + + static const $core.List values = [ + UNKNOWN, + PANIC, + FATAL, + ERROR, + WARN, + INFO, + DEBUG, + TRACE, + ]; + + static final $core.List _byValue = + $pb.ProtobufEnum.$_initByValueList(values, 7); + static LogLevel? valueOf($core.int value) => + value < 0 || value >= _byValue.length ? null : _byValue[value]; + + const LogLevel._(super.value, super.name); +} + +class ExposeProtocol extends $pb.ProtobufEnum { + static const ExposeProtocol EXPOSE_HTTP = + ExposeProtocol._(0, _omitEnumNames ? '' : 'EXPOSE_HTTP'); + static const ExposeProtocol EXPOSE_HTTPS = + ExposeProtocol._(1, _omitEnumNames ? '' : 'EXPOSE_HTTPS'); + static const ExposeProtocol EXPOSE_TCP = + ExposeProtocol._(2, _omitEnumNames ? '' : 'EXPOSE_TCP'); + static const ExposeProtocol EXPOSE_UDP = + ExposeProtocol._(3, _omitEnumNames ? '' : 'EXPOSE_UDP'); + static const ExposeProtocol EXPOSE_TLS = + ExposeProtocol._(4, _omitEnumNames ? '' : 'EXPOSE_TLS'); + + static const $core.List values = [ + EXPOSE_HTTP, + EXPOSE_HTTPS, + EXPOSE_TCP, + EXPOSE_UDP, + EXPOSE_TLS, + ]; + + static final $core.List _byValue = + $pb.ProtobufEnum.$_initByValueList(values, 4); + static ExposeProtocol? valueOf($core.int value) => + value < 0 || value >= _byValue.length ? null : _byValue[value]; + + const ExposeProtocol._(super.value, super.name); +} + +/// avoid collision with loglevel enum +class OSLifecycleRequest_CycleType extends $pb.ProtobufEnum { + static const OSLifecycleRequest_CycleType UNKNOWN = + OSLifecycleRequest_CycleType._(0, _omitEnumNames ? '' : 'UNKNOWN'); + static const OSLifecycleRequest_CycleType SLEEP = + OSLifecycleRequest_CycleType._(1, _omitEnumNames ? '' : 'SLEEP'); + static const OSLifecycleRequest_CycleType WAKEUP = + OSLifecycleRequest_CycleType._(2, _omitEnumNames ? '' : 'WAKEUP'); + + static const $core.List values = + [ + UNKNOWN, + SLEEP, + WAKEUP, + ]; + + static final $core.List _byValue = + $pb.ProtobufEnum.$_initByValueList(values, 2); + static OSLifecycleRequest_CycleType? valueOf($core.int value) => + value < 0 || value >= _byValue.length ? null : _byValue[value]; + + const OSLifecycleRequest_CycleType._(super.value, super.name); +} + +class SystemEvent_Severity extends $pb.ProtobufEnum { + static const SystemEvent_Severity INFO = + SystemEvent_Severity._(0, _omitEnumNames ? '' : 'INFO'); + static const SystemEvent_Severity WARNING = + SystemEvent_Severity._(1, _omitEnumNames ? '' : 'WARNING'); + static const SystemEvent_Severity ERROR = + SystemEvent_Severity._(2, _omitEnumNames ? '' : 'ERROR'); + static const SystemEvent_Severity CRITICAL = + SystemEvent_Severity._(3, _omitEnumNames ? '' : 'CRITICAL'); + + static const $core.List values = [ + INFO, + WARNING, + ERROR, + CRITICAL, + ]; + + static final $core.List _byValue = + $pb.ProtobufEnum.$_initByValueList(values, 3); + static SystemEvent_Severity? valueOf($core.int value) => + value < 0 || value >= _byValue.length ? null : _byValue[value]; + + const SystemEvent_Severity._(super.value, super.name); +} + +class SystemEvent_Category extends $pb.ProtobufEnum { + static const SystemEvent_Category NETWORK = + SystemEvent_Category._(0, _omitEnumNames ? '' : 'NETWORK'); + static const SystemEvent_Category DNS = + SystemEvent_Category._(1, _omitEnumNames ? '' : 'DNS'); + static const SystemEvent_Category AUTHENTICATION = + SystemEvent_Category._(2, _omitEnumNames ? '' : 'AUTHENTICATION'); + static const SystemEvent_Category CONNECTIVITY = + SystemEvent_Category._(3, _omitEnumNames ? '' : 'CONNECTIVITY'); + static const SystemEvent_Category SYSTEM = + SystemEvent_Category._(4, _omitEnumNames ? '' : 'SYSTEM'); + + static const $core.List values = [ + NETWORK, + DNS, + AUTHENTICATION, + CONNECTIVITY, + SYSTEM, + ]; + + static final $core.List _byValue = + $pb.ProtobufEnum.$_initByValueList(values, 4); + static SystemEvent_Category? valueOf($core.int value) => + value < 0 || value >= _byValue.length ? null : _byValue[value]; + + const SystemEvent_Category._(super.value, super.name); +} + +const $core.bool _omitEnumNames = + $core.bool.fromEnvironment('protobuf.omit_enum_names'); diff --git a/client/flutter_ui/lib/src/generated/daemon.pbgrpc.dart b/client/flutter_ui/lib/src/generated/daemon.pbgrpc.dart new file mode 100644 index 000000000..4c4942b76 --- /dev/null +++ b/client/flutter_ui/lib/src/generated/daemon.pbgrpc.dart @@ -0,0 +1,1141 @@ +// This is a generated file - do not edit. +// +// Generated from daemon.proto. + +// @dart = 3.3 + +// ignore_for_file: annotate_overrides, camel_case_types, comment_references +// ignore_for_file: constant_identifier_names +// ignore_for_file: curly_braces_in_flow_control_structures +// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes +// ignore_for_file: non_constant_identifier_names, prefer_relative_imports + +import 'dart:async' as $async; +import 'dart:core' as $core; + +import 'package:grpc/service_api.dart' as $grpc; +import 'package:protobuf/protobuf.dart' as $pb; + +import 'daemon.pb.dart' as $0; + +export 'daemon.pb.dart'; + +@$pb.GrpcServiceName('daemon.DaemonService') +class DaemonServiceClient extends $grpc.Client { + /// The hostname for this service. + static const $core.String defaultHost = ''; + + /// OAuth scopes needed for the client. + static const $core.List<$core.String> oauthScopes = [ + '', + ]; + + DaemonServiceClient(super.channel, {super.options, super.interceptors}); + + /// Login uses setup key to prepare configuration for the daemon. + $grpc.ResponseFuture<$0.LoginResponse> login( + $0.LoginRequest request, { + $grpc.CallOptions? options, + }) { + return $createUnaryCall(_$login, request, options: options); + } + + /// WaitSSOLogin uses the userCode to validate the TokenInfo and + /// waits for the user to continue with the login on a browser + $grpc.ResponseFuture<$0.WaitSSOLoginResponse> waitSSOLogin( + $0.WaitSSOLoginRequest request, { + $grpc.CallOptions? options, + }) { + return $createUnaryCall(_$waitSSOLogin, request, options: options); + } + + /// Up starts engine work in the daemon. + $grpc.ResponseFuture<$0.UpResponse> up( + $0.UpRequest request, { + $grpc.CallOptions? options, + }) { + return $createUnaryCall(_$up, request, options: options); + } + + /// Status of the service. + $grpc.ResponseFuture<$0.StatusResponse> status( + $0.StatusRequest request, { + $grpc.CallOptions? options, + }) { + return $createUnaryCall(_$status, request, options: options); + } + + /// Down stops engine work in the daemon. + $grpc.ResponseFuture<$0.DownResponse> down( + $0.DownRequest request, { + $grpc.CallOptions? options, + }) { + return $createUnaryCall(_$down, request, options: options); + } + + /// GetConfig of the daemon. + $grpc.ResponseFuture<$0.GetConfigResponse> getConfig( + $0.GetConfigRequest request, { + $grpc.CallOptions? options, + }) { + return $createUnaryCall(_$getConfig, request, options: options); + } + + /// List available networks + $grpc.ResponseFuture<$0.ListNetworksResponse> listNetworks( + $0.ListNetworksRequest request, { + $grpc.CallOptions? options, + }) { + return $createUnaryCall(_$listNetworks, request, options: options); + } + + /// Select specific routes + $grpc.ResponseFuture<$0.SelectNetworksResponse> selectNetworks( + $0.SelectNetworksRequest request, { + $grpc.CallOptions? options, + }) { + return $createUnaryCall(_$selectNetworks, request, options: options); + } + + /// Deselect specific routes + $grpc.ResponseFuture<$0.SelectNetworksResponse> deselectNetworks( + $0.SelectNetworksRequest request, { + $grpc.CallOptions? options, + }) { + return $createUnaryCall(_$deselectNetworks, request, options: options); + } + + $grpc.ResponseFuture<$0.ForwardingRulesResponse> forwardingRules( + $0.EmptyRequest request, { + $grpc.CallOptions? options, + }) { + return $createUnaryCall(_$forwardingRules, request, options: options); + } + + /// DebugBundle creates a debug bundle + $grpc.ResponseFuture<$0.DebugBundleResponse> debugBundle( + $0.DebugBundleRequest request, { + $grpc.CallOptions? options, + }) { + return $createUnaryCall(_$debugBundle, request, options: options); + } + + /// GetLogLevel gets the log level of the daemon + $grpc.ResponseFuture<$0.GetLogLevelResponse> getLogLevel( + $0.GetLogLevelRequest request, { + $grpc.CallOptions? options, + }) { + return $createUnaryCall(_$getLogLevel, request, options: options); + } + + /// SetLogLevel sets the log level of the daemon + $grpc.ResponseFuture<$0.SetLogLevelResponse> setLogLevel( + $0.SetLogLevelRequest request, { + $grpc.CallOptions? options, + }) { + return $createUnaryCall(_$setLogLevel, request, options: options); + } + + /// List all states + $grpc.ResponseFuture<$0.ListStatesResponse> listStates( + $0.ListStatesRequest request, { + $grpc.CallOptions? options, + }) { + return $createUnaryCall(_$listStates, request, options: options); + } + + /// Clean specific state or all states + $grpc.ResponseFuture<$0.CleanStateResponse> cleanState( + $0.CleanStateRequest request, { + $grpc.CallOptions? options, + }) { + return $createUnaryCall(_$cleanState, request, options: options); + } + + /// Delete specific state or all states + $grpc.ResponseFuture<$0.DeleteStateResponse> deleteState( + $0.DeleteStateRequest request, { + $grpc.CallOptions? options, + }) { + return $createUnaryCall(_$deleteState, request, options: options); + } + + /// SetSyncResponsePersistence enables or disables sync response persistence + $grpc.ResponseFuture<$0.SetSyncResponsePersistenceResponse> + setSyncResponsePersistence( + $0.SetSyncResponsePersistenceRequest request, { + $grpc.CallOptions? options, + }) { + return $createUnaryCall(_$setSyncResponsePersistence, request, + options: options); + } + + $grpc.ResponseFuture<$0.TracePacketResponse> tracePacket( + $0.TracePacketRequest request, { + $grpc.CallOptions? options, + }) { + return $createUnaryCall(_$tracePacket, request, options: options); + } + + $grpc.ResponseStream<$0.SystemEvent> subscribeEvents( + $0.SubscribeRequest request, { + $grpc.CallOptions? options, + }) { + return $createStreamingCall( + _$subscribeEvents, $async.Stream.fromIterable([request]), + options: options); + } + + $grpc.ResponseFuture<$0.GetEventsResponse> getEvents( + $0.GetEventsRequest request, { + $grpc.CallOptions? options, + }) { + return $createUnaryCall(_$getEvents, request, options: options); + } + + $grpc.ResponseFuture<$0.SwitchProfileResponse> switchProfile( + $0.SwitchProfileRequest request, { + $grpc.CallOptions? options, + }) { + return $createUnaryCall(_$switchProfile, request, options: options); + } + + $grpc.ResponseFuture<$0.SetConfigResponse> setConfig( + $0.SetConfigRequest request, { + $grpc.CallOptions? options, + }) { + return $createUnaryCall(_$setConfig, request, options: options); + } + + $grpc.ResponseFuture<$0.AddProfileResponse> addProfile( + $0.AddProfileRequest request, { + $grpc.CallOptions? options, + }) { + return $createUnaryCall(_$addProfile, request, options: options); + } + + $grpc.ResponseFuture<$0.RemoveProfileResponse> removeProfile( + $0.RemoveProfileRequest request, { + $grpc.CallOptions? options, + }) { + return $createUnaryCall(_$removeProfile, request, options: options); + } + + $grpc.ResponseFuture<$0.ListProfilesResponse> listProfiles( + $0.ListProfilesRequest request, { + $grpc.CallOptions? options, + }) { + return $createUnaryCall(_$listProfiles, request, options: options); + } + + $grpc.ResponseFuture<$0.GetActiveProfileResponse> getActiveProfile( + $0.GetActiveProfileRequest request, { + $grpc.CallOptions? options, + }) { + return $createUnaryCall(_$getActiveProfile, request, options: options); + } + + /// Logout disconnects from the network and deletes the peer from the management server + $grpc.ResponseFuture<$0.LogoutResponse> logout( + $0.LogoutRequest request, { + $grpc.CallOptions? options, + }) { + return $createUnaryCall(_$logout, request, options: options); + } + + $grpc.ResponseFuture<$0.GetFeaturesResponse> getFeatures( + $0.GetFeaturesRequest request, { + $grpc.CallOptions? options, + }) { + return $createUnaryCall(_$getFeatures, request, options: options); + } + + /// TriggerUpdate initiates installation of the pending enforced version. + /// Called when the user clicks the install button in the UI (Mode 2 / enforced update). + $grpc.ResponseFuture<$0.TriggerUpdateResponse> triggerUpdate( + $0.TriggerUpdateRequest request, { + $grpc.CallOptions? options, + }) { + return $createUnaryCall(_$triggerUpdate, request, options: options); + } + + /// GetPeerSSHHostKey retrieves SSH host key for a specific peer + $grpc.ResponseFuture<$0.GetPeerSSHHostKeyResponse> getPeerSSHHostKey( + $0.GetPeerSSHHostKeyRequest request, { + $grpc.CallOptions? options, + }) { + return $createUnaryCall(_$getPeerSSHHostKey, request, options: options); + } + + /// RequestJWTAuth initiates JWT authentication flow for SSH + $grpc.ResponseFuture<$0.RequestJWTAuthResponse> requestJWTAuth( + $0.RequestJWTAuthRequest request, { + $grpc.CallOptions? options, + }) { + return $createUnaryCall(_$requestJWTAuth, request, options: options); + } + + /// WaitJWTToken waits for JWT authentication completion + $grpc.ResponseFuture<$0.WaitJWTTokenResponse> waitJWTToken( + $0.WaitJWTTokenRequest request, { + $grpc.CallOptions? options, + }) { + return $createUnaryCall(_$waitJWTToken, request, options: options); + } + + /// StartCPUProfile starts CPU profiling in the daemon + $grpc.ResponseFuture<$0.StartCPUProfileResponse> startCPUProfile( + $0.StartCPUProfileRequest request, { + $grpc.CallOptions? options, + }) { + return $createUnaryCall(_$startCPUProfile, request, options: options); + } + + /// StopCPUProfile stops CPU profiling in the daemon + $grpc.ResponseFuture<$0.StopCPUProfileResponse> stopCPUProfile( + $0.StopCPUProfileRequest request, { + $grpc.CallOptions? options, + }) { + return $createUnaryCall(_$stopCPUProfile, request, options: options); + } + + $grpc.ResponseFuture<$0.OSLifecycleResponse> notifyOSLifecycle( + $0.OSLifecycleRequest request, { + $grpc.CallOptions? options, + }) { + return $createUnaryCall(_$notifyOSLifecycle, request, options: options); + } + + $grpc.ResponseFuture<$0.InstallerResultResponse> getInstallerResult( + $0.InstallerResultRequest request, { + $grpc.CallOptions? options, + }) { + return $createUnaryCall(_$getInstallerResult, request, options: options); + } + + /// ExposeService exposes a local port via the NetBird reverse proxy + $grpc.ResponseStream<$0.ExposeServiceEvent> exposeService( + $0.ExposeServiceRequest request, { + $grpc.CallOptions? options, + }) { + return $createStreamingCall( + _$exposeService, $async.Stream.fromIterable([request]), + options: options); + } + + // method descriptors + + static final _$login = $grpc.ClientMethod<$0.LoginRequest, $0.LoginResponse>( + '/daemon.DaemonService/Login', + ($0.LoginRequest value) => value.writeToBuffer(), + $0.LoginResponse.fromBuffer); + static final _$waitSSOLogin = + $grpc.ClientMethod<$0.WaitSSOLoginRequest, $0.WaitSSOLoginResponse>( + '/daemon.DaemonService/WaitSSOLogin', + ($0.WaitSSOLoginRequest value) => value.writeToBuffer(), + $0.WaitSSOLoginResponse.fromBuffer); + static final _$up = $grpc.ClientMethod<$0.UpRequest, $0.UpResponse>( + '/daemon.DaemonService/Up', + ($0.UpRequest value) => value.writeToBuffer(), + $0.UpResponse.fromBuffer); + static final _$status = + $grpc.ClientMethod<$0.StatusRequest, $0.StatusResponse>( + '/daemon.DaemonService/Status', + ($0.StatusRequest value) => value.writeToBuffer(), + $0.StatusResponse.fromBuffer); + static final _$down = $grpc.ClientMethod<$0.DownRequest, $0.DownResponse>( + '/daemon.DaemonService/Down', + ($0.DownRequest value) => value.writeToBuffer(), + $0.DownResponse.fromBuffer); + static final _$getConfig = + $grpc.ClientMethod<$0.GetConfigRequest, $0.GetConfigResponse>( + '/daemon.DaemonService/GetConfig', + ($0.GetConfigRequest value) => value.writeToBuffer(), + $0.GetConfigResponse.fromBuffer); + static final _$listNetworks = + $grpc.ClientMethod<$0.ListNetworksRequest, $0.ListNetworksResponse>( + '/daemon.DaemonService/ListNetworks', + ($0.ListNetworksRequest value) => value.writeToBuffer(), + $0.ListNetworksResponse.fromBuffer); + static final _$selectNetworks = + $grpc.ClientMethod<$0.SelectNetworksRequest, $0.SelectNetworksResponse>( + '/daemon.DaemonService/SelectNetworks', + ($0.SelectNetworksRequest value) => value.writeToBuffer(), + $0.SelectNetworksResponse.fromBuffer); + static final _$deselectNetworks = + $grpc.ClientMethod<$0.SelectNetworksRequest, $0.SelectNetworksResponse>( + '/daemon.DaemonService/DeselectNetworks', + ($0.SelectNetworksRequest value) => value.writeToBuffer(), + $0.SelectNetworksResponse.fromBuffer); + static final _$forwardingRules = + $grpc.ClientMethod<$0.EmptyRequest, $0.ForwardingRulesResponse>( + '/daemon.DaemonService/ForwardingRules', + ($0.EmptyRequest value) => value.writeToBuffer(), + $0.ForwardingRulesResponse.fromBuffer); + static final _$debugBundle = + $grpc.ClientMethod<$0.DebugBundleRequest, $0.DebugBundleResponse>( + '/daemon.DaemonService/DebugBundle', + ($0.DebugBundleRequest value) => value.writeToBuffer(), + $0.DebugBundleResponse.fromBuffer); + static final _$getLogLevel = + $grpc.ClientMethod<$0.GetLogLevelRequest, $0.GetLogLevelResponse>( + '/daemon.DaemonService/GetLogLevel', + ($0.GetLogLevelRequest value) => value.writeToBuffer(), + $0.GetLogLevelResponse.fromBuffer); + static final _$setLogLevel = + $grpc.ClientMethod<$0.SetLogLevelRequest, $0.SetLogLevelResponse>( + '/daemon.DaemonService/SetLogLevel', + ($0.SetLogLevelRequest value) => value.writeToBuffer(), + $0.SetLogLevelResponse.fromBuffer); + static final _$listStates = + $grpc.ClientMethod<$0.ListStatesRequest, $0.ListStatesResponse>( + '/daemon.DaemonService/ListStates', + ($0.ListStatesRequest value) => value.writeToBuffer(), + $0.ListStatesResponse.fromBuffer); + static final _$cleanState = + $grpc.ClientMethod<$0.CleanStateRequest, $0.CleanStateResponse>( + '/daemon.DaemonService/CleanState', + ($0.CleanStateRequest value) => value.writeToBuffer(), + $0.CleanStateResponse.fromBuffer); + static final _$deleteState = + $grpc.ClientMethod<$0.DeleteStateRequest, $0.DeleteStateResponse>( + '/daemon.DaemonService/DeleteState', + ($0.DeleteStateRequest value) => value.writeToBuffer(), + $0.DeleteStateResponse.fromBuffer); + static final _$setSyncResponsePersistence = $grpc.ClientMethod< + $0.SetSyncResponsePersistenceRequest, + $0.SetSyncResponsePersistenceResponse>( + '/daemon.DaemonService/SetSyncResponsePersistence', + ($0.SetSyncResponsePersistenceRequest value) => value.writeToBuffer(), + $0.SetSyncResponsePersistenceResponse.fromBuffer); + static final _$tracePacket = + $grpc.ClientMethod<$0.TracePacketRequest, $0.TracePacketResponse>( + '/daemon.DaemonService/TracePacket', + ($0.TracePacketRequest value) => value.writeToBuffer(), + $0.TracePacketResponse.fromBuffer); + static final _$subscribeEvents = + $grpc.ClientMethod<$0.SubscribeRequest, $0.SystemEvent>( + '/daemon.DaemonService/SubscribeEvents', + ($0.SubscribeRequest value) => value.writeToBuffer(), + $0.SystemEvent.fromBuffer); + static final _$getEvents = + $grpc.ClientMethod<$0.GetEventsRequest, $0.GetEventsResponse>( + '/daemon.DaemonService/GetEvents', + ($0.GetEventsRequest value) => value.writeToBuffer(), + $0.GetEventsResponse.fromBuffer); + static final _$switchProfile = + $grpc.ClientMethod<$0.SwitchProfileRequest, $0.SwitchProfileResponse>( + '/daemon.DaemonService/SwitchProfile', + ($0.SwitchProfileRequest value) => value.writeToBuffer(), + $0.SwitchProfileResponse.fromBuffer); + static final _$setConfig = + $grpc.ClientMethod<$0.SetConfigRequest, $0.SetConfigResponse>( + '/daemon.DaemonService/SetConfig', + ($0.SetConfigRequest value) => value.writeToBuffer(), + $0.SetConfigResponse.fromBuffer); + static final _$addProfile = + $grpc.ClientMethod<$0.AddProfileRequest, $0.AddProfileResponse>( + '/daemon.DaemonService/AddProfile', + ($0.AddProfileRequest value) => value.writeToBuffer(), + $0.AddProfileResponse.fromBuffer); + static final _$removeProfile = + $grpc.ClientMethod<$0.RemoveProfileRequest, $0.RemoveProfileResponse>( + '/daemon.DaemonService/RemoveProfile', + ($0.RemoveProfileRequest value) => value.writeToBuffer(), + $0.RemoveProfileResponse.fromBuffer); + static final _$listProfiles = + $grpc.ClientMethod<$0.ListProfilesRequest, $0.ListProfilesResponse>( + '/daemon.DaemonService/ListProfiles', + ($0.ListProfilesRequest value) => value.writeToBuffer(), + $0.ListProfilesResponse.fromBuffer); + static final _$getActiveProfile = $grpc.ClientMethod< + $0.GetActiveProfileRequest, $0.GetActiveProfileResponse>( + '/daemon.DaemonService/GetActiveProfile', + ($0.GetActiveProfileRequest value) => value.writeToBuffer(), + $0.GetActiveProfileResponse.fromBuffer); + static final _$logout = + $grpc.ClientMethod<$0.LogoutRequest, $0.LogoutResponse>( + '/daemon.DaemonService/Logout', + ($0.LogoutRequest value) => value.writeToBuffer(), + $0.LogoutResponse.fromBuffer); + static final _$getFeatures = + $grpc.ClientMethod<$0.GetFeaturesRequest, $0.GetFeaturesResponse>( + '/daemon.DaemonService/GetFeatures', + ($0.GetFeaturesRequest value) => value.writeToBuffer(), + $0.GetFeaturesResponse.fromBuffer); + static final _$triggerUpdate = + $grpc.ClientMethod<$0.TriggerUpdateRequest, $0.TriggerUpdateResponse>( + '/daemon.DaemonService/TriggerUpdate', + ($0.TriggerUpdateRequest value) => value.writeToBuffer(), + $0.TriggerUpdateResponse.fromBuffer); + static final _$getPeerSSHHostKey = $grpc.ClientMethod< + $0.GetPeerSSHHostKeyRequest, $0.GetPeerSSHHostKeyResponse>( + '/daemon.DaemonService/GetPeerSSHHostKey', + ($0.GetPeerSSHHostKeyRequest value) => value.writeToBuffer(), + $0.GetPeerSSHHostKeyResponse.fromBuffer); + static final _$requestJWTAuth = + $grpc.ClientMethod<$0.RequestJWTAuthRequest, $0.RequestJWTAuthResponse>( + '/daemon.DaemonService/RequestJWTAuth', + ($0.RequestJWTAuthRequest value) => value.writeToBuffer(), + $0.RequestJWTAuthResponse.fromBuffer); + static final _$waitJWTToken = + $grpc.ClientMethod<$0.WaitJWTTokenRequest, $0.WaitJWTTokenResponse>( + '/daemon.DaemonService/WaitJWTToken', + ($0.WaitJWTTokenRequest value) => value.writeToBuffer(), + $0.WaitJWTTokenResponse.fromBuffer); + static final _$startCPUProfile = + $grpc.ClientMethod<$0.StartCPUProfileRequest, $0.StartCPUProfileResponse>( + '/daemon.DaemonService/StartCPUProfile', + ($0.StartCPUProfileRequest value) => value.writeToBuffer(), + $0.StartCPUProfileResponse.fromBuffer); + static final _$stopCPUProfile = + $grpc.ClientMethod<$0.StopCPUProfileRequest, $0.StopCPUProfileResponse>( + '/daemon.DaemonService/StopCPUProfile', + ($0.StopCPUProfileRequest value) => value.writeToBuffer(), + $0.StopCPUProfileResponse.fromBuffer); + static final _$notifyOSLifecycle = + $grpc.ClientMethod<$0.OSLifecycleRequest, $0.OSLifecycleResponse>( + '/daemon.DaemonService/NotifyOSLifecycle', + ($0.OSLifecycleRequest value) => value.writeToBuffer(), + $0.OSLifecycleResponse.fromBuffer); + static final _$getInstallerResult = + $grpc.ClientMethod<$0.InstallerResultRequest, $0.InstallerResultResponse>( + '/daemon.DaemonService/GetInstallerResult', + ($0.InstallerResultRequest value) => value.writeToBuffer(), + $0.InstallerResultResponse.fromBuffer); + static final _$exposeService = + $grpc.ClientMethod<$0.ExposeServiceRequest, $0.ExposeServiceEvent>( + '/daemon.DaemonService/ExposeService', + ($0.ExposeServiceRequest value) => value.writeToBuffer(), + $0.ExposeServiceEvent.fromBuffer); +} + +@$pb.GrpcServiceName('daemon.DaemonService') +abstract class DaemonServiceBase extends $grpc.Service { + $core.String get $name => 'daemon.DaemonService'; + + DaemonServiceBase() { + $addMethod($grpc.ServiceMethod<$0.LoginRequest, $0.LoginResponse>( + 'Login', + login_Pre, + false, + false, + ($core.List<$core.int> value) => $0.LoginRequest.fromBuffer(value), + ($0.LoginResponse value) => value.writeToBuffer())); + $addMethod( + $grpc.ServiceMethod<$0.WaitSSOLoginRequest, $0.WaitSSOLoginResponse>( + 'WaitSSOLogin', + waitSSOLogin_Pre, + false, + false, + ($core.List<$core.int> value) => + $0.WaitSSOLoginRequest.fromBuffer(value), + ($0.WaitSSOLoginResponse value) => value.writeToBuffer())); + $addMethod($grpc.ServiceMethod<$0.UpRequest, $0.UpResponse>( + 'Up', + up_Pre, + false, + false, + ($core.List<$core.int> value) => $0.UpRequest.fromBuffer(value), + ($0.UpResponse value) => value.writeToBuffer())); + $addMethod($grpc.ServiceMethod<$0.StatusRequest, $0.StatusResponse>( + 'Status', + status_Pre, + false, + false, + ($core.List<$core.int> value) => $0.StatusRequest.fromBuffer(value), + ($0.StatusResponse value) => value.writeToBuffer())); + $addMethod($grpc.ServiceMethod<$0.DownRequest, $0.DownResponse>( + 'Down', + down_Pre, + false, + false, + ($core.List<$core.int> value) => $0.DownRequest.fromBuffer(value), + ($0.DownResponse value) => value.writeToBuffer())); + $addMethod($grpc.ServiceMethod<$0.GetConfigRequest, $0.GetConfigResponse>( + 'GetConfig', + getConfig_Pre, + false, + false, + ($core.List<$core.int> value) => $0.GetConfigRequest.fromBuffer(value), + ($0.GetConfigResponse value) => value.writeToBuffer())); + $addMethod( + $grpc.ServiceMethod<$0.ListNetworksRequest, $0.ListNetworksResponse>( + 'ListNetworks', + listNetworks_Pre, + false, + false, + ($core.List<$core.int> value) => + $0.ListNetworksRequest.fromBuffer(value), + ($0.ListNetworksResponse value) => value.writeToBuffer())); + $addMethod($grpc.ServiceMethod<$0.SelectNetworksRequest, + $0.SelectNetworksResponse>( + 'SelectNetworks', + selectNetworks_Pre, + false, + false, + ($core.List<$core.int> value) => + $0.SelectNetworksRequest.fromBuffer(value), + ($0.SelectNetworksResponse value) => value.writeToBuffer())); + $addMethod($grpc.ServiceMethod<$0.SelectNetworksRequest, + $0.SelectNetworksResponse>( + 'DeselectNetworks', + deselectNetworks_Pre, + false, + false, + ($core.List<$core.int> value) => + $0.SelectNetworksRequest.fromBuffer(value), + ($0.SelectNetworksResponse value) => value.writeToBuffer())); + $addMethod($grpc.ServiceMethod<$0.EmptyRequest, $0.ForwardingRulesResponse>( + 'ForwardingRules', + forwardingRules_Pre, + false, + false, + ($core.List<$core.int> value) => $0.EmptyRequest.fromBuffer(value), + ($0.ForwardingRulesResponse value) => value.writeToBuffer())); + $addMethod( + $grpc.ServiceMethod<$0.DebugBundleRequest, $0.DebugBundleResponse>( + 'DebugBundle', + debugBundle_Pre, + false, + false, + ($core.List<$core.int> value) => + $0.DebugBundleRequest.fromBuffer(value), + ($0.DebugBundleResponse value) => value.writeToBuffer())); + $addMethod( + $grpc.ServiceMethod<$0.GetLogLevelRequest, $0.GetLogLevelResponse>( + 'GetLogLevel', + getLogLevel_Pre, + false, + false, + ($core.List<$core.int> value) => + $0.GetLogLevelRequest.fromBuffer(value), + ($0.GetLogLevelResponse value) => value.writeToBuffer())); + $addMethod( + $grpc.ServiceMethod<$0.SetLogLevelRequest, $0.SetLogLevelResponse>( + 'SetLogLevel', + setLogLevel_Pre, + false, + false, + ($core.List<$core.int> value) => + $0.SetLogLevelRequest.fromBuffer(value), + ($0.SetLogLevelResponse value) => value.writeToBuffer())); + $addMethod($grpc.ServiceMethod<$0.ListStatesRequest, $0.ListStatesResponse>( + 'ListStates', + listStates_Pre, + false, + false, + ($core.List<$core.int> value) => $0.ListStatesRequest.fromBuffer(value), + ($0.ListStatesResponse value) => value.writeToBuffer())); + $addMethod($grpc.ServiceMethod<$0.CleanStateRequest, $0.CleanStateResponse>( + 'CleanState', + cleanState_Pre, + false, + false, + ($core.List<$core.int> value) => $0.CleanStateRequest.fromBuffer(value), + ($0.CleanStateResponse value) => value.writeToBuffer())); + $addMethod( + $grpc.ServiceMethod<$0.DeleteStateRequest, $0.DeleteStateResponse>( + 'DeleteState', + deleteState_Pre, + false, + false, + ($core.List<$core.int> value) => + $0.DeleteStateRequest.fromBuffer(value), + ($0.DeleteStateResponse value) => value.writeToBuffer())); + $addMethod($grpc.ServiceMethod<$0.SetSyncResponsePersistenceRequest, + $0.SetSyncResponsePersistenceResponse>( + 'SetSyncResponsePersistence', + setSyncResponsePersistence_Pre, + false, + false, + ($core.List<$core.int> value) => + $0.SetSyncResponsePersistenceRequest.fromBuffer(value), + ($0.SetSyncResponsePersistenceResponse value) => + value.writeToBuffer())); + $addMethod( + $grpc.ServiceMethod<$0.TracePacketRequest, $0.TracePacketResponse>( + 'TracePacket', + tracePacket_Pre, + false, + false, + ($core.List<$core.int> value) => + $0.TracePacketRequest.fromBuffer(value), + ($0.TracePacketResponse value) => value.writeToBuffer())); + $addMethod($grpc.ServiceMethod<$0.SubscribeRequest, $0.SystemEvent>( + 'SubscribeEvents', + subscribeEvents_Pre, + false, + true, + ($core.List<$core.int> value) => $0.SubscribeRequest.fromBuffer(value), + ($0.SystemEvent value) => value.writeToBuffer())); + $addMethod($grpc.ServiceMethod<$0.GetEventsRequest, $0.GetEventsResponse>( + 'GetEvents', + getEvents_Pre, + false, + false, + ($core.List<$core.int> value) => $0.GetEventsRequest.fromBuffer(value), + ($0.GetEventsResponse value) => value.writeToBuffer())); + $addMethod( + $grpc.ServiceMethod<$0.SwitchProfileRequest, $0.SwitchProfileResponse>( + 'SwitchProfile', + switchProfile_Pre, + false, + false, + ($core.List<$core.int> value) => + $0.SwitchProfileRequest.fromBuffer(value), + ($0.SwitchProfileResponse value) => value.writeToBuffer())); + $addMethod($grpc.ServiceMethod<$0.SetConfigRequest, $0.SetConfigResponse>( + 'SetConfig', + setConfig_Pre, + false, + false, + ($core.List<$core.int> value) => $0.SetConfigRequest.fromBuffer(value), + ($0.SetConfigResponse value) => value.writeToBuffer())); + $addMethod($grpc.ServiceMethod<$0.AddProfileRequest, $0.AddProfileResponse>( + 'AddProfile', + addProfile_Pre, + false, + false, + ($core.List<$core.int> value) => $0.AddProfileRequest.fromBuffer(value), + ($0.AddProfileResponse value) => value.writeToBuffer())); + $addMethod( + $grpc.ServiceMethod<$0.RemoveProfileRequest, $0.RemoveProfileResponse>( + 'RemoveProfile', + removeProfile_Pre, + false, + false, + ($core.List<$core.int> value) => + $0.RemoveProfileRequest.fromBuffer(value), + ($0.RemoveProfileResponse value) => value.writeToBuffer())); + $addMethod( + $grpc.ServiceMethod<$0.ListProfilesRequest, $0.ListProfilesResponse>( + 'ListProfiles', + listProfiles_Pre, + false, + false, + ($core.List<$core.int> value) => + $0.ListProfilesRequest.fromBuffer(value), + ($0.ListProfilesResponse value) => value.writeToBuffer())); + $addMethod($grpc.ServiceMethod<$0.GetActiveProfileRequest, + $0.GetActiveProfileResponse>( + 'GetActiveProfile', + getActiveProfile_Pre, + false, + false, + ($core.List<$core.int> value) => + $0.GetActiveProfileRequest.fromBuffer(value), + ($0.GetActiveProfileResponse value) => value.writeToBuffer())); + $addMethod($grpc.ServiceMethod<$0.LogoutRequest, $0.LogoutResponse>( + 'Logout', + logout_Pre, + false, + false, + ($core.List<$core.int> value) => $0.LogoutRequest.fromBuffer(value), + ($0.LogoutResponse value) => value.writeToBuffer())); + $addMethod( + $grpc.ServiceMethod<$0.GetFeaturesRequest, $0.GetFeaturesResponse>( + 'GetFeatures', + getFeatures_Pre, + false, + false, + ($core.List<$core.int> value) => + $0.GetFeaturesRequest.fromBuffer(value), + ($0.GetFeaturesResponse value) => value.writeToBuffer())); + $addMethod( + $grpc.ServiceMethod<$0.TriggerUpdateRequest, $0.TriggerUpdateResponse>( + 'TriggerUpdate', + triggerUpdate_Pre, + false, + false, + ($core.List<$core.int> value) => + $0.TriggerUpdateRequest.fromBuffer(value), + ($0.TriggerUpdateResponse value) => value.writeToBuffer())); + $addMethod($grpc.ServiceMethod<$0.GetPeerSSHHostKeyRequest, + $0.GetPeerSSHHostKeyResponse>( + 'GetPeerSSHHostKey', + getPeerSSHHostKey_Pre, + false, + false, + ($core.List<$core.int> value) => + $0.GetPeerSSHHostKeyRequest.fromBuffer(value), + ($0.GetPeerSSHHostKeyResponse value) => value.writeToBuffer())); + $addMethod($grpc.ServiceMethod<$0.RequestJWTAuthRequest, + $0.RequestJWTAuthResponse>( + 'RequestJWTAuth', + requestJWTAuth_Pre, + false, + false, + ($core.List<$core.int> value) => + $0.RequestJWTAuthRequest.fromBuffer(value), + ($0.RequestJWTAuthResponse value) => value.writeToBuffer())); + $addMethod( + $grpc.ServiceMethod<$0.WaitJWTTokenRequest, $0.WaitJWTTokenResponse>( + 'WaitJWTToken', + waitJWTToken_Pre, + false, + false, + ($core.List<$core.int> value) => + $0.WaitJWTTokenRequest.fromBuffer(value), + ($0.WaitJWTTokenResponse value) => value.writeToBuffer())); + $addMethod($grpc.ServiceMethod<$0.StartCPUProfileRequest, + $0.StartCPUProfileResponse>( + 'StartCPUProfile', + startCPUProfile_Pre, + false, + false, + ($core.List<$core.int> value) => + $0.StartCPUProfileRequest.fromBuffer(value), + ($0.StartCPUProfileResponse value) => value.writeToBuffer())); + $addMethod($grpc.ServiceMethod<$0.StopCPUProfileRequest, + $0.StopCPUProfileResponse>( + 'StopCPUProfile', + stopCPUProfile_Pre, + false, + false, + ($core.List<$core.int> value) => + $0.StopCPUProfileRequest.fromBuffer(value), + ($0.StopCPUProfileResponse value) => value.writeToBuffer())); + $addMethod( + $grpc.ServiceMethod<$0.OSLifecycleRequest, $0.OSLifecycleResponse>( + 'NotifyOSLifecycle', + notifyOSLifecycle_Pre, + false, + false, + ($core.List<$core.int> value) => + $0.OSLifecycleRequest.fromBuffer(value), + ($0.OSLifecycleResponse value) => value.writeToBuffer())); + $addMethod($grpc.ServiceMethod<$0.InstallerResultRequest, + $0.InstallerResultResponse>( + 'GetInstallerResult', + getInstallerResult_Pre, + false, + false, + ($core.List<$core.int> value) => + $0.InstallerResultRequest.fromBuffer(value), + ($0.InstallerResultResponse value) => value.writeToBuffer())); + $addMethod( + $grpc.ServiceMethod<$0.ExposeServiceRequest, $0.ExposeServiceEvent>( + 'ExposeService', + exposeService_Pre, + false, + true, + ($core.List<$core.int> value) => + $0.ExposeServiceRequest.fromBuffer(value), + ($0.ExposeServiceEvent value) => value.writeToBuffer())); + } + + $async.Future<$0.LoginResponse> login_Pre( + $grpc.ServiceCall $call, $async.Future<$0.LoginRequest> $request) async { + return login($call, await $request); + } + + $async.Future<$0.LoginResponse> login( + $grpc.ServiceCall call, $0.LoginRequest request); + + $async.Future<$0.WaitSSOLoginResponse> waitSSOLogin_Pre( + $grpc.ServiceCall $call, + $async.Future<$0.WaitSSOLoginRequest> $request) async { + return waitSSOLogin($call, await $request); + } + + $async.Future<$0.WaitSSOLoginResponse> waitSSOLogin( + $grpc.ServiceCall call, $0.WaitSSOLoginRequest request); + + $async.Future<$0.UpResponse> up_Pre( + $grpc.ServiceCall $call, $async.Future<$0.UpRequest> $request) async { + return up($call, await $request); + } + + $async.Future<$0.UpResponse> up($grpc.ServiceCall call, $0.UpRequest request); + + $async.Future<$0.StatusResponse> status_Pre( + $grpc.ServiceCall $call, $async.Future<$0.StatusRequest> $request) async { + return status($call, await $request); + } + + $async.Future<$0.StatusResponse> status( + $grpc.ServiceCall call, $0.StatusRequest request); + + $async.Future<$0.DownResponse> down_Pre( + $grpc.ServiceCall $call, $async.Future<$0.DownRequest> $request) async { + return down($call, await $request); + } + + $async.Future<$0.DownResponse> down( + $grpc.ServiceCall call, $0.DownRequest request); + + $async.Future<$0.GetConfigResponse> getConfig_Pre($grpc.ServiceCall $call, + $async.Future<$0.GetConfigRequest> $request) async { + return getConfig($call, await $request); + } + + $async.Future<$0.GetConfigResponse> getConfig( + $grpc.ServiceCall call, $0.GetConfigRequest request); + + $async.Future<$0.ListNetworksResponse> listNetworks_Pre( + $grpc.ServiceCall $call, + $async.Future<$0.ListNetworksRequest> $request) async { + return listNetworks($call, await $request); + } + + $async.Future<$0.ListNetworksResponse> listNetworks( + $grpc.ServiceCall call, $0.ListNetworksRequest request); + + $async.Future<$0.SelectNetworksResponse> selectNetworks_Pre( + $grpc.ServiceCall $call, + $async.Future<$0.SelectNetworksRequest> $request) async { + return selectNetworks($call, await $request); + } + + $async.Future<$0.SelectNetworksResponse> selectNetworks( + $grpc.ServiceCall call, $0.SelectNetworksRequest request); + + $async.Future<$0.SelectNetworksResponse> deselectNetworks_Pre( + $grpc.ServiceCall $call, + $async.Future<$0.SelectNetworksRequest> $request) async { + return deselectNetworks($call, await $request); + } + + $async.Future<$0.SelectNetworksResponse> deselectNetworks( + $grpc.ServiceCall call, $0.SelectNetworksRequest request); + + $async.Future<$0.ForwardingRulesResponse> forwardingRules_Pre( + $grpc.ServiceCall $call, $async.Future<$0.EmptyRequest> $request) async { + return forwardingRules($call, await $request); + } + + $async.Future<$0.ForwardingRulesResponse> forwardingRules( + $grpc.ServiceCall call, $0.EmptyRequest request); + + $async.Future<$0.DebugBundleResponse> debugBundle_Pre($grpc.ServiceCall $call, + $async.Future<$0.DebugBundleRequest> $request) async { + return debugBundle($call, await $request); + } + + $async.Future<$0.DebugBundleResponse> debugBundle( + $grpc.ServiceCall call, $0.DebugBundleRequest request); + + $async.Future<$0.GetLogLevelResponse> getLogLevel_Pre($grpc.ServiceCall $call, + $async.Future<$0.GetLogLevelRequest> $request) async { + return getLogLevel($call, await $request); + } + + $async.Future<$0.GetLogLevelResponse> getLogLevel( + $grpc.ServiceCall call, $0.GetLogLevelRequest request); + + $async.Future<$0.SetLogLevelResponse> setLogLevel_Pre($grpc.ServiceCall $call, + $async.Future<$0.SetLogLevelRequest> $request) async { + return setLogLevel($call, await $request); + } + + $async.Future<$0.SetLogLevelResponse> setLogLevel( + $grpc.ServiceCall call, $0.SetLogLevelRequest request); + + $async.Future<$0.ListStatesResponse> listStates_Pre($grpc.ServiceCall $call, + $async.Future<$0.ListStatesRequest> $request) async { + return listStates($call, await $request); + } + + $async.Future<$0.ListStatesResponse> listStates( + $grpc.ServiceCall call, $0.ListStatesRequest request); + + $async.Future<$0.CleanStateResponse> cleanState_Pre($grpc.ServiceCall $call, + $async.Future<$0.CleanStateRequest> $request) async { + return cleanState($call, await $request); + } + + $async.Future<$0.CleanStateResponse> cleanState( + $grpc.ServiceCall call, $0.CleanStateRequest request); + + $async.Future<$0.DeleteStateResponse> deleteState_Pre($grpc.ServiceCall $call, + $async.Future<$0.DeleteStateRequest> $request) async { + return deleteState($call, await $request); + } + + $async.Future<$0.DeleteStateResponse> deleteState( + $grpc.ServiceCall call, $0.DeleteStateRequest request); + + $async.Future<$0.SetSyncResponsePersistenceResponse> + setSyncResponsePersistence_Pre($grpc.ServiceCall $call, + $async.Future<$0.SetSyncResponsePersistenceRequest> $request) async { + return setSyncResponsePersistence($call, await $request); + } + + $async.Future<$0.SetSyncResponsePersistenceResponse> + setSyncResponsePersistence( + $grpc.ServiceCall call, $0.SetSyncResponsePersistenceRequest request); + + $async.Future<$0.TracePacketResponse> tracePacket_Pre($grpc.ServiceCall $call, + $async.Future<$0.TracePacketRequest> $request) async { + return tracePacket($call, await $request); + } + + $async.Future<$0.TracePacketResponse> tracePacket( + $grpc.ServiceCall call, $0.TracePacketRequest request); + + $async.Stream<$0.SystemEvent> subscribeEvents_Pre($grpc.ServiceCall $call, + $async.Future<$0.SubscribeRequest> $request) async* { + yield* subscribeEvents($call, await $request); + } + + $async.Stream<$0.SystemEvent> subscribeEvents( + $grpc.ServiceCall call, $0.SubscribeRequest request); + + $async.Future<$0.GetEventsResponse> getEvents_Pre($grpc.ServiceCall $call, + $async.Future<$0.GetEventsRequest> $request) async { + return getEvents($call, await $request); + } + + $async.Future<$0.GetEventsResponse> getEvents( + $grpc.ServiceCall call, $0.GetEventsRequest request); + + $async.Future<$0.SwitchProfileResponse> switchProfile_Pre( + $grpc.ServiceCall $call, + $async.Future<$0.SwitchProfileRequest> $request) async { + return switchProfile($call, await $request); + } + + $async.Future<$0.SwitchProfileResponse> switchProfile( + $grpc.ServiceCall call, $0.SwitchProfileRequest request); + + $async.Future<$0.SetConfigResponse> setConfig_Pre($grpc.ServiceCall $call, + $async.Future<$0.SetConfigRequest> $request) async { + return setConfig($call, await $request); + } + + $async.Future<$0.SetConfigResponse> setConfig( + $grpc.ServiceCall call, $0.SetConfigRequest request); + + $async.Future<$0.AddProfileResponse> addProfile_Pre($grpc.ServiceCall $call, + $async.Future<$0.AddProfileRequest> $request) async { + return addProfile($call, await $request); + } + + $async.Future<$0.AddProfileResponse> addProfile( + $grpc.ServiceCall call, $0.AddProfileRequest request); + + $async.Future<$0.RemoveProfileResponse> removeProfile_Pre( + $grpc.ServiceCall $call, + $async.Future<$0.RemoveProfileRequest> $request) async { + return removeProfile($call, await $request); + } + + $async.Future<$0.RemoveProfileResponse> removeProfile( + $grpc.ServiceCall call, $0.RemoveProfileRequest request); + + $async.Future<$0.ListProfilesResponse> listProfiles_Pre( + $grpc.ServiceCall $call, + $async.Future<$0.ListProfilesRequest> $request) async { + return listProfiles($call, await $request); + } + + $async.Future<$0.ListProfilesResponse> listProfiles( + $grpc.ServiceCall call, $0.ListProfilesRequest request); + + $async.Future<$0.GetActiveProfileResponse> getActiveProfile_Pre( + $grpc.ServiceCall $call, + $async.Future<$0.GetActiveProfileRequest> $request) async { + return getActiveProfile($call, await $request); + } + + $async.Future<$0.GetActiveProfileResponse> getActiveProfile( + $grpc.ServiceCall call, $0.GetActiveProfileRequest request); + + $async.Future<$0.LogoutResponse> logout_Pre( + $grpc.ServiceCall $call, $async.Future<$0.LogoutRequest> $request) async { + return logout($call, await $request); + } + + $async.Future<$0.LogoutResponse> logout( + $grpc.ServiceCall call, $0.LogoutRequest request); + + $async.Future<$0.GetFeaturesResponse> getFeatures_Pre($grpc.ServiceCall $call, + $async.Future<$0.GetFeaturesRequest> $request) async { + return getFeatures($call, await $request); + } + + $async.Future<$0.GetFeaturesResponse> getFeatures( + $grpc.ServiceCall call, $0.GetFeaturesRequest request); + + $async.Future<$0.TriggerUpdateResponse> triggerUpdate_Pre( + $grpc.ServiceCall $call, + $async.Future<$0.TriggerUpdateRequest> $request) async { + return triggerUpdate($call, await $request); + } + + $async.Future<$0.TriggerUpdateResponse> triggerUpdate( + $grpc.ServiceCall call, $0.TriggerUpdateRequest request); + + $async.Future<$0.GetPeerSSHHostKeyResponse> getPeerSSHHostKey_Pre( + $grpc.ServiceCall $call, + $async.Future<$0.GetPeerSSHHostKeyRequest> $request) async { + return getPeerSSHHostKey($call, await $request); + } + + $async.Future<$0.GetPeerSSHHostKeyResponse> getPeerSSHHostKey( + $grpc.ServiceCall call, $0.GetPeerSSHHostKeyRequest request); + + $async.Future<$0.RequestJWTAuthResponse> requestJWTAuth_Pre( + $grpc.ServiceCall $call, + $async.Future<$0.RequestJWTAuthRequest> $request) async { + return requestJWTAuth($call, await $request); + } + + $async.Future<$0.RequestJWTAuthResponse> requestJWTAuth( + $grpc.ServiceCall call, $0.RequestJWTAuthRequest request); + + $async.Future<$0.WaitJWTTokenResponse> waitJWTToken_Pre( + $grpc.ServiceCall $call, + $async.Future<$0.WaitJWTTokenRequest> $request) async { + return waitJWTToken($call, await $request); + } + + $async.Future<$0.WaitJWTTokenResponse> waitJWTToken( + $grpc.ServiceCall call, $0.WaitJWTTokenRequest request); + + $async.Future<$0.StartCPUProfileResponse> startCPUProfile_Pre( + $grpc.ServiceCall $call, + $async.Future<$0.StartCPUProfileRequest> $request) async { + return startCPUProfile($call, await $request); + } + + $async.Future<$0.StartCPUProfileResponse> startCPUProfile( + $grpc.ServiceCall call, $0.StartCPUProfileRequest request); + + $async.Future<$0.StopCPUProfileResponse> stopCPUProfile_Pre( + $grpc.ServiceCall $call, + $async.Future<$0.StopCPUProfileRequest> $request) async { + return stopCPUProfile($call, await $request); + } + + $async.Future<$0.StopCPUProfileResponse> stopCPUProfile( + $grpc.ServiceCall call, $0.StopCPUProfileRequest request); + + $async.Future<$0.OSLifecycleResponse> notifyOSLifecycle_Pre( + $grpc.ServiceCall $call, + $async.Future<$0.OSLifecycleRequest> $request) async { + return notifyOSLifecycle($call, await $request); + } + + $async.Future<$0.OSLifecycleResponse> notifyOSLifecycle( + $grpc.ServiceCall call, $0.OSLifecycleRequest request); + + $async.Future<$0.InstallerResultResponse> getInstallerResult_Pre( + $grpc.ServiceCall $call, + $async.Future<$0.InstallerResultRequest> $request) async { + return getInstallerResult($call, await $request); + } + + $async.Future<$0.InstallerResultResponse> getInstallerResult( + $grpc.ServiceCall call, $0.InstallerResultRequest request); + + $async.Stream<$0.ExposeServiceEvent> exposeService_Pre( + $grpc.ServiceCall $call, + $async.Future<$0.ExposeServiceRequest> $request) async* { + yield* exposeService($call, await $request); + } + + $async.Stream<$0.ExposeServiceEvent> exposeService( + $grpc.ServiceCall call, $0.ExposeServiceRequest request); +} diff --git a/client/flutter_ui/lib/src/generated/daemon.pbjson.dart b/client/flutter_ui/lib/src/generated/daemon.pbjson.dart new file mode 100644 index 000000000..5191f475f --- /dev/null +++ b/client/flutter_ui/lib/src/generated/daemon.pbjson.dart @@ -0,0 +1,2589 @@ +// This is a generated file - do not edit. +// +// Generated from daemon.proto. + +// @dart = 3.3 + +// ignore_for_file: annotate_overrides, camel_case_types, comment_references +// ignore_for_file: constant_identifier_names +// ignore_for_file: curly_braces_in_flow_control_structures +// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes +// ignore_for_file: non_constant_identifier_names, prefer_relative_imports +// ignore_for_file: unused_import + +import 'dart:convert' as $convert; +import 'dart:core' as $core; +import 'dart:typed_data' as $typed_data; + +@$core.Deprecated('Use logLevelDescriptor instead') +const LogLevel$json = { + '1': 'LogLevel', + '2': [ + {'1': 'UNKNOWN', '2': 0}, + {'1': 'PANIC', '2': 1}, + {'1': 'FATAL', '2': 2}, + {'1': 'ERROR', '2': 3}, + {'1': 'WARN', '2': 4}, + {'1': 'INFO', '2': 5}, + {'1': 'DEBUG', '2': 6}, + {'1': 'TRACE', '2': 7}, + ], +}; + +/// Descriptor for `LogLevel`. Decode as a `google.protobuf.EnumDescriptorProto`. +final $typed_data.Uint8List logLevelDescriptor = $convert.base64Decode( + 'CghMb2dMZXZlbBILCgdVTktOT1dOEAASCQoFUEFOSUMQARIJCgVGQVRBTBACEgkKBUVSUk9SEA' + 'MSCAoEV0FSThAEEggKBElORk8QBRIJCgVERUJVRxAGEgkKBVRSQUNFEAc='); + +@$core.Deprecated('Use exposeProtocolDescriptor instead') +const ExposeProtocol$json = { + '1': 'ExposeProtocol', + '2': [ + {'1': 'EXPOSE_HTTP', '2': 0}, + {'1': 'EXPOSE_HTTPS', '2': 1}, + {'1': 'EXPOSE_TCP', '2': 2}, + {'1': 'EXPOSE_UDP', '2': 3}, + {'1': 'EXPOSE_TLS', '2': 4}, + ], +}; + +/// Descriptor for `ExposeProtocol`. Decode as a `google.protobuf.EnumDescriptorProto`. +final $typed_data.Uint8List exposeProtocolDescriptor = $convert.base64Decode( + 'Cg5FeHBvc2VQcm90b2NvbBIPCgtFWFBPU0VfSFRUUBAAEhAKDEVYUE9TRV9IVFRQUxABEg4KCk' + 'VYUE9TRV9UQ1AQAhIOCgpFWFBPU0VfVURQEAMSDgoKRVhQT1NFX1RMUxAE'); + +@$core.Deprecated('Use emptyRequestDescriptor instead') +const EmptyRequest$json = { + '1': 'EmptyRequest', +}; + +/// Descriptor for `EmptyRequest`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List emptyRequestDescriptor = + $convert.base64Decode('CgxFbXB0eVJlcXVlc3Q='); + +@$core.Deprecated('Use oSLifecycleRequestDescriptor instead') +const OSLifecycleRequest$json = { + '1': 'OSLifecycleRequest', + '2': [ + { + '1': 'type', + '3': 1, + '4': 1, + '5': 14, + '6': '.daemon.OSLifecycleRequest.CycleType', + '10': 'type' + }, + ], + '4': [OSLifecycleRequest_CycleType$json], +}; + +@$core.Deprecated('Use oSLifecycleRequestDescriptor instead') +const OSLifecycleRequest_CycleType$json = { + '1': 'CycleType', + '2': [ + {'1': 'UNKNOWN', '2': 0}, + {'1': 'SLEEP', '2': 1}, + {'1': 'WAKEUP', '2': 2}, + ], +}; + +/// Descriptor for `OSLifecycleRequest`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List oSLifecycleRequestDescriptor = $convert.base64Decode( + 'ChJPU0xpZmVjeWNsZVJlcXVlc3QSOAoEdHlwZRgBIAEoDjIkLmRhZW1vbi5PU0xpZmVjeWNsZV' + 'JlcXVlc3QuQ3ljbGVUeXBlUgR0eXBlIi8KCUN5Y2xlVHlwZRILCgdVTktOT1dOEAASCQoFU0xF' + 'RVAQARIKCgZXQUtFVVAQAg=='); + +@$core.Deprecated('Use oSLifecycleResponseDescriptor instead') +const OSLifecycleResponse$json = { + '1': 'OSLifecycleResponse', +}; + +/// Descriptor for `OSLifecycleResponse`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List oSLifecycleResponseDescriptor = + $convert.base64Decode('ChNPU0xpZmVjeWNsZVJlc3BvbnNl'); + +@$core.Deprecated('Use loginRequestDescriptor instead') +const LoginRequest$json = { + '1': 'LoginRequest', + '2': [ + {'1': 'setupKey', '3': 1, '4': 1, '5': 9, '10': 'setupKey'}, + { + '1': 'preSharedKey', + '3': 2, + '4': 1, + '5': 9, + '8': {'3': true}, + '10': 'preSharedKey', + }, + {'1': 'managementUrl', '3': 3, '4': 1, '5': 9, '10': 'managementUrl'}, + {'1': 'adminURL', '3': 4, '4': 1, '5': 9, '10': 'adminURL'}, + {'1': 'natExternalIPs', '3': 5, '4': 3, '5': 9, '10': 'natExternalIPs'}, + { + '1': 'cleanNATExternalIPs', + '3': 6, + '4': 1, + '5': 8, + '10': 'cleanNATExternalIPs' + }, + { + '1': 'customDNSAddress', + '3': 7, + '4': 1, + '5': 12, + '10': 'customDNSAddress' + }, + { + '1': 'isUnixDesktopClient', + '3': 8, + '4': 1, + '5': 8, + '10': 'isUnixDesktopClient' + }, + {'1': 'hostname', '3': 9, '4': 1, '5': 9, '10': 'hostname'}, + { + '1': 'rosenpassEnabled', + '3': 10, + '4': 1, + '5': 8, + '9': 0, + '10': 'rosenpassEnabled', + '17': true + }, + { + '1': 'interfaceName', + '3': 11, + '4': 1, + '5': 9, + '9': 1, + '10': 'interfaceName', + '17': true + }, + { + '1': 'wireguardPort', + '3': 12, + '4': 1, + '5': 3, + '9': 2, + '10': 'wireguardPort', + '17': true + }, + { + '1': 'optionalPreSharedKey', + '3': 13, + '4': 1, + '5': 9, + '9': 3, + '10': 'optionalPreSharedKey', + '17': true + }, + { + '1': 'disableAutoConnect', + '3': 14, + '4': 1, + '5': 8, + '9': 4, + '10': 'disableAutoConnect', + '17': true + }, + { + '1': 'serverSSHAllowed', + '3': 15, + '4': 1, + '5': 8, + '9': 5, + '10': 'serverSSHAllowed', + '17': true + }, + { + '1': 'rosenpassPermissive', + '3': 16, + '4': 1, + '5': 8, + '9': 6, + '10': 'rosenpassPermissive', + '17': true + }, + { + '1': 'extraIFaceBlacklist', + '3': 17, + '4': 3, + '5': 9, + '10': 'extraIFaceBlacklist' + }, + { + '1': 'networkMonitor', + '3': 18, + '4': 1, + '5': 8, + '9': 7, + '10': 'networkMonitor', + '17': true + }, + { + '1': 'dnsRouteInterval', + '3': 19, + '4': 1, + '5': 11, + '6': '.google.protobuf.Duration', + '9': 8, + '10': 'dnsRouteInterval', + '17': true + }, + { + '1': 'disable_client_routes', + '3': 20, + '4': 1, + '5': 8, + '9': 9, + '10': 'disableClientRoutes', + '17': true + }, + { + '1': 'disable_server_routes', + '3': 21, + '4': 1, + '5': 8, + '9': 10, + '10': 'disableServerRoutes', + '17': true + }, + { + '1': 'disable_dns', + '3': 22, + '4': 1, + '5': 8, + '9': 11, + '10': 'disableDns', + '17': true + }, + { + '1': 'disable_firewall', + '3': 23, + '4': 1, + '5': 8, + '9': 12, + '10': 'disableFirewall', + '17': true + }, + { + '1': 'block_lan_access', + '3': 24, + '4': 1, + '5': 8, + '9': 13, + '10': 'blockLanAccess', + '17': true + }, + { + '1': 'disable_notifications', + '3': 25, + '4': 1, + '5': 8, + '9': 14, + '10': 'disableNotifications', + '17': true + }, + {'1': 'dns_labels', '3': 26, '4': 3, '5': 9, '10': 'dnsLabels'}, + {'1': 'cleanDNSLabels', '3': 27, '4': 1, '5': 8, '10': 'cleanDNSLabels'}, + { + '1': 'lazyConnectionEnabled', + '3': 28, + '4': 1, + '5': 8, + '9': 15, + '10': 'lazyConnectionEnabled', + '17': true + }, + { + '1': 'block_inbound', + '3': 29, + '4': 1, + '5': 8, + '9': 16, + '10': 'blockInbound', + '17': true + }, + { + '1': 'profileName', + '3': 30, + '4': 1, + '5': 9, + '9': 17, + '10': 'profileName', + '17': true + }, + { + '1': 'username', + '3': 31, + '4': 1, + '5': 9, + '9': 18, + '10': 'username', + '17': true + }, + {'1': 'mtu', '3': 32, '4': 1, '5': 3, '9': 19, '10': 'mtu', '17': true}, + {'1': 'hint', '3': 33, '4': 1, '5': 9, '9': 20, '10': 'hint', '17': true}, + { + '1': 'enableSSHRoot', + '3': 34, + '4': 1, + '5': 8, + '9': 21, + '10': 'enableSSHRoot', + '17': true + }, + { + '1': 'enableSSHSFTP', + '3': 35, + '4': 1, + '5': 8, + '9': 22, + '10': 'enableSSHSFTP', + '17': true + }, + { + '1': 'enableSSHLocalPortForwarding', + '3': 36, + '4': 1, + '5': 8, + '9': 23, + '10': 'enableSSHLocalPortForwarding', + '17': true + }, + { + '1': 'enableSSHRemotePortForwarding', + '3': 37, + '4': 1, + '5': 8, + '9': 24, + '10': 'enableSSHRemotePortForwarding', + '17': true + }, + { + '1': 'disableSSHAuth', + '3': 38, + '4': 1, + '5': 8, + '9': 25, + '10': 'disableSSHAuth', + '17': true + }, + { + '1': 'sshJWTCacheTTL', + '3': 39, + '4': 1, + '5': 5, + '9': 26, + '10': 'sshJWTCacheTTL', + '17': true + }, + ], + '8': [ + {'1': '_rosenpassEnabled'}, + {'1': '_interfaceName'}, + {'1': '_wireguardPort'}, + {'1': '_optionalPreSharedKey'}, + {'1': '_disableAutoConnect'}, + {'1': '_serverSSHAllowed'}, + {'1': '_rosenpassPermissive'}, + {'1': '_networkMonitor'}, + {'1': '_dnsRouteInterval'}, + {'1': '_disable_client_routes'}, + {'1': '_disable_server_routes'}, + {'1': '_disable_dns'}, + {'1': '_disable_firewall'}, + {'1': '_block_lan_access'}, + {'1': '_disable_notifications'}, + {'1': '_lazyConnectionEnabled'}, + {'1': '_block_inbound'}, + {'1': '_profileName'}, + {'1': '_username'}, + {'1': '_mtu'}, + {'1': '_hint'}, + {'1': '_enableSSHRoot'}, + {'1': '_enableSSHSFTP'}, + {'1': '_enableSSHLocalPortForwarding'}, + {'1': '_enableSSHRemotePortForwarding'}, + {'1': '_disableSSHAuth'}, + {'1': '_sshJWTCacheTTL'}, + ], +}; + +/// Descriptor for `LoginRequest`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List loginRequestDescriptor = $convert.base64Decode( + 'CgxMb2dpblJlcXVlc3QSGgoIc2V0dXBLZXkYASABKAlSCHNldHVwS2V5EiYKDHByZVNoYXJlZE' + 'tleRgCIAEoCUICGAFSDHByZVNoYXJlZEtleRIkCg1tYW5hZ2VtZW50VXJsGAMgASgJUg1tYW5h' + 'Z2VtZW50VXJsEhoKCGFkbWluVVJMGAQgASgJUghhZG1pblVSTBImCg5uYXRFeHRlcm5hbElQcx' + 'gFIAMoCVIObmF0RXh0ZXJuYWxJUHMSMAoTY2xlYW5OQVRFeHRlcm5hbElQcxgGIAEoCFITY2xl' + 'YW5OQVRFeHRlcm5hbElQcxIqChBjdXN0b21ETlNBZGRyZXNzGAcgASgMUhBjdXN0b21ETlNBZG' + 'RyZXNzEjAKE2lzVW5peERlc2t0b3BDbGllbnQYCCABKAhSE2lzVW5peERlc2t0b3BDbGllbnQS' + 'GgoIaG9zdG5hbWUYCSABKAlSCGhvc3RuYW1lEi8KEHJvc2VucGFzc0VuYWJsZWQYCiABKAhIAF' + 'IQcm9zZW5wYXNzRW5hYmxlZIgBARIpCg1pbnRlcmZhY2VOYW1lGAsgASgJSAFSDWludGVyZmFj' + 'ZU5hbWWIAQESKQoNd2lyZWd1YXJkUG9ydBgMIAEoA0gCUg13aXJlZ3VhcmRQb3J0iAEBEjcKFG' + '9wdGlvbmFsUHJlU2hhcmVkS2V5GA0gASgJSANSFG9wdGlvbmFsUHJlU2hhcmVkS2V5iAEBEjMK' + 'EmRpc2FibGVBdXRvQ29ubmVjdBgOIAEoCEgEUhJkaXNhYmxlQXV0b0Nvbm5lY3SIAQESLwoQc2' + 'VydmVyU1NIQWxsb3dlZBgPIAEoCEgFUhBzZXJ2ZXJTU0hBbGxvd2VkiAEBEjUKE3Jvc2VucGFz' + 'c1Blcm1pc3NpdmUYECABKAhIBlITcm9zZW5wYXNzUGVybWlzc2l2ZYgBARIwChNleHRyYUlGYW' + 'NlQmxhY2tsaXN0GBEgAygJUhNleHRyYUlGYWNlQmxhY2tsaXN0EisKDm5ldHdvcmtNb25pdG9y' + 'GBIgASgISAdSDm5ldHdvcmtNb25pdG9yiAEBEkoKEGRuc1JvdXRlSW50ZXJ2YWwYEyABKAsyGS' + '5nb29nbGUucHJvdG9idWYuRHVyYXRpb25ICFIQZG5zUm91dGVJbnRlcnZhbIgBARI3ChVkaXNh' + 'YmxlX2NsaWVudF9yb3V0ZXMYFCABKAhICVITZGlzYWJsZUNsaWVudFJvdXRlc4gBARI3ChVkaX' + 'NhYmxlX3NlcnZlcl9yb3V0ZXMYFSABKAhIClITZGlzYWJsZVNlcnZlclJvdXRlc4gBARIkCgtk' + 'aXNhYmxlX2RucxgWIAEoCEgLUgpkaXNhYmxlRG5ziAEBEi4KEGRpc2FibGVfZmlyZXdhbGwYFy' + 'ABKAhIDFIPZGlzYWJsZUZpcmV3YWxsiAEBEi0KEGJsb2NrX2xhbl9hY2Nlc3MYGCABKAhIDVIO' + 'YmxvY2tMYW5BY2Nlc3OIAQESOAoVZGlzYWJsZV9ub3RpZmljYXRpb25zGBkgASgISA5SFGRpc2' + 'FibGVOb3RpZmljYXRpb25ziAEBEh0KCmRuc19sYWJlbHMYGiADKAlSCWRuc0xhYmVscxImCg5j' + 'bGVhbkROU0xhYmVscxgbIAEoCFIOY2xlYW5ETlNMYWJlbHMSOQoVbGF6eUNvbm5lY3Rpb25Fbm' + 'FibGVkGBwgASgISA9SFWxhenlDb25uZWN0aW9uRW5hYmxlZIgBARIoCg1ibG9ja19pbmJvdW5k' + 'GB0gASgISBBSDGJsb2NrSW5ib3VuZIgBARIlCgtwcm9maWxlTmFtZRgeIAEoCUgRUgtwcm9maW' + 'xlTmFtZYgBARIfCgh1c2VybmFtZRgfIAEoCUgSUgh1c2VybmFtZYgBARIVCgNtdHUYICABKANI' + 'E1IDbXR1iAEBEhcKBGhpbnQYISABKAlIFFIEaGludIgBARIpCg1lbmFibGVTU0hSb290GCIgAS' + 'gISBVSDWVuYWJsZVNTSFJvb3SIAQESKQoNZW5hYmxlU1NIU0ZUUBgjIAEoCEgWUg1lbmFibGVT' + 'U0hTRlRQiAEBEkcKHGVuYWJsZVNTSExvY2FsUG9ydEZvcndhcmRpbmcYJCABKAhIF1IcZW5hYm' + 'xlU1NITG9jYWxQb3J0Rm9yd2FyZGluZ4gBARJJCh1lbmFibGVTU0hSZW1vdGVQb3J0Rm9yd2Fy' + 'ZGluZxglIAEoCEgYUh1lbmFibGVTU0hSZW1vdGVQb3J0Rm9yd2FyZGluZ4gBARIrCg5kaXNhYm' + 'xlU1NIQXV0aBgmIAEoCEgZUg5kaXNhYmxlU1NIQXV0aIgBARIrCg5zc2hKV1RDYWNoZVRUTBgn' + 'IAEoBUgaUg5zc2hKV1RDYWNoZVRUTIgBAUITChFfcm9zZW5wYXNzRW5hYmxlZEIQCg5faW50ZX' + 'JmYWNlTmFtZUIQCg5fd2lyZWd1YXJkUG9ydEIXChVfb3B0aW9uYWxQcmVTaGFyZWRLZXlCFQoT' + 'X2Rpc2FibGVBdXRvQ29ubmVjdEITChFfc2VydmVyU1NIQWxsb3dlZEIWChRfcm9zZW5wYXNzUG' + 'VybWlzc2l2ZUIRCg9fbmV0d29ya01vbml0b3JCEwoRX2Ruc1JvdXRlSW50ZXJ2YWxCGAoWX2Rp' + 'c2FibGVfY2xpZW50X3JvdXRlc0IYChZfZGlzYWJsZV9zZXJ2ZXJfcm91dGVzQg4KDF9kaXNhYm' + 'xlX2Ruc0ITChFfZGlzYWJsZV9maXJld2FsbEITChFfYmxvY2tfbGFuX2FjY2Vzc0IYChZfZGlz' + 'YWJsZV9ub3RpZmljYXRpb25zQhgKFl9sYXp5Q29ubmVjdGlvbkVuYWJsZWRCEAoOX2Jsb2NrX2' + 'luYm91bmRCDgoMX3Byb2ZpbGVOYW1lQgsKCV91c2VybmFtZUIGCgRfbXR1QgcKBV9oaW50QhAK' + 'Dl9lbmFibGVTU0hSb290QhAKDl9lbmFibGVTU0hTRlRQQh8KHV9lbmFibGVTU0hMb2NhbFBvcn' + 'RGb3J3YXJkaW5nQiAKHl9lbmFibGVTU0hSZW1vdGVQb3J0Rm9yd2FyZGluZ0IRCg9fZGlzYWJs' + 'ZVNTSEF1dGhCEQoPX3NzaEpXVENhY2hlVFRM'); + +@$core.Deprecated('Use loginResponseDescriptor instead') +const LoginResponse$json = { + '1': 'LoginResponse', + '2': [ + {'1': 'needsSSOLogin', '3': 1, '4': 1, '5': 8, '10': 'needsSSOLogin'}, + {'1': 'userCode', '3': 2, '4': 1, '5': 9, '10': 'userCode'}, + {'1': 'verificationURI', '3': 3, '4': 1, '5': 9, '10': 'verificationURI'}, + { + '1': 'verificationURIComplete', + '3': 4, + '4': 1, + '5': 9, + '10': 'verificationURIComplete' + }, + ], +}; + +/// Descriptor for `LoginResponse`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List loginResponseDescriptor = $convert.base64Decode( + 'Cg1Mb2dpblJlc3BvbnNlEiQKDW5lZWRzU1NPTG9naW4YASABKAhSDW5lZWRzU1NPTG9naW4SGg' + 'oIdXNlckNvZGUYAiABKAlSCHVzZXJDb2RlEigKD3ZlcmlmaWNhdGlvblVSSRgDIAEoCVIPdmVy' + 'aWZpY2F0aW9uVVJJEjgKF3ZlcmlmaWNhdGlvblVSSUNvbXBsZXRlGAQgASgJUhd2ZXJpZmljYX' + 'Rpb25VUklDb21wbGV0ZQ=='); + +@$core.Deprecated('Use waitSSOLoginRequestDescriptor instead') +const WaitSSOLoginRequest$json = { + '1': 'WaitSSOLoginRequest', + '2': [ + {'1': 'userCode', '3': 1, '4': 1, '5': 9, '10': 'userCode'}, + {'1': 'hostname', '3': 2, '4': 1, '5': 9, '10': 'hostname'}, + ], +}; + +/// Descriptor for `WaitSSOLoginRequest`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List waitSSOLoginRequestDescriptor = $convert.base64Decode( + 'ChNXYWl0U1NPTG9naW5SZXF1ZXN0EhoKCHVzZXJDb2RlGAEgASgJUgh1c2VyQ29kZRIaCghob3' + 'N0bmFtZRgCIAEoCVIIaG9zdG5hbWU='); + +@$core.Deprecated('Use waitSSOLoginResponseDescriptor instead') +const WaitSSOLoginResponse$json = { + '1': 'WaitSSOLoginResponse', + '2': [ + {'1': 'email', '3': 1, '4': 1, '5': 9, '10': 'email'}, + ], +}; + +/// Descriptor for `WaitSSOLoginResponse`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List waitSSOLoginResponseDescriptor = + $convert.base64Decode( + 'ChRXYWl0U1NPTG9naW5SZXNwb25zZRIUCgVlbWFpbBgBIAEoCVIFZW1haWw='); + +@$core.Deprecated('Use upRequestDescriptor instead') +const UpRequest$json = { + '1': 'UpRequest', + '2': [ + { + '1': 'profileName', + '3': 1, + '4': 1, + '5': 9, + '9': 0, + '10': 'profileName', + '17': true + }, + { + '1': 'username', + '3': 2, + '4': 1, + '5': 9, + '9': 1, + '10': 'username', + '17': true + }, + ], + '8': [ + {'1': '_profileName'}, + {'1': '_username'}, + ], + '9': [ + {'1': 3, '2': 4}, + ], +}; + +/// Descriptor for `UpRequest`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List upRequestDescriptor = $convert.base64Decode( + 'CglVcFJlcXVlc3QSJQoLcHJvZmlsZU5hbWUYASABKAlIAFILcHJvZmlsZU5hbWWIAQESHwoIdX' + 'Nlcm5hbWUYAiABKAlIAVIIdXNlcm5hbWWIAQFCDgoMX3Byb2ZpbGVOYW1lQgsKCV91c2VybmFt' + 'ZUoECAMQBA=='); + +@$core.Deprecated('Use upResponseDescriptor instead') +const UpResponse$json = { + '1': 'UpResponse', +}; + +/// Descriptor for `UpResponse`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List upResponseDescriptor = + $convert.base64Decode('CgpVcFJlc3BvbnNl'); + +@$core.Deprecated('Use statusRequestDescriptor instead') +const StatusRequest$json = { + '1': 'StatusRequest', + '2': [ + { + '1': 'getFullPeerStatus', + '3': 1, + '4': 1, + '5': 8, + '10': 'getFullPeerStatus' + }, + {'1': 'shouldRunProbes', '3': 2, '4': 1, '5': 8, '10': 'shouldRunProbes'}, + { + '1': 'waitForReady', + '3': 3, + '4': 1, + '5': 8, + '9': 0, + '10': 'waitForReady', + '17': true + }, + ], + '8': [ + {'1': '_waitForReady'}, + ], +}; + +/// Descriptor for `StatusRequest`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List statusRequestDescriptor = $convert.base64Decode( + 'Cg1TdGF0dXNSZXF1ZXN0EiwKEWdldEZ1bGxQZWVyU3RhdHVzGAEgASgIUhFnZXRGdWxsUGVlcl' + 'N0YXR1cxIoCg9zaG91bGRSdW5Qcm9iZXMYAiABKAhSD3Nob3VsZFJ1blByb2JlcxInCgx3YWl0' + 'Rm9yUmVhZHkYAyABKAhIAFIMd2FpdEZvclJlYWR5iAEBQg8KDV93YWl0Rm9yUmVhZHk='); + +@$core.Deprecated('Use statusResponseDescriptor instead') +const StatusResponse$json = { + '1': 'StatusResponse', + '2': [ + {'1': 'status', '3': 1, '4': 1, '5': 9, '10': 'status'}, + { + '1': 'fullStatus', + '3': 2, + '4': 1, + '5': 11, + '6': '.daemon.FullStatus', + '10': 'fullStatus' + }, + {'1': 'daemonVersion', '3': 3, '4': 1, '5': 9, '10': 'daemonVersion'}, + ], +}; + +/// Descriptor for `StatusResponse`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List statusResponseDescriptor = $convert.base64Decode( + 'Cg5TdGF0dXNSZXNwb25zZRIWCgZzdGF0dXMYASABKAlSBnN0YXR1cxIyCgpmdWxsU3RhdHVzGA' + 'IgASgLMhIuZGFlbW9uLkZ1bGxTdGF0dXNSCmZ1bGxTdGF0dXMSJAoNZGFlbW9uVmVyc2lvbhgD' + 'IAEoCVINZGFlbW9uVmVyc2lvbg=='); + +@$core.Deprecated('Use downRequestDescriptor instead') +const DownRequest$json = { + '1': 'DownRequest', +}; + +/// Descriptor for `DownRequest`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List downRequestDescriptor = + $convert.base64Decode('CgtEb3duUmVxdWVzdA=='); + +@$core.Deprecated('Use downResponseDescriptor instead') +const DownResponse$json = { + '1': 'DownResponse', +}; + +/// Descriptor for `DownResponse`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List downResponseDescriptor = + $convert.base64Decode('CgxEb3duUmVzcG9uc2U='); + +@$core.Deprecated('Use getConfigRequestDescriptor instead') +const GetConfigRequest$json = { + '1': 'GetConfigRequest', + '2': [ + {'1': 'profileName', '3': 1, '4': 1, '5': 9, '10': 'profileName'}, + {'1': 'username', '3': 2, '4': 1, '5': 9, '10': 'username'}, + ], +}; + +/// Descriptor for `GetConfigRequest`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List getConfigRequestDescriptor = $convert.base64Decode( + 'ChBHZXRDb25maWdSZXF1ZXN0EiAKC3Byb2ZpbGVOYW1lGAEgASgJUgtwcm9maWxlTmFtZRIaCg' + 'h1c2VybmFtZRgCIAEoCVIIdXNlcm5hbWU='); + +@$core.Deprecated('Use getConfigResponseDescriptor instead') +const GetConfigResponse$json = { + '1': 'GetConfigResponse', + '2': [ + {'1': 'managementUrl', '3': 1, '4': 1, '5': 9, '10': 'managementUrl'}, + {'1': 'configFile', '3': 2, '4': 1, '5': 9, '10': 'configFile'}, + {'1': 'logFile', '3': 3, '4': 1, '5': 9, '10': 'logFile'}, + {'1': 'preSharedKey', '3': 4, '4': 1, '5': 9, '10': 'preSharedKey'}, + {'1': 'adminURL', '3': 5, '4': 1, '5': 9, '10': 'adminURL'}, + {'1': 'interfaceName', '3': 6, '4': 1, '5': 9, '10': 'interfaceName'}, + {'1': 'wireguardPort', '3': 7, '4': 1, '5': 3, '10': 'wireguardPort'}, + {'1': 'mtu', '3': 8, '4': 1, '5': 3, '10': 'mtu'}, + { + '1': 'disableAutoConnect', + '3': 9, + '4': 1, + '5': 8, + '10': 'disableAutoConnect' + }, + { + '1': 'serverSSHAllowed', + '3': 10, + '4': 1, + '5': 8, + '10': 'serverSSHAllowed' + }, + { + '1': 'rosenpassEnabled', + '3': 11, + '4': 1, + '5': 8, + '10': 'rosenpassEnabled' + }, + { + '1': 'rosenpassPermissive', + '3': 12, + '4': 1, + '5': 8, + '10': 'rosenpassPermissive' + }, + { + '1': 'disable_notifications', + '3': 13, + '4': 1, + '5': 8, + '10': 'disableNotifications' + }, + { + '1': 'lazyConnectionEnabled', + '3': 14, + '4': 1, + '5': 8, + '10': 'lazyConnectionEnabled' + }, + {'1': 'blockInbound', '3': 15, '4': 1, '5': 8, '10': 'blockInbound'}, + {'1': 'networkMonitor', '3': 16, '4': 1, '5': 8, '10': 'networkMonitor'}, + {'1': 'disable_dns', '3': 17, '4': 1, '5': 8, '10': 'disableDns'}, + { + '1': 'disable_client_routes', + '3': 18, + '4': 1, + '5': 8, + '10': 'disableClientRoutes' + }, + { + '1': 'disable_server_routes', + '3': 19, + '4': 1, + '5': 8, + '10': 'disableServerRoutes' + }, + {'1': 'block_lan_access', '3': 20, '4': 1, '5': 8, '10': 'blockLanAccess'}, + {'1': 'enableSSHRoot', '3': 21, '4': 1, '5': 8, '10': 'enableSSHRoot'}, + {'1': 'enableSSHSFTP', '3': 24, '4': 1, '5': 8, '10': 'enableSSHSFTP'}, + { + '1': 'enableSSHLocalPortForwarding', + '3': 22, + '4': 1, + '5': 8, + '10': 'enableSSHLocalPortForwarding' + }, + { + '1': 'enableSSHRemotePortForwarding', + '3': 23, + '4': 1, + '5': 8, + '10': 'enableSSHRemotePortForwarding' + }, + {'1': 'disableSSHAuth', '3': 25, '4': 1, '5': 8, '10': 'disableSSHAuth'}, + {'1': 'sshJWTCacheTTL', '3': 26, '4': 1, '5': 5, '10': 'sshJWTCacheTTL'}, + ], +}; + +/// Descriptor for `GetConfigResponse`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List getConfigResponseDescriptor = $convert.base64Decode( + 'ChFHZXRDb25maWdSZXNwb25zZRIkCg1tYW5hZ2VtZW50VXJsGAEgASgJUg1tYW5hZ2VtZW50VX' + 'JsEh4KCmNvbmZpZ0ZpbGUYAiABKAlSCmNvbmZpZ0ZpbGUSGAoHbG9nRmlsZRgDIAEoCVIHbG9n' + 'RmlsZRIiCgxwcmVTaGFyZWRLZXkYBCABKAlSDHByZVNoYXJlZEtleRIaCghhZG1pblVSTBgFIA' + 'EoCVIIYWRtaW5VUkwSJAoNaW50ZXJmYWNlTmFtZRgGIAEoCVINaW50ZXJmYWNlTmFtZRIkCg13' + 'aXJlZ3VhcmRQb3J0GAcgASgDUg13aXJlZ3VhcmRQb3J0EhAKA210dRgIIAEoA1IDbXR1Ei4KEm' + 'Rpc2FibGVBdXRvQ29ubmVjdBgJIAEoCFISZGlzYWJsZUF1dG9Db25uZWN0EioKEHNlcnZlclNT' + 'SEFsbG93ZWQYCiABKAhSEHNlcnZlclNTSEFsbG93ZWQSKgoQcm9zZW5wYXNzRW5hYmxlZBgLIA' + 'EoCFIQcm9zZW5wYXNzRW5hYmxlZBIwChNyb3NlbnBhc3NQZXJtaXNzaXZlGAwgASgIUhNyb3Nl' + 'bnBhc3NQZXJtaXNzaXZlEjMKFWRpc2FibGVfbm90aWZpY2F0aW9ucxgNIAEoCFIUZGlzYWJsZU' + '5vdGlmaWNhdGlvbnMSNAoVbGF6eUNvbm5lY3Rpb25FbmFibGVkGA4gASgIUhVsYXp5Q29ubmVj' + 'dGlvbkVuYWJsZWQSIgoMYmxvY2tJbmJvdW5kGA8gASgIUgxibG9ja0luYm91bmQSJgoObmV0d2' + '9ya01vbml0b3IYECABKAhSDm5ldHdvcmtNb25pdG9yEh8KC2Rpc2FibGVfZG5zGBEgASgIUgpk' + 'aXNhYmxlRG5zEjIKFWRpc2FibGVfY2xpZW50X3JvdXRlcxgSIAEoCFITZGlzYWJsZUNsaWVudF' + 'JvdXRlcxIyChVkaXNhYmxlX3NlcnZlcl9yb3V0ZXMYEyABKAhSE2Rpc2FibGVTZXJ2ZXJSb3V0' + 'ZXMSKAoQYmxvY2tfbGFuX2FjY2VzcxgUIAEoCFIOYmxvY2tMYW5BY2Nlc3MSJAoNZW5hYmxlU1' + 'NIUm9vdBgVIAEoCFINZW5hYmxlU1NIUm9vdBIkCg1lbmFibGVTU0hTRlRQGBggASgIUg1lbmFi' + 'bGVTU0hTRlRQEkIKHGVuYWJsZVNTSExvY2FsUG9ydEZvcndhcmRpbmcYFiABKAhSHGVuYWJsZV' + 'NTSExvY2FsUG9ydEZvcndhcmRpbmcSRAodZW5hYmxlU1NIUmVtb3RlUG9ydEZvcndhcmRpbmcY' + 'FyABKAhSHWVuYWJsZVNTSFJlbW90ZVBvcnRGb3J3YXJkaW5nEiYKDmRpc2FibGVTU0hBdXRoGB' + 'kgASgIUg5kaXNhYmxlU1NIQXV0aBImCg5zc2hKV1RDYWNoZVRUTBgaIAEoBVIOc3NoSldUQ2Fj' + 'aGVUVEw='); + +@$core.Deprecated('Use peerStateDescriptor instead') +const PeerState$json = { + '1': 'PeerState', + '2': [ + {'1': 'IP', '3': 1, '4': 1, '5': 9, '10': 'IP'}, + {'1': 'pubKey', '3': 2, '4': 1, '5': 9, '10': 'pubKey'}, + {'1': 'connStatus', '3': 3, '4': 1, '5': 9, '10': 'connStatus'}, + { + '1': 'connStatusUpdate', + '3': 4, + '4': 1, + '5': 11, + '6': '.google.protobuf.Timestamp', + '10': 'connStatusUpdate' + }, + {'1': 'relayed', '3': 5, '4': 1, '5': 8, '10': 'relayed'}, + { + '1': 'localIceCandidateType', + '3': 7, + '4': 1, + '5': 9, + '10': 'localIceCandidateType' + }, + { + '1': 'remoteIceCandidateType', + '3': 8, + '4': 1, + '5': 9, + '10': 'remoteIceCandidateType' + }, + {'1': 'fqdn', '3': 9, '4': 1, '5': 9, '10': 'fqdn'}, + { + '1': 'localIceCandidateEndpoint', + '3': 10, + '4': 1, + '5': 9, + '10': 'localIceCandidateEndpoint' + }, + { + '1': 'remoteIceCandidateEndpoint', + '3': 11, + '4': 1, + '5': 9, + '10': 'remoteIceCandidateEndpoint' + }, + { + '1': 'lastWireguardHandshake', + '3': 12, + '4': 1, + '5': 11, + '6': '.google.protobuf.Timestamp', + '10': 'lastWireguardHandshake' + }, + {'1': 'bytesRx', '3': 13, '4': 1, '5': 3, '10': 'bytesRx'}, + {'1': 'bytesTx', '3': 14, '4': 1, '5': 3, '10': 'bytesTx'}, + { + '1': 'rosenpassEnabled', + '3': 15, + '4': 1, + '5': 8, + '10': 'rosenpassEnabled' + }, + {'1': 'networks', '3': 16, '4': 3, '5': 9, '10': 'networks'}, + { + '1': 'latency', + '3': 17, + '4': 1, + '5': 11, + '6': '.google.protobuf.Duration', + '10': 'latency' + }, + {'1': 'relayAddress', '3': 18, '4': 1, '5': 9, '10': 'relayAddress'}, + {'1': 'sshHostKey', '3': 19, '4': 1, '5': 12, '10': 'sshHostKey'}, + ], +}; + +/// Descriptor for `PeerState`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List peerStateDescriptor = $convert.base64Decode( + 'CglQZWVyU3RhdGUSDgoCSVAYASABKAlSAklQEhYKBnB1YktleRgCIAEoCVIGcHViS2V5Eh4KCm' + 'Nvbm5TdGF0dXMYAyABKAlSCmNvbm5TdGF0dXMSRgoQY29ublN0YXR1c1VwZGF0ZRgEIAEoCzIa' + 'Lmdvb2dsZS5wcm90b2J1Zi5UaW1lc3RhbXBSEGNvbm5TdGF0dXNVcGRhdGUSGAoHcmVsYXllZB' + 'gFIAEoCFIHcmVsYXllZBI0ChVsb2NhbEljZUNhbmRpZGF0ZVR5cGUYByABKAlSFWxvY2FsSWNl' + 'Q2FuZGlkYXRlVHlwZRI2ChZyZW1vdGVJY2VDYW5kaWRhdGVUeXBlGAggASgJUhZyZW1vdGVJY2' + 'VDYW5kaWRhdGVUeXBlEhIKBGZxZG4YCSABKAlSBGZxZG4SPAoZbG9jYWxJY2VDYW5kaWRhdGVF' + 'bmRwb2ludBgKIAEoCVIZbG9jYWxJY2VDYW5kaWRhdGVFbmRwb2ludBI+ChpyZW1vdGVJY2VDYW' + '5kaWRhdGVFbmRwb2ludBgLIAEoCVIacmVtb3RlSWNlQ2FuZGlkYXRlRW5kcG9pbnQSUgoWbGFz' + 'dFdpcmVndWFyZEhhbmRzaGFrZRgMIAEoCzIaLmdvb2dsZS5wcm90b2J1Zi5UaW1lc3RhbXBSFm' + 'xhc3RXaXJlZ3VhcmRIYW5kc2hha2USGAoHYnl0ZXNSeBgNIAEoA1IHYnl0ZXNSeBIYCgdieXRl' + 'c1R4GA4gASgDUgdieXRlc1R4EioKEHJvc2VucGFzc0VuYWJsZWQYDyABKAhSEHJvc2VucGFzc0' + 'VuYWJsZWQSGgoIbmV0d29ya3MYECADKAlSCG5ldHdvcmtzEjMKB2xhdGVuY3kYESABKAsyGS5n' + 'b29nbGUucHJvdG9idWYuRHVyYXRpb25SB2xhdGVuY3kSIgoMcmVsYXlBZGRyZXNzGBIgASgJUg' + 'xyZWxheUFkZHJlc3MSHgoKc3NoSG9zdEtleRgTIAEoDFIKc3NoSG9zdEtleQ=='); + +@$core.Deprecated('Use localPeerStateDescriptor instead') +const LocalPeerState$json = { + '1': 'LocalPeerState', + '2': [ + {'1': 'IP', '3': 1, '4': 1, '5': 9, '10': 'IP'}, + {'1': 'pubKey', '3': 2, '4': 1, '5': 9, '10': 'pubKey'}, + {'1': 'kernelInterface', '3': 3, '4': 1, '5': 8, '10': 'kernelInterface'}, + {'1': 'fqdn', '3': 4, '4': 1, '5': 9, '10': 'fqdn'}, + {'1': 'rosenpassEnabled', '3': 5, '4': 1, '5': 8, '10': 'rosenpassEnabled'}, + { + '1': 'rosenpassPermissive', + '3': 6, + '4': 1, + '5': 8, + '10': 'rosenpassPermissive' + }, + {'1': 'networks', '3': 7, '4': 3, '5': 9, '10': 'networks'}, + ], +}; + +/// Descriptor for `LocalPeerState`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List localPeerStateDescriptor = $convert.base64Decode( + 'Cg5Mb2NhbFBlZXJTdGF0ZRIOCgJJUBgBIAEoCVICSVASFgoGcHViS2V5GAIgASgJUgZwdWJLZX' + 'kSKAoPa2VybmVsSW50ZXJmYWNlGAMgASgIUg9rZXJuZWxJbnRlcmZhY2USEgoEZnFkbhgEIAEo' + 'CVIEZnFkbhIqChByb3NlbnBhc3NFbmFibGVkGAUgASgIUhByb3NlbnBhc3NFbmFibGVkEjAKE3' + 'Jvc2VucGFzc1Blcm1pc3NpdmUYBiABKAhSE3Jvc2VucGFzc1Blcm1pc3NpdmUSGgoIbmV0d29y' + 'a3MYByADKAlSCG5ldHdvcmtz'); + +@$core.Deprecated('Use signalStateDescriptor instead') +const SignalState$json = { + '1': 'SignalState', + '2': [ + {'1': 'URL', '3': 1, '4': 1, '5': 9, '10': 'URL'}, + {'1': 'connected', '3': 2, '4': 1, '5': 8, '10': 'connected'}, + {'1': 'error', '3': 3, '4': 1, '5': 9, '10': 'error'}, + ], +}; + +/// Descriptor for `SignalState`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List signalStateDescriptor = $convert.base64Decode( + 'CgtTaWduYWxTdGF0ZRIQCgNVUkwYASABKAlSA1VSTBIcCgljb25uZWN0ZWQYAiABKAhSCWNvbm' + '5lY3RlZBIUCgVlcnJvchgDIAEoCVIFZXJyb3I='); + +@$core.Deprecated('Use managementStateDescriptor instead') +const ManagementState$json = { + '1': 'ManagementState', + '2': [ + {'1': 'URL', '3': 1, '4': 1, '5': 9, '10': 'URL'}, + {'1': 'connected', '3': 2, '4': 1, '5': 8, '10': 'connected'}, + {'1': 'error', '3': 3, '4': 1, '5': 9, '10': 'error'}, + ], +}; + +/// Descriptor for `ManagementState`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List managementStateDescriptor = $convert.base64Decode( + 'Cg9NYW5hZ2VtZW50U3RhdGUSEAoDVVJMGAEgASgJUgNVUkwSHAoJY29ubmVjdGVkGAIgASgIUg' + 'ljb25uZWN0ZWQSFAoFZXJyb3IYAyABKAlSBWVycm9y'); + +@$core.Deprecated('Use relayStateDescriptor instead') +const RelayState$json = { + '1': 'RelayState', + '2': [ + {'1': 'URI', '3': 1, '4': 1, '5': 9, '10': 'URI'}, + {'1': 'available', '3': 2, '4': 1, '5': 8, '10': 'available'}, + {'1': 'error', '3': 3, '4': 1, '5': 9, '10': 'error'}, + ], +}; + +/// Descriptor for `RelayState`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List relayStateDescriptor = $convert.base64Decode( + 'CgpSZWxheVN0YXRlEhAKA1VSSRgBIAEoCVIDVVJJEhwKCWF2YWlsYWJsZRgCIAEoCFIJYXZhaW' + 'xhYmxlEhQKBWVycm9yGAMgASgJUgVlcnJvcg=='); + +@$core.Deprecated('Use nSGroupStateDescriptor instead') +const NSGroupState$json = { + '1': 'NSGroupState', + '2': [ + {'1': 'servers', '3': 1, '4': 3, '5': 9, '10': 'servers'}, + {'1': 'domains', '3': 2, '4': 3, '5': 9, '10': 'domains'}, + {'1': 'enabled', '3': 3, '4': 1, '5': 8, '10': 'enabled'}, + {'1': 'error', '3': 4, '4': 1, '5': 9, '10': 'error'}, + ], +}; + +/// Descriptor for `NSGroupState`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List nSGroupStateDescriptor = $convert.base64Decode( + 'CgxOU0dyb3VwU3RhdGUSGAoHc2VydmVycxgBIAMoCVIHc2VydmVycxIYCgdkb21haW5zGAIgAy' + 'gJUgdkb21haW5zEhgKB2VuYWJsZWQYAyABKAhSB2VuYWJsZWQSFAoFZXJyb3IYBCABKAlSBWVy' + 'cm9y'); + +@$core.Deprecated('Use sSHSessionInfoDescriptor instead') +const SSHSessionInfo$json = { + '1': 'SSHSessionInfo', + '2': [ + {'1': 'username', '3': 1, '4': 1, '5': 9, '10': 'username'}, + {'1': 'remoteAddress', '3': 2, '4': 1, '5': 9, '10': 'remoteAddress'}, + {'1': 'command', '3': 3, '4': 1, '5': 9, '10': 'command'}, + {'1': 'jwtUsername', '3': 4, '4': 1, '5': 9, '10': 'jwtUsername'}, + {'1': 'portForwards', '3': 5, '4': 3, '5': 9, '10': 'portForwards'}, + ], +}; + +/// Descriptor for `SSHSessionInfo`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List sSHSessionInfoDescriptor = $convert.base64Decode( + 'Cg5TU0hTZXNzaW9uSW5mbxIaCgh1c2VybmFtZRgBIAEoCVIIdXNlcm5hbWUSJAoNcmVtb3RlQW' + 'RkcmVzcxgCIAEoCVINcmVtb3RlQWRkcmVzcxIYCgdjb21tYW5kGAMgASgJUgdjb21tYW5kEiAK' + 'C2p3dFVzZXJuYW1lGAQgASgJUgtqd3RVc2VybmFtZRIiCgxwb3J0Rm9yd2FyZHMYBSADKAlSDH' + 'BvcnRGb3J3YXJkcw=='); + +@$core.Deprecated('Use sSHServerStateDescriptor instead') +const SSHServerState$json = { + '1': 'SSHServerState', + '2': [ + {'1': 'enabled', '3': 1, '4': 1, '5': 8, '10': 'enabled'}, + { + '1': 'sessions', + '3': 2, + '4': 3, + '5': 11, + '6': '.daemon.SSHSessionInfo', + '10': 'sessions' + }, + ], +}; + +/// Descriptor for `SSHServerState`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List sSHServerStateDescriptor = $convert.base64Decode( + 'Cg5TU0hTZXJ2ZXJTdGF0ZRIYCgdlbmFibGVkGAEgASgIUgdlbmFibGVkEjIKCHNlc3Npb25zGA' + 'IgAygLMhYuZGFlbW9uLlNTSFNlc3Npb25JbmZvUghzZXNzaW9ucw=='); + +@$core.Deprecated('Use fullStatusDescriptor instead') +const FullStatus$json = { + '1': 'FullStatus', + '2': [ + { + '1': 'managementState', + '3': 1, + '4': 1, + '5': 11, + '6': '.daemon.ManagementState', + '10': 'managementState' + }, + { + '1': 'signalState', + '3': 2, + '4': 1, + '5': 11, + '6': '.daemon.SignalState', + '10': 'signalState' + }, + { + '1': 'localPeerState', + '3': 3, + '4': 1, + '5': 11, + '6': '.daemon.LocalPeerState', + '10': 'localPeerState' + }, + { + '1': 'peers', + '3': 4, + '4': 3, + '5': 11, + '6': '.daemon.PeerState', + '10': 'peers' + }, + { + '1': 'relays', + '3': 5, + '4': 3, + '5': 11, + '6': '.daemon.RelayState', + '10': 'relays' + }, + { + '1': 'dns_servers', + '3': 6, + '4': 3, + '5': 11, + '6': '.daemon.NSGroupState', + '10': 'dnsServers' + }, + { + '1': 'NumberOfForwardingRules', + '3': 8, + '4': 1, + '5': 5, + '10': 'NumberOfForwardingRules' + }, + { + '1': 'events', + '3': 7, + '4': 3, + '5': 11, + '6': '.daemon.SystemEvent', + '10': 'events' + }, + { + '1': 'lazyConnectionEnabled', + '3': 9, + '4': 1, + '5': 8, + '10': 'lazyConnectionEnabled' + }, + { + '1': 'sshServerState', + '3': 10, + '4': 1, + '5': 11, + '6': '.daemon.SSHServerState', + '10': 'sshServerState' + }, + ], +}; + +/// Descriptor for `FullStatus`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List fullStatusDescriptor = $convert.base64Decode( + 'CgpGdWxsU3RhdHVzEkEKD21hbmFnZW1lbnRTdGF0ZRgBIAEoCzIXLmRhZW1vbi5NYW5hZ2VtZW' + '50U3RhdGVSD21hbmFnZW1lbnRTdGF0ZRI1CgtzaWduYWxTdGF0ZRgCIAEoCzITLmRhZW1vbi5T' + 'aWduYWxTdGF0ZVILc2lnbmFsU3RhdGUSPgoObG9jYWxQZWVyU3RhdGUYAyABKAsyFi5kYWVtb2' + '4uTG9jYWxQZWVyU3RhdGVSDmxvY2FsUGVlclN0YXRlEicKBXBlZXJzGAQgAygLMhEuZGFlbW9u' + 'LlBlZXJTdGF0ZVIFcGVlcnMSKgoGcmVsYXlzGAUgAygLMhIuZGFlbW9uLlJlbGF5U3RhdGVSBn' + 'JlbGF5cxI1CgtkbnNfc2VydmVycxgGIAMoCzIULmRhZW1vbi5OU0dyb3VwU3RhdGVSCmRuc1Nl' + 'cnZlcnMSOAoXTnVtYmVyT2ZGb3J3YXJkaW5nUnVsZXMYCCABKAVSF051bWJlck9mRm9yd2FyZG' + 'luZ1J1bGVzEisKBmV2ZW50cxgHIAMoCzITLmRhZW1vbi5TeXN0ZW1FdmVudFIGZXZlbnRzEjQK' + 'FWxhenlDb25uZWN0aW9uRW5hYmxlZBgJIAEoCFIVbGF6eUNvbm5lY3Rpb25FbmFibGVkEj4KDn' + 'NzaFNlcnZlclN0YXRlGAogASgLMhYuZGFlbW9uLlNTSFNlcnZlclN0YXRlUg5zc2hTZXJ2ZXJT' + 'dGF0ZQ=='); + +@$core.Deprecated('Use listNetworksRequestDescriptor instead') +const ListNetworksRequest$json = { + '1': 'ListNetworksRequest', +}; + +/// Descriptor for `ListNetworksRequest`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List listNetworksRequestDescriptor = + $convert.base64Decode('ChNMaXN0TmV0d29ya3NSZXF1ZXN0'); + +@$core.Deprecated('Use listNetworksResponseDescriptor instead') +const ListNetworksResponse$json = { + '1': 'ListNetworksResponse', + '2': [ + { + '1': 'routes', + '3': 1, + '4': 3, + '5': 11, + '6': '.daemon.Network', + '10': 'routes' + }, + ], +}; + +/// Descriptor for `ListNetworksResponse`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List listNetworksResponseDescriptor = $convert.base64Decode( + 'ChRMaXN0TmV0d29ya3NSZXNwb25zZRInCgZyb3V0ZXMYASADKAsyDy5kYWVtb24uTmV0d29ya1' + 'IGcm91dGVz'); + +@$core.Deprecated('Use selectNetworksRequestDescriptor instead') +const SelectNetworksRequest$json = { + '1': 'SelectNetworksRequest', + '2': [ + {'1': 'networkIDs', '3': 1, '4': 3, '5': 9, '10': 'networkIDs'}, + {'1': 'append', '3': 2, '4': 1, '5': 8, '10': 'append'}, + {'1': 'all', '3': 3, '4': 1, '5': 8, '10': 'all'}, + ], +}; + +/// Descriptor for `SelectNetworksRequest`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List selectNetworksRequestDescriptor = $convert.base64Decode( + 'ChVTZWxlY3ROZXR3b3Jrc1JlcXVlc3QSHgoKbmV0d29ya0lEcxgBIAMoCVIKbmV0d29ya0lEcx' + 'IWCgZhcHBlbmQYAiABKAhSBmFwcGVuZBIQCgNhbGwYAyABKAhSA2FsbA=='); + +@$core.Deprecated('Use selectNetworksResponseDescriptor instead') +const SelectNetworksResponse$json = { + '1': 'SelectNetworksResponse', +}; + +/// Descriptor for `SelectNetworksResponse`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List selectNetworksResponseDescriptor = + $convert.base64Decode('ChZTZWxlY3ROZXR3b3Jrc1Jlc3BvbnNl'); + +@$core.Deprecated('Use iPListDescriptor instead') +const IPList$json = { + '1': 'IPList', + '2': [ + {'1': 'ips', '3': 1, '4': 3, '5': 9, '10': 'ips'}, + ], +}; + +/// Descriptor for `IPList`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List iPListDescriptor = + $convert.base64Decode('CgZJUExpc3QSEAoDaXBzGAEgAygJUgNpcHM='); + +@$core.Deprecated('Use networkDescriptor instead') +const Network$json = { + '1': 'Network', + '2': [ + {'1': 'ID', '3': 1, '4': 1, '5': 9, '10': 'ID'}, + {'1': 'range', '3': 2, '4': 1, '5': 9, '10': 'range'}, + {'1': 'selected', '3': 3, '4': 1, '5': 8, '10': 'selected'}, + {'1': 'domains', '3': 4, '4': 3, '5': 9, '10': 'domains'}, + { + '1': 'resolvedIPs', + '3': 5, + '4': 3, + '5': 11, + '6': '.daemon.Network.ResolvedIPsEntry', + '10': 'resolvedIPs' + }, + ], + '3': [Network_ResolvedIPsEntry$json], +}; + +@$core.Deprecated('Use networkDescriptor instead') +const Network_ResolvedIPsEntry$json = { + '1': 'ResolvedIPsEntry', + '2': [ + {'1': 'key', '3': 1, '4': 1, '5': 9, '10': 'key'}, + { + '1': 'value', + '3': 2, + '4': 1, + '5': 11, + '6': '.daemon.IPList', + '10': 'value' + }, + ], + '7': {'7': true}, +}; + +/// Descriptor for `Network`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List networkDescriptor = $convert.base64Decode( + 'CgdOZXR3b3JrEg4KAklEGAEgASgJUgJJRBIUCgVyYW5nZRgCIAEoCVIFcmFuZ2USGgoIc2VsZW' + 'N0ZWQYAyABKAhSCHNlbGVjdGVkEhgKB2RvbWFpbnMYBCADKAlSB2RvbWFpbnMSQgoLcmVzb2x2' + 'ZWRJUHMYBSADKAsyIC5kYWVtb24uTmV0d29yay5SZXNvbHZlZElQc0VudHJ5UgtyZXNvbHZlZE' + 'lQcxpOChBSZXNvbHZlZElQc0VudHJ5EhAKA2tleRgBIAEoCVIDa2V5EiQKBXZhbHVlGAIgASgL' + 'Mg4uZGFlbW9uLklQTGlzdFIFdmFsdWU6AjgB'); + +@$core.Deprecated('Use portInfoDescriptor instead') +const PortInfo$json = { + '1': 'PortInfo', + '2': [ + {'1': 'port', '3': 1, '4': 1, '5': 13, '9': 0, '10': 'port'}, + { + '1': 'range', + '3': 2, + '4': 1, + '5': 11, + '6': '.daemon.PortInfo.Range', + '9': 0, + '10': 'range' + }, + ], + '3': [PortInfo_Range$json], + '8': [ + {'1': 'portSelection'}, + ], +}; + +@$core.Deprecated('Use portInfoDescriptor instead') +const PortInfo_Range$json = { + '1': 'Range', + '2': [ + {'1': 'start', '3': 1, '4': 1, '5': 13, '10': 'start'}, + {'1': 'end', '3': 2, '4': 1, '5': 13, '10': 'end'}, + ], +}; + +/// Descriptor for `PortInfo`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List portInfoDescriptor = $convert.base64Decode( + 'CghQb3J0SW5mbxIUCgRwb3J0GAEgASgNSABSBHBvcnQSLgoFcmFuZ2UYAiABKAsyFi5kYWVtb2' + '4uUG9ydEluZm8uUmFuZ2VIAFIFcmFuZ2UaLwoFUmFuZ2USFAoFc3RhcnQYASABKA1SBXN0YXJ0' + 'EhAKA2VuZBgCIAEoDVIDZW5kQg8KDXBvcnRTZWxlY3Rpb24='); + +@$core.Deprecated('Use forwardingRuleDescriptor instead') +const ForwardingRule$json = { + '1': 'ForwardingRule', + '2': [ + {'1': 'protocol', '3': 1, '4': 1, '5': 9, '10': 'protocol'}, + { + '1': 'destinationPort', + '3': 2, + '4': 1, + '5': 11, + '6': '.daemon.PortInfo', + '10': 'destinationPort' + }, + { + '1': 'translatedAddress', + '3': 3, + '4': 1, + '5': 9, + '10': 'translatedAddress' + }, + { + '1': 'translatedHostname', + '3': 4, + '4': 1, + '5': 9, + '10': 'translatedHostname' + }, + { + '1': 'translatedPort', + '3': 5, + '4': 1, + '5': 11, + '6': '.daemon.PortInfo', + '10': 'translatedPort' + }, + ], +}; + +/// Descriptor for `ForwardingRule`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List forwardingRuleDescriptor = $convert.base64Decode( + 'Cg5Gb3J3YXJkaW5nUnVsZRIaCghwcm90b2NvbBgBIAEoCVIIcHJvdG9jb2wSOgoPZGVzdGluYX' + 'Rpb25Qb3J0GAIgASgLMhAuZGFlbW9uLlBvcnRJbmZvUg9kZXN0aW5hdGlvblBvcnQSLAoRdHJh' + 'bnNsYXRlZEFkZHJlc3MYAyABKAlSEXRyYW5zbGF0ZWRBZGRyZXNzEi4KEnRyYW5zbGF0ZWRIb3' + 'N0bmFtZRgEIAEoCVISdHJhbnNsYXRlZEhvc3RuYW1lEjgKDnRyYW5zbGF0ZWRQb3J0GAUgASgL' + 'MhAuZGFlbW9uLlBvcnRJbmZvUg50cmFuc2xhdGVkUG9ydA=='); + +@$core.Deprecated('Use forwardingRulesResponseDescriptor instead') +const ForwardingRulesResponse$json = { + '1': 'ForwardingRulesResponse', + '2': [ + { + '1': 'rules', + '3': 1, + '4': 3, + '5': 11, + '6': '.daemon.ForwardingRule', + '10': 'rules' + }, + ], +}; + +/// Descriptor for `ForwardingRulesResponse`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List forwardingRulesResponseDescriptor = + $convert.base64Decode( + 'ChdGb3J3YXJkaW5nUnVsZXNSZXNwb25zZRIsCgVydWxlcxgBIAMoCzIWLmRhZW1vbi5Gb3J3YX' + 'JkaW5nUnVsZVIFcnVsZXM='); + +@$core.Deprecated('Use debugBundleRequestDescriptor instead') +const DebugBundleRequest$json = { + '1': 'DebugBundleRequest', + '2': [ + {'1': 'anonymize', '3': 1, '4': 1, '5': 8, '10': 'anonymize'}, + {'1': 'systemInfo', '3': 3, '4': 1, '5': 8, '10': 'systemInfo'}, + {'1': 'uploadURL', '3': 4, '4': 1, '5': 9, '10': 'uploadURL'}, + {'1': 'logFileCount', '3': 5, '4': 1, '5': 13, '10': 'logFileCount'}, + ], +}; + +/// Descriptor for `DebugBundleRequest`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List debugBundleRequestDescriptor = $convert.base64Decode( + 'ChJEZWJ1Z0J1bmRsZVJlcXVlc3QSHAoJYW5vbnltaXplGAEgASgIUglhbm9ueW1pemUSHgoKc3' + 'lzdGVtSW5mbxgDIAEoCFIKc3lzdGVtSW5mbxIcCgl1cGxvYWRVUkwYBCABKAlSCXVwbG9hZFVS' + 'TBIiCgxsb2dGaWxlQ291bnQYBSABKA1SDGxvZ0ZpbGVDb3VudA=='); + +@$core.Deprecated('Use debugBundleResponseDescriptor instead') +const DebugBundleResponse$json = { + '1': 'DebugBundleResponse', + '2': [ + {'1': 'path', '3': 1, '4': 1, '5': 9, '10': 'path'}, + {'1': 'uploadedKey', '3': 2, '4': 1, '5': 9, '10': 'uploadedKey'}, + { + '1': 'uploadFailureReason', + '3': 3, + '4': 1, + '5': 9, + '10': 'uploadFailureReason' + }, + ], +}; + +/// Descriptor for `DebugBundleResponse`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List debugBundleResponseDescriptor = $convert.base64Decode( + 'ChNEZWJ1Z0J1bmRsZVJlc3BvbnNlEhIKBHBhdGgYASABKAlSBHBhdGgSIAoLdXBsb2FkZWRLZX' + 'kYAiABKAlSC3VwbG9hZGVkS2V5EjAKE3VwbG9hZEZhaWx1cmVSZWFzb24YAyABKAlSE3VwbG9h' + 'ZEZhaWx1cmVSZWFzb24='); + +@$core.Deprecated('Use getLogLevelRequestDescriptor instead') +const GetLogLevelRequest$json = { + '1': 'GetLogLevelRequest', +}; + +/// Descriptor for `GetLogLevelRequest`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List getLogLevelRequestDescriptor = + $convert.base64Decode('ChJHZXRMb2dMZXZlbFJlcXVlc3Q='); + +@$core.Deprecated('Use getLogLevelResponseDescriptor instead') +const GetLogLevelResponse$json = { + '1': 'GetLogLevelResponse', + '2': [ + { + '1': 'level', + '3': 1, + '4': 1, + '5': 14, + '6': '.daemon.LogLevel', + '10': 'level' + }, + ], +}; + +/// Descriptor for `GetLogLevelResponse`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List getLogLevelResponseDescriptor = $convert.base64Decode( + 'ChNHZXRMb2dMZXZlbFJlc3BvbnNlEiYKBWxldmVsGAEgASgOMhAuZGFlbW9uLkxvZ0xldmVsUg' + 'VsZXZlbA=='); + +@$core.Deprecated('Use setLogLevelRequestDescriptor instead') +const SetLogLevelRequest$json = { + '1': 'SetLogLevelRequest', + '2': [ + { + '1': 'level', + '3': 1, + '4': 1, + '5': 14, + '6': '.daemon.LogLevel', + '10': 'level' + }, + ], +}; + +/// Descriptor for `SetLogLevelRequest`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List setLogLevelRequestDescriptor = $convert.base64Decode( + 'ChJTZXRMb2dMZXZlbFJlcXVlc3QSJgoFbGV2ZWwYASABKA4yEC5kYWVtb24uTG9nTGV2ZWxSBW' + 'xldmVs'); + +@$core.Deprecated('Use setLogLevelResponseDescriptor instead') +const SetLogLevelResponse$json = { + '1': 'SetLogLevelResponse', +}; + +/// Descriptor for `SetLogLevelResponse`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List setLogLevelResponseDescriptor = + $convert.base64Decode('ChNTZXRMb2dMZXZlbFJlc3BvbnNl'); + +@$core.Deprecated('Use stateDescriptor instead') +const State$json = { + '1': 'State', + '2': [ + {'1': 'name', '3': 1, '4': 1, '5': 9, '10': 'name'}, + ], +}; + +/// Descriptor for `State`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List stateDescriptor = + $convert.base64Decode('CgVTdGF0ZRISCgRuYW1lGAEgASgJUgRuYW1l'); + +@$core.Deprecated('Use listStatesRequestDescriptor instead') +const ListStatesRequest$json = { + '1': 'ListStatesRequest', +}; + +/// Descriptor for `ListStatesRequest`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List listStatesRequestDescriptor = + $convert.base64Decode('ChFMaXN0U3RhdGVzUmVxdWVzdA=='); + +@$core.Deprecated('Use listStatesResponseDescriptor instead') +const ListStatesResponse$json = { + '1': 'ListStatesResponse', + '2': [ + { + '1': 'states', + '3': 1, + '4': 3, + '5': 11, + '6': '.daemon.State', + '10': 'states' + }, + ], +}; + +/// Descriptor for `ListStatesResponse`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List listStatesResponseDescriptor = $convert.base64Decode( + 'ChJMaXN0U3RhdGVzUmVzcG9uc2USJQoGc3RhdGVzGAEgAygLMg0uZGFlbW9uLlN0YXRlUgZzdG' + 'F0ZXM='); + +@$core.Deprecated('Use cleanStateRequestDescriptor instead') +const CleanStateRequest$json = { + '1': 'CleanStateRequest', + '2': [ + {'1': 'state_name', '3': 1, '4': 1, '5': 9, '10': 'stateName'}, + {'1': 'all', '3': 2, '4': 1, '5': 8, '10': 'all'}, + ], +}; + +/// Descriptor for `CleanStateRequest`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List cleanStateRequestDescriptor = $convert.base64Decode( + 'ChFDbGVhblN0YXRlUmVxdWVzdBIdCgpzdGF0ZV9uYW1lGAEgASgJUglzdGF0ZU5hbWUSEAoDYW' + 'xsGAIgASgIUgNhbGw='); + +@$core.Deprecated('Use cleanStateResponseDescriptor instead') +const CleanStateResponse$json = { + '1': 'CleanStateResponse', + '2': [ + {'1': 'cleaned_states', '3': 1, '4': 1, '5': 5, '10': 'cleanedStates'}, + ], +}; + +/// Descriptor for `CleanStateResponse`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List cleanStateResponseDescriptor = $convert.base64Decode( + 'ChJDbGVhblN0YXRlUmVzcG9uc2USJQoOY2xlYW5lZF9zdGF0ZXMYASABKAVSDWNsZWFuZWRTdG' + 'F0ZXM='); + +@$core.Deprecated('Use deleteStateRequestDescriptor instead') +const DeleteStateRequest$json = { + '1': 'DeleteStateRequest', + '2': [ + {'1': 'state_name', '3': 1, '4': 1, '5': 9, '10': 'stateName'}, + {'1': 'all', '3': 2, '4': 1, '5': 8, '10': 'all'}, + ], +}; + +/// Descriptor for `DeleteStateRequest`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List deleteStateRequestDescriptor = $convert.base64Decode( + 'ChJEZWxldGVTdGF0ZVJlcXVlc3QSHQoKc3RhdGVfbmFtZRgBIAEoCVIJc3RhdGVOYW1lEhAKA2' + 'FsbBgCIAEoCFIDYWxs'); + +@$core.Deprecated('Use deleteStateResponseDescriptor instead') +const DeleteStateResponse$json = { + '1': 'DeleteStateResponse', + '2': [ + {'1': 'deleted_states', '3': 1, '4': 1, '5': 5, '10': 'deletedStates'}, + ], +}; + +/// Descriptor for `DeleteStateResponse`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List deleteStateResponseDescriptor = $convert.base64Decode( + 'ChNEZWxldGVTdGF0ZVJlc3BvbnNlEiUKDmRlbGV0ZWRfc3RhdGVzGAEgASgFUg1kZWxldGVkU3' + 'RhdGVz'); + +@$core.Deprecated('Use setSyncResponsePersistenceRequestDescriptor instead') +const SetSyncResponsePersistenceRequest$json = { + '1': 'SetSyncResponsePersistenceRequest', + '2': [ + {'1': 'enabled', '3': 1, '4': 1, '5': 8, '10': 'enabled'}, + ], +}; + +/// Descriptor for `SetSyncResponsePersistenceRequest`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List setSyncResponsePersistenceRequestDescriptor = + $convert.base64Decode( + 'CiFTZXRTeW5jUmVzcG9uc2VQZXJzaXN0ZW5jZVJlcXVlc3QSGAoHZW5hYmxlZBgBIAEoCFIHZW' + '5hYmxlZA=='); + +@$core.Deprecated('Use setSyncResponsePersistenceResponseDescriptor instead') +const SetSyncResponsePersistenceResponse$json = { + '1': 'SetSyncResponsePersistenceResponse', +}; + +/// Descriptor for `SetSyncResponsePersistenceResponse`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List setSyncResponsePersistenceResponseDescriptor = + $convert.base64Decode('CiJTZXRTeW5jUmVzcG9uc2VQZXJzaXN0ZW5jZVJlc3BvbnNl'); + +@$core.Deprecated('Use tCPFlagsDescriptor instead') +const TCPFlags$json = { + '1': 'TCPFlags', + '2': [ + {'1': 'syn', '3': 1, '4': 1, '5': 8, '10': 'syn'}, + {'1': 'ack', '3': 2, '4': 1, '5': 8, '10': 'ack'}, + {'1': 'fin', '3': 3, '4': 1, '5': 8, '10': 'fin'}, + {'1': 'rst', '3': 4, '4': 1, '5': 8, '10': 'rst'}, + {'1': 'psh', '3': 5, '4': 1, '5': 8, '10': 'psh'}, + {'1': 'urg', '3': 6, '4': 1, '5': 8, '10': 'urg'}, + ], +}; + +/// Descriptor for `TCPFlags`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List tCPFlagsDescriptor = $convert.base64Decode( + 'CghUQ1BGbGFncxIQCgNzeW4YASABKAhSA3N5bhIQCgNhY2sYAiABKAhSA2FjaxIQCgNmaW4YAy' + 'ABKAhSA2ZpbhIQCgNyc3QYBCABKAhSA3JzdBIQCgNwc2gYBSABKAhSA3BzaBIQCgN1cmcYBiAB' + 'KAhSA3VyZw=='); + +@$core.Deprecated('Use tracePacketRequestDescriptor instead') +const TracePacketRequest$json = { + '1': 'TracePacketRequest', + '2': [ + {'1': 'source_ip', '3': 1, '4': 1, '5': 9, '10': 'sourceIp'}, + {'1': 'destination_ip', '3': 2, '4': 1, '5': 9, '10': 'destinationIp'}, + {'1': 'protocol', '3': 3, '4': 1, '5': 9, '10': 'protocol'}, + {'1': 'source_port', '3': 4, '4': 1, '5': 13, '10': 'sourcePort'}, + {'1': 'destination_port', '3': 5, '4': 1, '5': 13, '10': 'destinationPort'}, + {'1': 'direction', '3': 6, '4': 1, '5': 9, '10': 'direction'}, + { + '1': 'tcp_flags', + '3': 7, + '4': 1, + '5': 11, + '6': '.daemon.TCPFlags', + '9': 0, + '10': 'tcpFlags', + '17': true + }, + { + '1': 'icmp_type', + '3': 8, + '4': 1, + '5': 13, + '9': 1, + '10': 'icmpType', + '17': true + }, + { + '1': 'icmp_code', + '3': 9, + '4': 1, + '5': 13, + '9': 2, + '10': 'icmpCode', + '17': true + }, + ], + '8': [ + {'1': '_tcp_flags'}, + {'1': '_icmp_type'}, + {'1': '_icmp_code'}, + ], +}; + +/// Descriptor for `TracePacketRequest`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List tracePacketRequestDescriptor = $convert.base64Decode( + 'ChJUcmFjZVBhY2tldFJlcXVlc3QSGwoJc291cmNlX2lwGAEgASgJUghzb3VyY2VJcBIlCg5kZX' + 'N0aW5hdGlvbl9pcBgCIAEoCVINZGVzdGluYXRpb25JcBIaCghwcm90b2NvbBgDIAEoCVIIcHJv' + 'dG9jb2wSHwoLc291cmNlX3BvcnQYBCABKA1SCnNvdXJjZVBvcnQSKQoQZGVzdGluYXRpb25fcG' + '9ydBgFIAEoDVIPZGVzdGluYXRpb25Qb3J0EhwKCWRpcmVjdGlvbhgGIAEoCVIJZGlyZWN0aW9u' + 'EjIKCXRjcF9mbGFncxgHIAEoCzIQLmRhZW1vbi5UQ1BGbGFnc0gAUgh0Y3BGbGFnc4gBARIgCg' + 'lpY21wX3R5cGUYCCABKA1IAVIIaWNtcFR5cGWIAQESIAoJaWNtcF9jb2RlGAkgASgNSAJSCGlj' + 'bXBDb2RliAEBQgwKCl90Y3BfZmxhZ3NCDAoKX2ljbXBfdHlwZUIMCgpfaWNtcF9jb2Rl'); + +@$core.Deprecated('Use traceStageDescriptor instead') +const TraceStage$json = { + '1': 'TraceStage', + '2': [ + {'1': 'name', '3': 1, '4': 1, '5': 9, '10': 'name'}, + {'1': 'message', '3': 2, '4': 1, '5': 9, '10': 'message'}, + {'1': 'allowed', '3': 3, '4': 1, '5': 8, '10': 'allowed'}, + { + '1': 'forwarding_details', + '3': 4, + '4': 1, + '5': 9, + '9': 0, + '10': 'forwardingDetails', + '17': true + }, + ], + '8': [ + {'1': '_forwarding_details'}, + ], +}; + +/// Descriptor for `TraceStage`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List traceStageDescriptor = $convert.base64Decode( + 'CgpUcmFjZVN0YWdlEhIKBG5hbWUYASABKAlSBG5hbWUSGAoHbWVzc2FnZRgCIAEoCVIHbWVzc2' + 'FnZRIYCgdhbGxvd2VkGAMgASgIUgdhbGxvd2VkEjIKEmZvcndhcmRpbmdfZGV0YWlscxgEIAEo' + 'CUgAUhFmb3J3YXJkaW5nRGV0YWlsc4gBAUIVChNfZm9yd2FyZGluZ19kZXRhaWxz'); + +@$core.Deprecated('Use tracePacketResponseDescriptor instead') +const TracePacketResponse$json = { + '1': 'TracePacketResponse', + '2': [ + { + '1': 'stages', + '3': 1, + '4': 3, + '5': 11, + '6': '.daemon.TraceStage', + '10': 'stages' + }, + { + '1': 'final_disposition', + '3': 2, + '4': 1, + '5': 8, + '10': 'finalDisposition' + }, + ], +}; + +/// Descriptor for `TracePacketResponse`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List tracePacketResponseDescriptor = $convert.base64Decode( + 'ChNUcmFjZVBhY2tldFJlc3BvbnNlEioKBnN0YWdlcxgBIAMoCzISLmRhZW1vbi5UcmFjZVN0YW' + 'dlUgZzdGFnZXMSKwoRZmluYWxfZGlzcG9zaXRpb24YAiABKAhSEGZpbmFsRGlzcG9zaXRpb24='); + +@$core.Deprecated('Use subscribeRequestDescriptor instead') +const SubscribeRequest$json = { + '1': 'SubscribeRequest', +}; + +/// Descriptor for `SubscribeRequest`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List subscribeRequestDescriptor = + $convert.base64Decode('ChBTdWJzY3JpYmVSZXF1ZXN0'); + +@$core.Deprecated('Use systemEventDescriptor instead') +const SystemEvent$json = { + '1': 'SystemEvent', + '2': [ + {'1': 'id', '3': 1, '4': 1, '5': 9, '10': 'id'}, + { + '1': 'severity', + '3': 2, + '4': 1, + '5': 14, + '6': '.daemon.SystemEvent.Severity', + '10': 'severity' + }, + { + '1': 'category', + '3': 3, + '4': 1, + '5': 14, + '6': '.daemon.SystemEvent.Category', + '10': 'category' + }, + {'1': 'message', '3': 4, '4': 1, '5': 9, '10': 'message'}, + {'1': 'userMessage', '3': 5, '4': 1, '5': 9, '10': 'userMessage'}, + { + '1': 'timestamp', + '3': 6, + '4': 1, + '5': 11, + '6': '.google.protobuf.Timestamp', + '10': 'timestamp' + }, + { + '1': 'metadata', + '3': 7, + '4': 3, + '5': 11, + '6': '.daemon.SystemEvent.MetadataEntry', + '10': 'metadata' + }, + ], + '3': [SystemEvent_MetadataEntry$json], + '4': [SystemEvent_Severity$json, SystemEvent_Category$json], +}; + +@$core.Deprecated('Use systemEventDescriptor instead') +const SystemEvent_MetadataEntry$json = { + '1': 'MetadataEntry', + '2': [ + {'1': 'key', '3': 1, '4': 1, '5': 9, '10': 'key'}, + {'1': 'value', '3': 2, '4': 1, '5': 9, '10': 'value'}, + ], + '7': {'7': true}, +}; + +@$core.Deprecated('Use systemEventDescriptor instead') +const SystemEvent_Severity$json = { + '1': 'Severity', + '2': [ + {'1': 'INFO', '2': 0}, + {'1': 'WARNING', '2': 1}, + {'1': 'ERROR', '2': 2}, + {'1': 'CRITICAL', '2': 3}, + ], +}; + +@$core.Deprecated('Use systemEventDescriptor instead') +const SystemEvent_Category$json = { + '1': 'Category', + '2': [ + {'1': 'NETWORK', '2': 0}, + {'1': 'DNS', '2': 1}, + {'1': 'AUTHENTICATION', '2': 2}, + {'1': 'CONNECTIVITY', '2': 3}, + {'1': 'SYSTEM', '2': 4}, + ], +}; + +/// Descriptor for `SystemEvent`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List systemEventDescriptor = $convert.base64Decode( + 'CgtTeXN0ZW1FdmVudBIOCgJpZBgBIAEoCVICaWQSOAoIc2V2ZXJpdHkYAiABKA4yHC5kYWVtb2' + '4uU3lzdGVtRXZlbnQuU2V2ZXJpdHlSCHNldmVyaXR5EjgKCGNhdGVnb3J5GAMgASgOMhwuZGFl' + 'bW9uLlN5c3RlbUV2ZW50LkNhdGVnb3J5UghjYXRlZ29yeRIYCgdtZXNzYWdlGAQgASgJUgdtZX' + 'NzYWdlEiAKC3VzZXJNZXNzYWdlGAUgASgJUgt1c2VyTWVzc2FnZRI4Cgl0aW1lc3RhbXAYBiAB' + 'KAsyGi5nb29nbGUucHJvdG9idWYuVGltZXN0YW1wUgl0aW1lc3RhbXASPQoIbWV0YWRhdGEYBy' + 'ADKAsyIS5kYWVtb24uU3lzdGVtRXZlbnQuTWV0YWRhdGFFbnRyeVIIbWV0YWRhdGEaOwoNTWV0' + 'YWRhdGFFbnRyeRIQCgNrZXkYASABKAlSA2tleRIUCgV2YWx1ZRgCIAEoCVIFdmFsdWU6AjgBIj' + 'oKCFNldmVyaXR5EggKBElORk8QABILCgdXQVJOSU5HEAESCQoFRVJST1IQAhIMCghDUklUSUNB' + 'TBADIlIKCENhdGVnb3J5EgsKB05FVFdPUksQABIHCgNETlMQARISCg5BVVRIRU5USUNBVElPTh' + 'ACEhAKDENPTk5FQ1RJVklUWRADEgoKBlNZU1RFTRAE'); + +@$core.Deprecated('Use getEventsRequestDescriptor instead') +const GetEventsRequest$json = { + '1': 'GetEventsRequest', +}; + +/// Descriptor for `GetEventsRequest`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List getEventsRequestDescriptor = + $convert.base64Decode('ChBHZXRFdmVudHNSZXF1ZXN0'); + +@$core.Deprecated('Use getEventsResponseDescriptor instead') +const GetEventsResponse$json = { + '1': 'GetEventsResponse', + '2': [ + { + '1': 'events', + '3': 1, + '4': 3, + '5': 11, + '6': '.daemon.SystemEvent', + '10': 'events' + }, + ], +}; + +/// Descriptor for `GetEventsResponse`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List getEventsResponseDescriptor = $convert.base64Decode( + 'ChFHZXRFdmVudHNSZXNwb25zZRIrCgZldmVudHMYASADKAsyEy5kYWVtb24uU3lzdGVtRXZlbn' + 'RSBmV2ZW50cw=='); + +@$core.Deprecated('Use switchProfileRequestDescriptor instead') +const SwitchProfileRequest$json = { + '1': 'SwitchProfileRequest', + '2': [ + { + '1': 'profileName', + '3': 1, + '4': 1, + '5': 9, + '9': 0, + '10': 'profileName', + '17': true + }, + { + '1': 'username', + '3': 2, + '4': 1, + '5': 9, + '9': 1, + '10': 'username', + '17': true + }, + ], + '8': [ + {'1': '_profileName'}, + {'1': '_username'}, + ], +}; + +/// Descriptor for `SwitchProfileRequest`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List switchProfileRequestDescriptor = $convert.base64Decode( + 'ChRTd2l0Y2hQcm9maWxlUmVxdWVzdBIlCgtwcm9maWxlTmFtZRgBIAEoCUgAUgtwcm9maWxlTm' + 'FtZYgBARIfCgh1c2VybmFtZRgCIAEoCUgBUgh1c2VybmFtZYgBAUIOCgxfcHJvZmlsZU5hbWVC' + 'CwoJX3VzZXJuYW1l'); + +@$core.Deprecated('Use switchProfileResponseDescriptor instead') +const SwitchProfileResponse$json = { + '1': 'SwitchProfileResponse', +}; + +/// Descriptor for `SwitchProfileResponse`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List switchProfileResponseDescriptor = + $convert.base64Decode('ChVTd2l0Y2hQcm9maWxlUmVzcG9uc2U='); + +@$core.Deprecated('Use setConfigRequestDescriptor instead') +const SetConfigRequest$json = { + '1': 'SetConfigRequest', + '2': [ + {'1': 'username', '3': 1, '4': 1, '5': 9, '10': 'username'}, + {'1': 'profileName', '3': 2, '4': 1, '5': 9, '10': 'profileName'}, + {'1': 'managementUrl', '3': 3, '4': 1, '5': 9, '10': 'managementUrl'}, + {'1': 'adminURL', '3': 4, '4': 1, '5': 9, '10': 'adminURL'}, + { + '1': 'rosenpassEnabled', + '3': 5, + '4': 1, + '5': 8, + '9': 0, + '10': 'rosenpassEnabled', + '17': true + }, + { + '1': 'interfaceName', + '3': 6, + '4': 1, + '5': 9, + '9': 1, + '10': 'interfaceName', + '17': true + }, + { + '1': 'wireguardPort', + '3': 7, + '4': 1, + '5': 3, + '9': 2, + '10': 'wireguardPort', + '17': true + }, + { + '1': 'optionalPreSharedKey', + '3': 8, + '4': 1, + '5': 9, + '9': 3, + '10': 'optionalPreSharedKey', + '17': true + }, + { + '1': 'disableAutoConnect', + '3': 9, + '4': 1, + '5': 8, + '9': 4, + '10': 'disableAutoConnect', + '17': true + }, + { + '1': 'serverSSHAllowed', + '3': 10, + '4': 1, + '5': 8, + '9': 5, + '10': 'serverSSHAllowed', + '17': true + }, + { + '1': 'rosenpassPermissive', + '3': 11, + '4': 1, + '5': 8, + '9': 6, + '10': 'rosenpassPermissive', + '17': true + }, + { + '1': 'networkMonitor', + '3': 12, + '4': 1, + '5': 8, + '9': 7, + '10': 'networkMonitor', + '17': true + }, + { + '1': 'disable_client_routes', + '3': 13, + '4': 1, + '5': 8, + '9': 8, + '10': 'disableClientRoutes', + '17': true + }, + { + '1': 'disable_server_routes', + '3': 14, + '4': 1, + '5': 8, + '9': 9, + '10': 'disableServerRoutes', + '17': true + }, + { + '1': 'disable_dns', + '3': 15, + '4': 1, + '5': 8, + '9': 10, + '10': 'disableDns', + '17': true + }, + { + '1': 'disable_firewall', + '3': 16, + '4': 1, + '5': 8, + '9': 11, + '10': 'disableFirewall', + '17': true + }, + { + '1': 'block_lan_access', + '3': 17, + '4': 1, + '5': 8, + '9': 12, + '10': 'blockLanAccess', + '17': true + }, + { + '1': 'disable_notifications', + '3': 18, + '4': 1, + '5': 8, + '9': 13, + '10': 'disableNotifications', + '17': true + }, + { + '1': 'lazyConnectionEnabled', + '3': 19, + '4': 1, + '5': 8, + '9': 14, + '10': 'lazyConnectionEnabled', + '17': true + }, + { + '1': 'block_inbound', + '3': 20, + '4': 1, + '5': 8, + '9': 15, + '10': 'blockInbound', + '17': true + }, + {'1': 'natExternalIPs', '3': 21, '4': 3, '5': 9, '10': 'natExternalIPs'}, + { + '1': 'cleanNATExternalIPs', + '3': 22, + '4': 1, + '5': 8, + '10': 'cleanNATExternalIPs' + }, + { + '1': 'customDNSAddress', + '3': 23, + '4': 1, + '5': 12, + '10': 'customDNSAddress' + }, + { + '1': 'extraIFaceBlacklist', + '3': 24, + '4': 3, + '5': 9, + '10': 'extraIFaceBlacklist' + }, + {'1': 'dns_labels', '3': 25, '4': 3, '5': 9, '10': 'dnsLabels'}, + {'1': 'cleanDNSLabels', '3': 26, '4': 1, '5': 8, '10': 'cleanDNSLabels'}, + { + '1': 'dnsRouteInterval', + '3': 27, + '4': 1, + '5': 11, + '6': '.google.protobuf.Duration', + '9': 16, + '10': 'dnsRouteInterval', + '17': true + }, + {'1': 'mtu', '3': 28, '4': 1, '5': 3, '9': 17, '10': 'mtu', '17': true}, + { + '1': 'enableSSHRoot', + '3': 29, + '4': 1, + '5': 8, + '9': 18, + '10': 'enableSSHRoot', + '17': true + }, + { + '1': 'enableSSHSFTP', + '3': 30, + '4': 1, + '5': 8, + '9': 19, + '10': 'enableSSHSFTP', + '17': true + }, + { + '1': 'enableSSHLocalPortForwarding', + '3': 31, + '4': 1, + '5': 8, + '9': 20, + '10': 'enableSSHLocalPortForwarding', + '17': true + }, + { + '1': 'enableSSHRemotePortForwarding', + '3': 32, + '4': 1, + '5': 8, + '9': 21, + '10': 'enableSSHRemotePortForwarding', + '17': true + }, + { + '1': 'disableSSHAuth', + '3': 33, + '4': 1, + '5': 8, + '9': 22, + '10': 'disableSSHAuth', + '17': true + }, + { + '1': 'sshJWTCacheTTL', + '3': 34, + '4': 1, + '5': 5, + '9': 23, + '10': 'sshJWTCacheTTL', + '17': true + }, + ], + '8': [ + {'1': '_rosenpassEnabled'}, + {'1': '_interfaceName'}, + {'1': '_wireguardPort'}, + {'1': '_optionalPreSharedKey'}, + {'1': '_disableAutoConnect'}, + {'1': '_serverSSHAllowed'}, + {'1': '_rosenpassPermissive'}, + {'1': '_networkMonitor'}, + {'1': '_disable_client_routes'}, + {'1': '_disable_server_routes'}, + {'1': '_disable_dns'}, + {'1': '_disable_firewall'}, + {'1': '_block_lan_access'}, + {'1': '_disable_notifications'}, + {'1': '_lazyConnectionEnabled'}, + {'1': '_block_inbound'}, + {'1': '_dnsRouteInterval'}, + {'1': '_mtu'}, + {'1': '_enableSSHRoot'}, + {'1': '_enableSSHSFTP'}, + {'1': '_enableSSHLocalPortForwarding'}, + {'1': '_enableSSHRemotePortForwarding'}, + {'1': '_disableSSHAuth'}, + {'1': '_sshJWTCacheTTL'}, + ], +}; + +/// Descriptor for `SetConfigRequest`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List setConfigRequestDescriptor = $convert.base64Decode( + 'ChBTZXRDb25maWdSZXF1ZXN0EhoKCHVzZXJuYW1lGAEgASgJUgh1c2VybmFtZRIgCgtwcm9maW' + 'xlTmFtZRgCIAEoCVILcHJvZmlsZU5hbWUSJAoNbWFuYWdlbWVudFVybBgDIAEoCVINbWFuYWdl' + 'bWVudFVybBIaCghhZG1pblVSTBgEIAEoCVIIYWRtaW5VUkwSLwoQcm9zZW5wYXNzRW5hYmxlZB' + 'gFIAEoCEgAUhByb3NlbnBhc3NFbmFibGVkiAEBEikKDWludGVyZmFjZU5hbWUYBiABKAlIAVIN' + 'aW50ZXJmYWNlTmFtZYgBARIpCg13aXJlZ3VhcmRQb3J0GAcgASgDSAJSDXdpcmVndWFyZFBvcn' + 'SIAQESNwoUb3B0aW9uYWxQcmVTaGFyZWRLZXkYCCABKAlIA1IUb3B0aW9uYWxQcmVTaGFyZWRL' + 'ZXmIAQESMwoSZGlzYWJsZUF1dG9Db25uZWN0GAkgASgISARSEmRpc2FibGVBdXRvQ29ubmVjdI' + 'gBARIvChBzZXJ2ZXJTU0hBbGxvd2VkGAogASgISAVSEHNlcnZlclNTSEFsbG93ZWSIAQESNQoT' + 'cm9zZW5wYXNzUGVybWlzc2l2ZRgLIAEoCEgGUhNyb3NlbnBhc3NQZXJtaXNzaXZliAEBEisKDm' + '5ldHdvcmtNb25pdG9yGAwgASgISAdSDm5ldHdvcmtNb25pdG9yiAEBEjcKFWRpc2FibGVfY2xp' + 'ZW50X3JvdXRlcxgNIAEoCEgIUhNkaXNhYmxlQ2xpZW50Um91dGVziAEBEjcKFWRpc2FibGVfc2' + 'VydmVyX3JvdXRlcxgOIAEoCEgJUhNkaXNhYmxlU2VydmVyUm91dGVziAEBEiQKC2Rpc2FibGVf' + 'ZG5zGA8gASgISApSCmRpc2FibGVEbnOIAQESLgoQZGlzYWJsZV9maXJld2FsbBgQIAEoCEgLUg' + '9kaXNhYmxlRmlyZXdhbGyIAQESLQoQYmxvY2tfbGFuX2FjY2VzcxgRIAEoCEgMUg5ibG9ja0xh' + 'bkFjY2Vzc4gBARI4ChVkaXNhYmxlX25vdGlmaWNhdGlvbnMYEiABKAhIDVIUZGlzYWJsZU5vdG' + 'lmaWNhdGlvbnOIAQESOQoVbGF6eUNvbm5lY3Rpb25FbmFibGVkGBMgASgISA5SFWxhenlDb25u' + 'ZWN0aW9uRW5hYmxlZIgBARIoCg1ibG9ja19pbmJvdW5kGBQgASgISA9SDGJsb2NrSW5ib3VuZI' + 'gBARImCg5uYXRFeHRlcm5hbElQcxgVIAMoCVIObmF0RXh0ZXJuYWxJUHMSMAoTY2xlYW5OQVRF' + 'eHRlcm5hbElQcxgWIAEoCFITY2xlYW5OQVRFeHRlcm5hbElQcxIqChBjdXN0b21ETlNBZGRyZX' + 'NzGBcgASgMUhBjdXN0b21ETlNBZGRyZXNzEjAKE2V4dHJhSUZhY2VCbGFja2xpc3QYGCADKAlS' + 'E2V4dHJhSUZhY2VCbGFja2xpc3QSHQoKZG5zX2xhYmVscxgZIAMoCVIJZG5zTGFiZWxzEiYKDm' + 'NsZWFuRE5TTGFiZWxzGBogASgIUg5jbGVhbkROU0xhYmVscxJKChBkbnNSb3V0ZUludGVydmFs' + 'GBsgASgLMhkuZ29vZ2xlLnByb3RvYnVmLkR1cmF0aW9uSBBSEGRuc1JvdXRlSW50ZXJ2YWyIAQ' + 'ESFQoDbXR1GBwgASgDSBFSA210dYgBARIpCg1lbmFibGVTU0hSb290GB0gASgISBJSDWVuYWJs' + 'ZVNTSFJvb3SIAQESKQoNZW5hYmxlU1NIU0ZUUBgeIAEoCEgTUg1lbmFibGVTU0hTRlRQiAEBEk' + 'cKHGVuYWJsZVNTSExvY2FsUG9ydEZvcndhcmRpbmcYHyABKAhIFFIcZW5hYmxlU1NITG9jYWxQ' + 'b3J0Rm9yd2FyZGluZ4gBARJJCh1lbmFibGVTU0hSZW1vdGVQb3J0Rm9yd2FyZGluZxggIAEoCE' + 'gVUh1lbmFibGVTU0hSZW1vdGVQb3J0Rm9yd2FyZGluZ4gBARIrCg5kaXNhYmxlU1NIQXV0aBgh' + 'IAEoCEgWUg5kaXNhYmxlU1NIQXV0aIgBARIrCg5zc2hKV1RDYWNoZVRUTBgiIAEoBUgXUg5zc2' + 'hKV1RDYWNoZVRUTIgBAUITChFfcm9zZW5wYXNzRW5hYmxlZEIQCg5faW50ZXJmYWNlTmFtZUIQ' + 'Cg5fd2lyZWd1YXJkUG9ydEIXChVfb3B0aW9uYWxQcmVTaGFyZWRLZXlCFQoTX2Rpc2FibGVBdX' + 'RvQ29ubmVjdEITChFfc2VydmVyU1NIQWxsb3dlZEIWChRfcm9zZW5wYXNzUGVybWlzc2l2ZUIR' + 'Cg9fbmV0d29ya01vbml0b3JCGAoWX2Rpc2FibGVfY2xpZW50X3JvdXRlc0IYChZfZGlzYWJsZV' + '9zZXJ2ZXJfcm91dGVzQg4KDF9kaXNhYmxlX2Ruc0ITChFfZGlzYWJsZV9maXJld2FsbEITChFf' + 'YmxvY2tfbGFuX2FjY2Vzc0IYChZfZGlzYWJsZV9ub3RpZmljYXRpb25zQhgKFl9sYXp5Q29ubm' + 'VjdGlvbkVuYWJsZWRCEAoOX2Jsb2NrX2luYm91bmRCEwoRX2Ruc1JvdXRlSW50ZXJ2YWxCBgoE' + 'X210dUIQCg5fZW5hYmxlU1NIUm9vdEIQCg5fZW5hYmxlU1NIU0ZUUEIfCh1fZW5hYmxlU1NITG' + '9jYWxQb3J0Rm9yd2FyZGluZ0IgCh5fZW5hYmxlU1NIUmVtb3RlUG9ydEZvcndhcmRpbmdCEQoP' + 'X2Rpc2FibGVTU0hBdXRoQhEKD19zc2hKV1RDYWNoZVRUTA=='); + +@$core.Deprecated('Use setConfigResponseDescriptor instead') +const SetConfigResponse$json = { + '1': 'SetConfigResponse', +}; + +/// Descriptor for `SetConfigResponse`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List setConfigResponseDescriptor = + $convert.base64Decode('ChFTZXRDb25maWdSZXNwb25zZQ=='); + +@$core.Deprecated('Use addProfileRequestDescriptor instead') +const AddProfileRequest$json = { + '1': 'AddProfileRequest', + '2': [ + {'1': 'username', '3': 1, '4': 1, '5': 9, '10': 'username'}, + {'1': 'profileName', '3': 2, '4': 1, '5': 9, '10': 'profileName'}, + ], +}; + +/// Descriptor for `AddProfileRequest`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List addProfileRequestDescriptor = $convert.base64Decode( + 'ChFBZGRQcm9maWxlUmVxdWVzdBIaCgh1c2VybmFtZRgBIAEoCVIIdXNlcm5hbWUSIAoLcHJvZm' + 'lsZU5hbWUYAiABKAlSC3Byb2ZpbGVOYW1l'); + +@$core.Deprecated('Use addProfileResponseDescriptor instead') +const AddProfileResponse$json = { + '1': 'AddProfileResponse', +}; + +/// Descriptor for `AddProfileResponse`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List addProfileResponseDescriptor = + $convert.base64Decode('ChJBZGRQcm9maWxlUmVzcG9uc2U='); + +@$core.Deprecated('Use removeProfileRequestDescriptor instead') +const RemoveProfileRequest$json = { + '1': 'RemoveProfileRequest', + '2': [ + {'1': 'username', '3': 1, '4': 1, '5': 9, '10': 'username'}, + {'1': 'profileName', '3': 2, '4': 1, '5': 9, '10': 'profileName'}, + ], +}; + +/// Descriptor for `RemoveProfileRequest`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List removeProfileRequestDescriptor = $convert.base64Decode( + 'ChRSZW1vdmVQcm9maWxlUmVxdWVzdBIaCgh1c2VybmFtZRgBIAEoCVIIdXNlcm5hbWUSIAoLcH' + 'JvZmlsZU5hbWUYAiABKAlSC3Byb2ZpbGVOYW1l'); + +@$core.Deprecated('Use removeProfileResponseDescriptor instead') +const RemoveProfileResponse$json = { + '1': 'RemoveProfileResponse', +}; + +/// Descriptor for `RemoveProfileResponse`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List removeProfileResponseDescriptor = + $convert.base64Decode('ChVSZW1vdmVQcm9maWxlUmVzcG9uc2U='); + +@$core.Deprecated('Use listProfilesRequestDescriptor instead') +const ListProfilesRequest$json = { + '1': 'ListProfilesRequest', + '2': [ + {'1': 'username', '3': 1, '4': 1, '5': 9, '10': 'username'}, + ], +}; + +/// Descriptor for `ListProfilesRequest`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List listProfilesRequestDescriptor = + $convert.base64Decode( + 'ChNMaXN0UHJvZmlsZXNSZXF1ZXN0EhoKCHVzZXJuYW1lGAEgASgJUgh1c2VybmFtZQ=='); + +@$core.Deprecated('Use listProfilesResponseDescriptor instead') +const ListProfilesResponse$json = { + '1': 'ListProfilesResponse', + '2': [ + { + '1': 'profiles', + '3': 1, + '4': 3, + '5': 11, + '6': '.daemon.Profile', + '10': 'profiles' + }, + ], +}; + +/// Descriptor for `ListProfilesResponse`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List listProfilesResponseDescriptor = $convert.base64Decode( + 'ChRMaXN0UHJvZmlsZXNSZXNwb25zZRIrCghwcm9maWxlcxgBIAMoCzIPLmRhZW1vbi5Qcm9maW' + 'xlUghwcm9maWxlcw=='); + +@$core.Deprecated('Use profileDescriptor instead') +const Profile$json = { + '1': 'Profile', + '2': [ + {'1': 'name', '3': 1, '4': 1, '5': 9, '10': 'name'}, + {'1': 'is_active', '3': 2, '4': 1, '5': 8, '10': 'isActive'}, + ], +}; + +/// Descriptor for `Profile`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List profileDescriptor = $convert.base64Decode( + 'CgdQcm9maWxlEhIKBG5hbWUYASABKAlSBG5hbWUSGwoJaXNfYWN0aXZlGAIgASgIUghpc0FjdG' + 'l2ZQ=='); + +@$core.Deprecated('Use getActiveProfileRequestDescriptor instead') +const GetActiveProfileRequest$json = { + '1': 'GetActiveProfileRequest', +}; + +/// Descriptor for `GetActiveProfileRequest`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List getActiveProfileRequestDescriptor = + $convert.base64Decode('ChdHZXRBY3RpdmVQcm9maWxlUmVxdWVzdA=='); + +@$core.Deprecated('Use getActiveProfileResponseDescriptor instead') +const GetActiveProfileResponse$json = { + '1': 'GetActiveProfileResponse', + '2': [ + {'1': 'profileName', '3': 1, '4': 1, '5': 9, '10': 'profileName'}, + {'1': 'username', '3': 2, '4': 1, '5': 9, '10': 'username'}, + ], +}; + +/// Descriptor for `GetActiveProfileResponse`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List getActiveProfileResponseDescriptor = + $convert.base64Decode( + 'ChhHZXRBY3RpdmVQcm9maWxlUmVzcG9uc2USIAoLcHJvZmlsZU5hbWUYASABKAlSC3Byb2ZpbG' + 'VOYW1lEhoKCHVzZXJuYW1lGAIgASgJUgh1c2VybmFtZQ=='); + +@$core.Deprecated('Use logoutRequestDescriptor instead') +const LogoutRequest$json = { + '1': 'LogoutRequest', + '2': [ + { + '1': 'profileName', + '3': 1, + '4': 1, + '5': 9, + '9': 0, + '10': 'profileName', + '17': true + }, + { + '1': 'username', + '3': 2, + '4': 1, + '5': 9, + '9': 1, + '10': 'username', + '17': true + }, + ], + '8': [ + {'1': '_profileName'}, + {'1': '_username'}, + ], +}; + +/// Descriptor for `LogoutRequest`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List logoutRequestDescriptor = $convert.base64Decode( + 'Cg1Mb2dvdXRSZXF1ZXN0EiUKC3Byb2ZpbGVOYW1lGAEgASgJSABSC3Byb2ZpbGVOYW1liAEBEh' + '8KCHVzZXJuYW1lGAIgASgJSAFSCHVzZXJuYW1liAEBQg4KDF9wcm9maWxlTmFtZUILCglfdXNl' + 'cm5hbWU='); + +@$core.Deprecated('Use logoutResponseDescriptor instead') +const LogoutResponse$json = { + '1': 'LogoutResponse', +}; + +/// Descriptor for `LogoutResponse`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List logoutResponseDescriptor = + $convert.base64Decode('Cg5Mb2dvdXRSZXNwb25zZQ=='); + +@$core.Deprecated('Use getFeaturesRequestDescriptor instead') +const GetFeaturesRequest$json = { + '1': 'GetFeaturesRequest', +}; + +/// Descriptor for `GetFeaturesRequest`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List getFeaturesRequestDescriptor = + $convert.base64Decode('ChJHZXRGZWF0dXJlc1JlcXVlc3Q='); + +@$core.Deprecated('Use getFeaturesResponseDescriptor instead') +const GetFeaturesResponse$json = { + '1': 'GetFeaturesResponse', + '2': [ + {'1': 'disable_profiles', '3': 1, '4': 1, '5': 8, '10': 'disableProfiles'}, + { + '1': 'disable_update_settings', + '3': 2, + '4': 1, + '5': 8, + '10': 'disableUpdateSettings' + }, + {'1': 'disable_networks', '3': 3, '4': 1, '5': 8, '10': 'disableNetworks'}, + ], +}; + +/// Descriptor for `GetFeaturesResponse`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List getFeaturesResponseDescriptor = $convert.base64Decode( + 'ChNHZXRGZWF0dXJlc1Jlc3BvbnNlEikKEGRpc2FibGVfcHJvZmlsZXMYASABKAhSD2Rpc2FibG' + 'VQcm9maWxlcxI2ChdkaXNhYmxlX3VwZGF0ZV9zZXR0aW5ncxgCIAEoCFIVZGlzYWJsZVVwZGF0' + 'ZVNldHRpbmdzEikKEGRpc2FibGVfbmV0d29ya3MYAyABKAhSD2Rpc2FibGVOZXR3b3Jrcw=='); + +@$core.Deprecated('Use triggerUpdateRequestDescriptor instead') +const TriggerUpdateRequest$json = { + '1': 'TriggerUpdateRequest', +}; + +/// Descriptor for `TriggerUpdateRequest`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List triggerUpdateRequestDescriptor = + $convert.base64Decode('ChRUcmlnZ2VyVXBkYXRlUmVxdWVzdA=='); + +@$core.Deprecated('Use triggerUpdateResponseDescriptor instead') +const TriggerUpdateResponse$json = { + '1': 'TriggerUpdateResponse', + '2': [ + {'1': 'success', '3': 1, '4': 1, '5': 8, '10': 'success'}, + {'1': 'errorMsg', '3': 2, '4': 1, '5': 9, '10': 'errorMsg'}, + ], +}; + +/// Descriptor for `TriggerUpdateResponse`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List triggerUpdateResponseDescriptor = $convert.base64Decode( + 'ChVUcmlnZ2VyVXBkYXRlUmVzcG9uc2USGAoHc3VjY2VzcxgBIAEoCFIHc3VjY2VzcxIaCghlcn' + 'Jvck1zZxgCIAEoCVIIZXJyb3JNc2c='); + +@$core.Deprecated('Use getPeerSSHHostKeyRequestDescriptor instead') +const GetPeerSSHHostKeyRequest$json = { + '1': 'GetPeerSSHHostKeyRequest', + '2': [ + {'1': 'peerAddress', '3': 1, '4': 1, '5': 9, '10': 'peerAddress'}, + ], +}; + +/// Descriptor for `GetPeerSSHHostKeyRequest`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List getPeerSSHHostKeyRequestDescriptor = + $convert.base64Decode( + 'ChhHZXRQZWVyU1NISG9zdEtleVJlcXVlc3QSIAoLcGVlckFkZHJlc3MYASABKAlSC3BlZXJBZG' + 'RyZXNz'); + +@$core.Deprecated('Use getPeerSSHHostKeyResponseDescriptor instead') +const GetPeerSSHHostKeyResponse$json = { + '1': 'GetPeerSSHHostKeyResponse', + '2': [ + {'1': 'sshHostKey', '3': 1, '4': 1, '5': 12, '10': 'sshHostKey'}, + {'1': 'peerIP', '3': 2, '4': 1, '5': 9, '10': 'peerIP'}, + {'1': 'peerFQDN', '3': 3, '4': 1, '5': 9, '10': 'peerFQDN'}, + {'1': 'found', '3': 4, '4': 1, '5': 8, '10': 'found'}, + ], +}; + +/// Descriptor for `GetPeerSSHHostKeyResponse`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List getPeerSSHHostKeyResponseDescriptor = $convert.base64Decode( + 'ChlHZXRQZWVyU1NISG9zdEtleVJlc3BvbnNlEh4KCnNzaEhvc3RLZXkYASABKAxSCnNzaEhvc3' + 'RLZXkSFgoGcGVlcklQGAIgASgJUgZwZWVySVASGgoIcGVlckZRRE4YAyABKAlSCHBlZXJGUURO' + 'EhQKBWZvdW5kGAQgASgIUgVmb3VuZA=='); + +@$core.Deprecated('Use requestJWTAuthRequestDescriptor instead') +const RequestJWTAuthRequest$json = { + '1': 'RequestJWTAuthRequest', + '2': [ + {'1': 'hint', '3': 1, '4': 1, '5': 9, '9': 0, '10': 'hint', '17': true}, + ], + '8': [ + {'1': '_hint'}, + ], +}; + +/// Descriptor for `RequestJWTAuthRequest`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List requestJWTAuthRequestDescriptor = $convert.base64Decode( + 'ChVSZXF1ZXN0SldUQXV0aFJlcXVlc3QSFwoEaGludBgBIAEoCUgAUgRoaW50iAEBQgcKBV9oaW' + '50'); + +@$core.Deprecated('Use requestJWTAuthResponseDescriptor instead') +const RequestJWTAuthResponse$json = { + '1': 'RequestJWTAuthResponse', + '2': [ + {'1': 'verificationURI', '3': 1, '4': 1, '5': 9, '10': 'verificationURI'}, + { + '1': 'verificationURIComplete', + '3': 2, + '4': 1, + '5': 9, + '10': 'verificationURIComplete' + }, + {'1': 'userCode', '3': 3, '4': 1, '5': 9, '10': 'userCode'}, + {'1': 'deviceCode', '3': 4, '4': 1, '5': 9, '10': 'deviceCode'}, + {'1': 'expiresIn', '3': 5, '4': 1, '5': 3, '10': 'expiresIn'}, + {'1': 'cachedToken', '3': 6, '4': 1, '5': 9, '10': 'cachedToken'}, + {'1': 'maxTokenAge', '3': 7, '4': 1, '5': 3, '10': 'maxTokenAge'}, + ], +}; + +/// Descriptor for `RequestJWTAuthResponse`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List requestJWTAuthResponseDescriptor = $convert.base64Decode( + 'ChZSZXF1ZXN0SldUQXV0aFJlc3BvbnNlEigKD3ZlcmlmaWNhdGlvblVSSRgBIAEoCVIPdmVyaW' + 'ZpY2F0aW9uVVJJEjgKF3ZlcmlmaWNhdGlvblVSSUNvbXBsZXRlGAIgASgJUhd2ZXJpZmljYXRp' + 'b25VUklDb21wbGV0ZRIaCgh1c2VyQ29kZRgDIAEoCVIIdXNlckNvZGUSHgoKZGV2aWNlQ29kZR' + 'gEIAEoCVIKZGV2aWNlQ29kZRIcCglleHBpcmVzSW4YBSABKANSCWV4cGlyZXNJbhIgCgtjYWNo' + 'ZWRUb2tlbhgGIAEoCVILY2FjaGVkVG9rZW4SIAoLbWF4VG9rZW5BZ2UYByABKANSC21heFRva2' + 'VuQWdl'); + +@$core.Deprecated('Use waitJWTTokenRequestDescriptor instead') +const WaitJWTTokenRequest$json = { + '1': 'WaitJWTTokenRequest', + '2': [ + {'1': 'deviceCode', '3': 1, '4': 1, '5': 9, '10': 'deviceCode'}, + {'1': 'userCode', '3': 2, '4': 1, '5': 9, '10': 'userCode'}, + ], +}; + +/// Descriptor for `WaitJWTTokenRequest`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List waitJWTTokenRequestDescriptor = $convert.base64Decode( + 'ChNXYWl0SldUVG9rZW5SZXF1ZXN0Eh4KCmRldmljZUNvZGUYASABKAlSCmRldmljZUNvZGUSGg' + 'oIdXNlckNvZGUYAiABKAlSCHVzZXJDb2Rl'); + +@$core.Deprecated('Use waitJWTTokenResponseDescriptor instead') +const WaitJWTTokenResponse$json = { + '1': 'WaitJWTTokenResponse', + '2': [ + {'1': 'token', '3': 1, '4': 1, '5': 9, '10': 'token'}, + {'1': 'tokenType', '3': 2, '4': 1, '5': 9, '10': 'tokenType'}, + {'1': 'expiresIn', '3': 3, '4': 1, '5': 3, '10': 'expiresIn'}, + ], +}; + +/// Descriptor for `WaitJWTTokenResponse`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List waitJWTTokenResponseDescriptor = $convert.base64Decode( + 'ChRXYWl0SldUVG9rZW5SZXNwb25zZRIUCgV0b2tlbhgBIAEoCVIFdG9rZW4SHAoJdG9rZW5UeX' + 'BlGAIgASgJUgl0b2tlblR5cGUSHAoJZXhwaXJlc0luGAMgASgDUglleHBpcmVzSW4='); + +@$core.Deprecated('Use startCPUProfileRequestDescriptor instead') +const StartCPUProfileRequest$json = { + '1': 'StartCPUProfileRequest', +}; + +/// Descriptor for `StartCPUProfileRequest`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List startCPUProfileRequestDescriptor = + $convert.base64Decode('ChZTdGFydENQVVByb2ZpbGVSZXF1ZXN0'); + +@$core.Deprecated('Use startCPUProfileResponseDescriptor instead') +const StartCPUProfileResponse$json = { + '1': 'StartCPUProfileResponse', +}; + +/// Descriptor for `StartCPUProfileResponse`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List startCPUProfileResponseDescriptor = + $convert.base64Decode('ChdTdGFydENQVVByb2ZpbGVSZXNwb25zZQ=='); + +@$core.Deprecated('Use stopCPUProfileRequestDescriptor instead') +const StopCPUProfileRequest$json = { + '1': 'StopCPUProfileRequest', +}; + +/// Descriptor for `StopCPUProfileRequest`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List stopCPUProfileRequestDescriptor = + $convert.base64Decode('ChVTdG9wQ1BVUHJvZmlsZVJlcXVlc3Q='); + +@$core.Deprecated('Use stopCPUProfileResponseDescriptor instead') +const StopCPUProfileResponse$json = { + '1': 'StopCPUProfileResponse', +}; + +/// Descriptor for `StopCPUProfileResponse`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List stopCPUProfileResponseDescriptor = + $convert.base64Decode('ChZTdG9wQ1BVUHJvZmlsZVJlc3BvbnNl'); + +@$core.Deprecated('Use installerResultRequestDescriptor instead') +const InstallerResultRequest$json = { + '1': 'InstallerResultRequest', +}; + +/// Descriptor for `InstallerResultRequest`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List installerResultRequestDescriptor = + $convert.base64Decode('ChZJbnN0YWxsZXJSZXN1bHRSZXF1ZXN0'); + +@$core.Deprecated('Use installerResultResponseDescriptor instead') +const InstallerResultResponse$json = { + '1': 'InstallerResultResponse', + '2': [ + {'1': 'success', '3': 1, '4': 1, '5': 8, '10': 'success'}, + {'1': 'errorMsg', '3': 2, '4': 1, '5': 9, '10': 'errorMsg'}, + ], +}; + +/// Descriptor for `InstallerResultResponse`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List installerResultResponseDescriptor = + $convert.base64Decode( + 'ChdJbnN0YWxsZXJSZXN1bHRSZXNwb25zZRIYCgdzdWNjZXNzGAEgASgIUgdzdWNjZXNzEhoKCG' + 'Vycm9yTXNnGAIgASgJUghlcnJvck1zZw=='); + +@$core.Deprecated('Use exposeServiceRequestDescriptor instead') +const ExposeServiceRequest$json = { + '1': 'ExposeServiceRequest', + '2': [ + {'1': 'port', '3': 1, '4': 1, '5': 13, '10': 'port'}, + { + '1': 'protocol', + '3': 2, + '4': 1, + '5': 14, + '6': '.daemon.ExposeProtocol', + '10': 'protocol' + }, + {'1': 'pin', '3': 3, '4': 1, '5': 9, '10': 'pin'}, + {'1': 'password', '3': 4, '4': 1, '5': 9, '10': 'password'}, + {'1': 'user_groups', '3': 5, '4': 3, '5': 9, '10': 'userGroups'}, + {'1': 'domain', '3': 6, '4': 1, '5': 9, '10': 'domain'}, + {'1': 'name_prefix', '3': 7, '4': 1, '5': 9, '10': 'namePrefix'}, + {'1': 'listen_port', '3': 8, '4': 1, '5': 13, '10': 'listenPort'}, + ], +}; + +/// Descriptor for `ExposeServiceRequest`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List exposeServiceRequestDescriptor = $convert.base64Decode( + 'ChRFeHBvc2VTZXJ2aWNlUmVxdWVzdBISCgRwb3J0GAEgASgNUgRwb3J0EjIKCHByb3RvY29sGA' + 'IgASgOMhYuZGFlbW9uLkV4cG9zZVByb3RvY29sUghwcm90b2NvbBIQCgNwaW4YAyABKAlSA3Bp' + 'bhIaCghwYXNzd29yZBgEIAEoCVIIcGFzc3dvcmQSHwoLdXNlcl9ncm91cHMYBSADKAlSCnVzZX' + 'JHcm91cHMSFgoGZG9tYWluGAYgASgJUgZkb21haW4SHwoLbmFtZV9wcmVmaXgYByABKAlSCm5h' + 'bWVQcmVmaXgSHwoLbGlzdGVuX3BvcnQYCCABKA1SCmxpc3RlblBvcnQ='); + +@$core.Deprecated('Use exposeServiceEventDescriptor instead') +const ExposeServiceEvent$json = { + '1': 'ExposeServiceEvent', + '2': [ + { + '1': 'ready', + '3': 1, + '4': 1, + '5': 11, + '6': '.daemon.ExposeServiceReady', + '9': 0, + '10': 'ready' + }, + ], + '8': [ + {'1': 'event'}, + ], +}; + +/// Descriptor for `ExposeServiceEvent`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List exposeServiceEventDescriptor = $convert.base64Decode( + 'ChJFeHBvc2VTZXJ2aWNlRXZlbnQSMgoFcmVhZHkYASABKAsyGi5kYWVtb24uRXhwb3NlU2Vydm' + 'ljZVJlYWR5SABSBXJlYWR5QgcKBWV2ZW50'); + +@$core.Deprecated('Use exposeServiceReadyDescriptor instead') +const ExposeServiceReady$json = { + '1': 'ExposeServiceReady', + '2': [ + {'1': 'service_name', '3': 1, '4': 1, '5': 9, '10': 'serviceName'}, + {'1': 'service_url', '3': 2, '4': 1, '5': 9, '10': 'serviceUrl'}, + {'1': 'domain', '3': 3, '4': 1, '5': 9, '10': 'domain'}, + { + '1': 'port_auto_assigned', + '3': 4, + '4': 1, + '5': 8, + '10': 'portAutoAssigned' + }, + ], +}; + +/// Descriptor for `ExposeServiceReady`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List exposeServiceReadyDescriptor = $convert.base64Decode( + 'ChJFeHBvc2VTZXJ2aWNlUmVhZHkSIQoMc2VydmljZV9uYW1lGAEgASgJUgtzZXJ2aWNlTmFtZR' + 'IfCgtzZXJ2aWNlX3VybBgCIAEoCVIKc2VydmljZVVybBIWCgZkb21haW4YAyABKAlSBmRvbWFp' + 'bhIsChJwb3J0X2F1dG9fYXNzaWduZWQYBCABKAhSEHBvcnRBdXRvQXNzaWduZWQ='); diff --git a/client/flutter_ui/lib/src/models.dart b/client/flutter_ui/lib/src/models.dart new file mode 100644 index 000000000..d689a0827 --- /dev/null +++ b/client/flutter_ui/lib/src/models.dart @@ -0,0 +1,257 @@ +enum ConnectionStatus { + disconnected, + connecting, + awaitingLogin, + connected, + error; + + String get label { + return switch (this) { + ConnectionStatus.disconnected => 'Disconnected', + ConnectionStatus.connecting => 'Connecting', + ConnectionStatus.awaitingLogin => 'Awaiting login', + ConnectionStatus.connected => 'Connected', + ConnectionStatus.error => 'Error', + }; + } +} + +enum NetworkFilter { + all, + overlapping, + exitNode; + + bool matches(NetworkRoute route) { + return switch (this) { + NetworkFilter.all => true, + NetworkFilter.overlapping => route.overlapping, + NetworkFilter.exitNode => route.isExitNode, + }; + } +} + +class ClientSnapshot { + const ClientSnapshot({ + required this.daemonAddr, + required this.daemonVersion, + required this.status, + required this.activeProfile, + required this.profiles, + required this.networks, + required this.settings, + this.errorMessage, + this.pendingLogin, + }); + + factory ClientSnapshot.initial(String daemonAddr) { + return ClientSnapshot( + daemonAddr: daemonAddr, + daemonVersion: 'unknown', + status: ConnectionStatus.disconnected, + activeProfile: const ProfileInfo(name: 'default', active: true), + profiles: const [ProfileInfo(name: 'default', active: true)], + networks: const [], + settings: const ClientSettings(), + ); + } + + final String daemonAddr; + final String daemonVersion; + final ConnectionStatus status; + final ProfileInfo activeProfile; + final List profiles; + final List networks; + final ClientSettings settings; + final String? errorMessage; + final PendingLogin? pendingLogin; + + ClientSnapshot copyWith({ + String? daemonAddr, + String? daemonVersion, + ConnectionStatus? status, + ProfileInfo? activeProfile, + List? profiles, + List? networks, + ClientSettings? settings, + String? errorMessage, + PendingLogin? pendingLogin, + bool clearError = false, + bool clearPendingLogin = false, + }) { + return ClientSnapshot( + daemonAddr: daemonAddr ?? this.daemonAddr, + daemonVersion: daemonVersion ?? this.daemonVersion, + status: status ?? this.status, + activeProfile: activeProfile ?? this.activeProfile, + profiles: profiles ?? this.profiles, + networks: networks ?? this.networks, + settings: settings ?? this.settings, + errorMessage: clearError ? null : errorMessage ?? this.errorMessage, + pendingLogin: clearPendingLogin + ? null + : pendingLogin ?? this.pendingLogin, + ); + } +} + +class PendingLogin { + const PendingLogin({ + required this.verificationUri, + required this.userCode, + }); + + final String verificationUri; + final String userCode; +} + +class ProfileInfo { + const ProfileInfo({required this.name, required this.active, this.email}); + + final String name; + final String? email; + final bool active; +} + +class NetworkRoute { + const NetworkRoute({ + required this.id, + required this.range, + this.domains = const [], + this.resolvedIps = const {}, + this.selected = false, + this.overlapping = false, + }); + + final String id; + final String range; + final List domains; + final Map> resolvedIps; + final bool selected; + final bool overlapping; + + bool get isExitNode => range == '0.0.0.0/0'; +} + +enum DaemonLogLevel { unknown, panic, fatal, error, warn, info, debug, trace } + +class DebugBundleResult { + const DebugBundleResult({ + required this.path, + this.uploadedKey = '', + this.uploadFailureReason = '', + }); + + final String path; + final String uploadedKey; + final String uploadFailureReason; + + bool get uploaded => uploadedKey.isNotEmpty && uploadFailureReason.isEmpty; + bool get uploadFailed => uploadFailureReason.isNotEmpty; +} + +class TriggerUpdateResult { + const TriggerUpdateResult({required this.success, this.errorMessage = ''}); + + final bool success; + final String errorMessage; +} + +class InstallerResult { + const InstallerResult({required this.success, this.errorMessage = ''}); + + final bool success; + final String errorMessage; +} + +class UpdateProgressEvent { + const UpdateProgressEvent({required this.version}); + final String version; +} + +enum NotificationSeverity { info, warning, error, critical } + +enum NotificationCategory { + network, + dns, + authentication, + connectivity, + system; + + String get label { + return switch (this) { + NotificationCategory.network => 'Network', + NotificationCategory.dns => 'DNS', + NotificationCategory.authentication => 'Authentication', + NotificationCategory.connectivity => 'Connectivity', + NotificationCategory.system => 'System', + }; + } +} + +class SystemNotification { + const SystemNotification({ + required this.severity, + required this.category, + required this.message, + required this.userMessage, + this.id, + }); + + final NotificationSeverity severity; + final NotificationCategory category; + final String message; + final String userMessage; + final String? id; +} + +class ClientSettings { + const ClientSettings({ + this.managementUrl = 'https://api.netbird.io', + this.interfaceName = 'wt0', + this.wireguardPort = 51820, + this.mtu = 1280, + this.autoConnect = true, + this.allowSsh = false, + this.quantumResistance = false, + this.notifications = true, + this.lazyConnection = false, + this.blockInbound = false, + }); + + final String managementUrl; + final String interfaceName; + final int wireguardPort; + final int mtu; + final bool autoConnect; + final bool allowSsh; + final bool quantumResistance; + final bool notifications; + final bool lazyConnection; + final bool blockInbound; + + ClientSettings copyWith({ + String? managementUrl, + String? interfaceName, + int? wireguardPort, + int? mtu, + bool? autoConnect, + bool? allowSsh, + bool? quantumResistance, + bool? notifications, + bool? lazyConnection, + bool? blockInbound, + }) { + return ClientSettings( + managementUrl: managementUrl ?? this.managementUrl, + interfaceName: interfaceName ?? this.interfaceName, + wireguardPort: wireguardPort ?? this.wireguardPort, + mtu: mtu ?? this.mtu, + autoConnect: autoConnect ?? this.autoConnect, + allowSsh: allowSsh ?? this.allowSsh, + quantumResistance: quantumResistance ?? this.quantumResistance, + notifications: notifications ?? this.notifications, + lazyConnection: lazyConnection ?? this.lazyConnection, + blockInbound: blockInbound ?? this.blockInbound, + ); + } +} diff --git a/client/flutter_ui/lib/src/platform.dart b/client/flutter_ui/lib/src/platform.dart new file mode 100644 index 000000000..931e009e5 --- /dev/null +++ b/client/flutter_ui/lib/src/platform.dart @@ -0,0 +1,22 @@ +import 'dart:io'; + +/// Opens a URL in the user's default browser. Returns false if the platform +/// helper exits non-zero or is missing. Mirrors the Go UI's `openURL` logic. +Future openExternalUrl(String url) async { + try { + final ProcessResult result; + if (Platform.isMacOS) { + result = await Process.run('open', [url]); + } else if (Platform.isWindows) { + result = await Process.run('rundll32', [ + 'url.dll,FileProtocolHandler', + url, + ]); + } else { + result = await Process.run('xdg-open', [url]); + } + return result.exitCode == 0; + } catch (_) { + return false; + } +} diff --git a/client/flutter_ui/lib/src/update_progress.dart b/client/flutter_ui/lib/src/update_progress.dart new file mode 100644 index 000000000..81e80fc4a --- /dev/null +++ b/client/flutter_ui/lib/src/update_progress.dart @@ -0,0 +1,140 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; + +import 'daemon_client.dart'; +import 'models.dart'; + +const _allowCloseAfter = Duration(seconds: 10); +const _dotInterval = Duration(seconds: 1); + +/// Shows a modal dialog while the daemon installs an update. Polls +/// `GetInstallerResult` and resolves when the daemon finishes or fails. +Future showUpdateProgressDialog({ + required BuildContext context, + required DaemonClient client, + required UpdateProgressEvent event, +}) { + return showDialog( + context: context, + barrierDismissible: false, + builder: (context) => _UpdateProgressDialog(client: client, event: event), + ); +} + +class _UpdateProgressDialog extends StatefulWidget { + const _UpdateProgressDialog({required this.client, required this.event}); + + final DaemonClient client; + final UpdateProgressEvent event; + + @override + State<_UpdateProgressDialog> createState() => _UpdateProgressDialogState(); +} + +class _UpdateProgressDialogState extends State<_UpdateProgressDialog> { + Timer? _dotTimer; + Timer? _allowCloseTimer; + int _dots = 0; + bool _canClose = false; + String _status = 'Updating'; + String? _error; + bool _resolved = false; + + @override + void initState() { + super.initState(); + _dotTimer = Timer.periodic(_dotInterval, (_) => _tick()); + _allowCloseTimer = Timer(_allowCloseAfter, () { + if (mounted) { + setState(() => _canClose = true); + } + }); + unawaited(_pollInstaller()); + } + + @override + void dispose() { + _dotTimer?.cancel(); + _allowCloseTimer?.cancel(); + super.dispose(); + } + + void _tick() { + if (!mounted) { + return; + } + setState(() { + _dots = (_dots + 1) % 4; + _status = 'Updating${'.' * _dots}'; + }); + } + + Future _pollInstaller() async { + try { + final result = await widget.client.getInstallerResult(); + if (!mounted) { + return; + } + if (result.success) { + Navigator.of(context).pop(); + return; + } + setState(() { + _resolved = true; + _canClose = true; + _status = 'Update failed'; + _error = result.errorMessage.isEmpty + ? 'Unknown error' + : result.errorMessage; + }); + } catch (error) { + if (!mounted) { + return; + } + setState(() { + _resolved = true; + _canClose = true; + _status = 'Update timed out'; + _error = error.toString(); + }); + } + } + + @override + Widget build(BuildContext context) { + return PopScope( + canPop: _canClose, + child: AlertDialog( + title: const Text('Updating client'), + content: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Your client version is older than the auto-update version set in ' + 'Management.\nUpdating client to ${widget.event.version}.', + ), + const SizedBox(height: 16), + if (!_resolved) const LinearProgressIndicator(), + const SizedBox(height: 12), + Text(_status), + if (_error != null) ...[ + const SizedBox(height: 12), + Text( + _error!, + style: TextStyle(color: Theme.of(context).colorScheme.error), + ), + ], + ], + ), + actions: [ + TextButton( + onPressed: _canClose ? () => Navigator.of(context).pop() : null, + child: const Text('Close'), + ), + ], + ), + ); + } +} diff --git a/client/flutter_ui/linux/.gitignore b/client/flutter_ui/linux/.gitignore new file mode 100644 index 000000000..d3896c984 --- /dev/null +++ b/client/flutter_ui/linux/.gitignore @@ -0,0 +1 @@ +flutter/ephemeral diff --git a/client/flutter_ui/linux/CMakeLists.txt b/client/flutter_ui/linux/CMakeLists.txt new file mode 100644 index 000000000..e6552e203 --- /dev/null +++ b/client/flutter_ui/linux/CMakeLists.txt @@ -0,0 +1,128 @@ +# Project-level configuration. +cmake_minimum_required(VERSION 3.13) +project(runner LANGUAGES CXX) + +# The name of the executable created for the application. Change this to change +# the on-disk name of your application. +set(BINARY_NAME "netbird_flutter_ui") +# The unique GTK application identifier for this application. See: +# https://wiki.gnome.org/HowDoI/ChooseApplicationID +set(APPLICATION_ID "io.netbird.netbird_flutter_ui") + +# Explicitly opt in to modern CMake behaviors to avoid warnings with recent +# versions of CMake. +cmake_policy(SET CMP0063 NEW) + +# Load bundled libraries from the lib/ directory relative to the binary. +set(CMAKE_INSTALL_RPATH "$ORIGIN/lib") + +# Root filesystem for cross-building. +if(FLUTTER_TARGET_PLATFORM_SYSROOT) + set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT}) + set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT}) + set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) + set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) + set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) + set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +endif() + +# Define build configuration options. +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE "Debug" CACHE + STRING "Flutter build mode" FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Profile" "Release") +endif() + +# Compilation settings that should be applied to most targets. +# +# Be cautious about adding new options here, as plugins use this function by +# default. In most cases, you should add new options to specific targets instead +# of modifying this function. +function(APPLY_STANDARD_SETTINGS TARGET) + target_compile_features(${TARGET} PUBLIC cxx_std_14) + target_compile_options(${TARGET} PRIVATE -Wall -Werror) + target_compile_options(${TARGET} PRIVATE "$<$>:-O3>") + target_compile_definitions(${TARGET} PRIVATE "$<$>:NDEBUG>") +endfunction() + +# Flutter library and tool build rules. +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) + +# Application build; see runner/CMakeLists.txt. +add_subdirectory("runner") + +# Run the Flutter tool portions of the build. This must not be removed. +add_dependencies(${BINARY_NAME} flutter_assemble) + +# Only the install-generated bundle's copy of the executable will launch +# correctly, since the resources must in the right relative locations. To avoid +# people trying to run the unbundled copy, put it in a subdirectory instead of +# the default top-level location. +set_target_properties(${BINARY_NAME} + PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run" +) + + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) + + +# === Installation === +# By default, "installing" just makes a relocatable bundle in the build +# directory. +set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle") +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) +endif() + +# Start with a clean build bundle directory every time. +install(CODE " + file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\") + " COMPONENT Runtime) + +set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") +set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib") + +install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES}) + install(FILES "${bundled_library}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endforeach(bundled_library) + +# Copy the native assets provided by the build.dart from all packages. +set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/linux/") +install(DIRECTORY "${NATIVE_ASSETS_DIR}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +# Fully re-copy the assets directory on each build to avoid having stale files +# from a previous install. +set(FLUTTER_ASSET_DIR_NAME "flutter_assets") +install(CODE " + file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") + " COMPONENT Runtime) +install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" + DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) + +# Install the AOT library on non-Debug builds only. +if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") + install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() diff --git a/client/flutter_ui/linux/flutter/CMakeLists.txt b/client/flutter_ui/linux/flutter/CMakeLists.txt new file mode 100644 index 000000000..d5bd01648 --- /dev/null +++ b/client/flutter_ui/linux/flutter/CMakeLists.txt @@ -0,0 +1,88 @@ +# This file controls Flutter-level build steps. It should not be edited. +cmake_minimum_required(VERSION 3.10) + +set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") + +# Configuration provided via flutter tool. +include(${EPHEMERAL_DIR}/generated_config.cmake) + +# TODO: Move the rest of this into files in ephemeral. See +# https://github.com/flutter/flutter/issues/57146. + +# Serves the same purpose as list(TRANSFORM ... PREPEND ...), +# which isn't available in 3.10. +function(list_prepend LIST_NAME PREFIX) + set(NEW_LIST "") + foreach(element ${${LIST_NAME}}) + list(APPEND NEW_LIST "${PREFIX}${element}") + endforeach(element) + set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE) +endfunction() + +# === Flutter Library === +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) +pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) +pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) + +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so") + +# Published to parent scope for install step. +set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) +set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) +set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) +set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "fl_basic_message_channel.h" + "fl_binary_codec.h" + "fl_binary_messenger.h" + "fl_dart_project.h" + "fl_engine.h" + "fl_json_message_codec.h" + "fl_json_method_codec.h" + "fl_message_codec.h" + "fl_method_call.h" + "fl_method_channel.h" + "fl_method_codec.h" + "fl_method_response.h" + "fl_plugin_registrar.h" + "fl_plugin_registry.h" + "fl_standard_message_codec.h" + "fl_standard_method_codec.h" + "fl_string_codec.h" + "fl_value.h" + "fl_view.h" + "flutter_linux.h" +) +list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}") +target_link_libraries(flutter INTERFACE + PkgConfig::GTK + PkgConfig::GLIB + PkgConfig::GIO +) +add_dependencies(flutter flutter_assemble) + +# === Flutter tool backend === +# _phony_ is a non-existent file to force this command to run every time, +# since currently there's no way to get a full input/output list from the +# flutter tool. +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CMAKE_CURRENT_BINARY_DIR}/_phony_ + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh" + ${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE} + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} +) diff --git a/client/flutter_ui/linux/flutter/generated_plugin_registrant.cc b/client/flutter_ui/linux/flutter/generated_plugin_registrant.cc new file mode 100644 index 000000000..f3c8c8825 --- /dev/null +++ b/client/flutter_ui/linux/flutter/generated_plugin_registrant.cc @@ -0,0 +1,27 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + +#include +#include +#include +#include + +void fl_register_plugins(FlPluginRegistry* registry) { + g_autoptr(FlPluginRegistrar) local_notifier_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "LocalNotifierPlugin"); + local_notifier_plugin_register_with_registrar(local_notifier_registrar); + g_autoptr(FlPluginRegistrar) screen_retriever_linux_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "ScreenRetrieverLinuxPlugin"); + screen_retriever_linux_plugin_register_with_registrar(screen_retriever_linux_registrar); + g_autoptr(FlPluginRegistrar) tray_manager_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "TrayManagerPlugin"); + tray_manager_plugin_register_with_registrar(tray_manager_registrar); + g_autoptr(FlPluginRegistrar) window_manager_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "WindowManagerPlugin"); + window_manager_plugin_register_with_registrar(window_manager_registrar); +} diff --git a/client/flutter_ui/linux/flutter/generated_plugin_registrant.h b/client/flutter_ui/linux/flutter/generated_plugin_registrant.h new file mode 100644 index 000000000..e0f0a47bc --- /dev/null +++ b/client/flutter_ui/linux/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void fl_register_plugins(FlPluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/client/flutter_ui/linux/flutter/generated_plugins.cmake b/client/flutter_ui/linux/flutter/generated_plugins.cmake new file mode 100644 index 000000000..ae9d73fcd --- /dev/null +++ b/client/flutter_ui/linux/flutter/generated_plugins.cmake @@ -0,0 +1,27 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST + local_notifier + screen_retriever_linux + tray_manager + window_manager +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) +endforeach(plugin) + +foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/client/flutter_ui/linux/runner/CMakeLists.txt b/client/flutter_ui/linux/runner/CMakeLists.txt new file mode 100644 index 000000000..e97dabc70 --- /dev/null +++ b/client/flutter_ui/linux/runner/CMakeLists.txt @@ -0,0 +1,26 @@ +cmake_minimum_required(VERSION 3.13) +project(runner LANGUAGES CXX) + +# Define the application target. To change its name, change BINARY_NAME in the +# top-level CMakeLists.txt, not the value here, or `flutter run` will no longer +# work. +# +# Any new source files that you add to the application should be added here. +add_executable(${BINARY_NAME} + "main.cc" + "my_application.cc" + "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" +) + +# Apply the standard set of build settings. This can be removed for applications +# that need different build settings. +apply_standard_settings(${BINARY_NAME}) + +# Add preprocessor definitions for the application ID. +add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") + +# Add dependency libraries. Add any application-specific dependencies here. +target_link_libraries(${BINARY_NAME} PRIVATE flutter) +target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) + +target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") diff --git a/client/flutter_ui/linux/runner/main.cc b/client/flutter_ui/linux/runner/main.cc new file mode 100644 index 000000000..e7c5c5437 --- /dev/null +++ b/client/flutter_ui/linux/runner/main.cc @@ -0,0 +1,6 @@ +#include "my_application.h" + +int main(int argc, char** argv) { + g_autoptr(MyApplication) app = my_application_new(); + return g_application_run(G_APPLICATION(app), argc, argv); +} diff --git a/client/flutter_ui/linux/runner/my_application.cc b/client/flutter_ui/linux/runner/my_application.cc new file mode 100644 index 000000000..fa5dbd1ed --- /dev/null +++ b/client/flutter_ui/linux/runner/my_application.cc @@ -0,0 +1,148 @@ +#include "my_application.h" + +#include +#ifdef GDK_WINDOWING_X11 +#include +#endif + +#include "flutter/generated_plugin_registrant.h" + +struct _MyApplication { + GtkApplication parent_instance; + char** dart_entrypoint_arguments; +}; + +G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) + +// Called when first Flutter frame received. +static void first_frame_cb(MyApplication* self, FlView* view) { + gtk_widget_show(gtk_widget_get_toplevel(GTK_WIDGET(view))); +} + +// Implements GApplication::activate. +static void my_application_activate(GApplication* application) { + MyApplication* self = MY_APPLICATION(application); + GtkWindow* window = + GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application))); + + // Use a header bar when running in GNOME as this is the common style used + // by applications and is the setup most users will be using (e.g. Ubuntu + // desktop). + // If running on X and not using GNOME then just use a traditional title bar + // in case the window manager does more exotic layout, e.g. tiling. + // If running on Wayland assume the header bar will work (may need changing + // if future cases occur). + gboolean use_header_bar = TRUE; +#ifdef GDK_WINDOWING_X11 + GdkScreen* screen = gtk_window_get_screen(window); + if (GDK_IS_X11_SCREEN(screen)) { + const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen); + if (g_strcmp0(wm_name, "GNOME Shell") != 0) { + use_header_bar = FALSE; + } + } +#endif + if (use_header_bar) { + GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); + gtk_widget_show(GTK_WIDGET(header_bar)); + gtk_header_bar_set_title(header_bar, "netbird_flutter_ui"); + gtk_header_bar_set_show_close_button(header_bar, TRUE); + gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); + } else { + gtk_window_set_title(window, "netbird_flutter_ui"); + } + + gtk_window_set_default_size(window, 1280, 720); + + g_autoptr(FlDartProject) project = fl_dart_project_new(); + fl_dart_project_set_dart_entrypoint_arguments( + project, self->dart_entrypoint_arguments); + + FlView* view = fl_view_new(project); + GdkRGBA background_color; + // Background defaults to black, override it here if necessary, e.g. #00000000 + // for transparent. + gdk_rgba_parse(&background_color, "#000000"); + fl_view_set_background_color(view, &background_color); + gtk_widget_show(GTK_WIDGET(view)); + gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); + + // Show the window when Flutter renders. + // Requires the view to be realized so we can start rendering. + g_signal_connect_swapped(view, "first-frame", G_CALLBACK(first_frame_cb), + self); + gtk_widget_realize(GTK_WIDGET(view)); + + fl_register_plugins(FL_PLUGIN_REGISTRY(view)); + + gtk_widget_grab_focus(GTK_WIDGET(view)); +} + +// Implements GApplication::local_command_line. +static gboolean my_application_local_command_line(GApplication* application, + gchar*** arguments, + int* exit_status) { + MyApplication* self = MY_APPLICATION(application); + // Strip out the first argument as it is the binary name. + self->dart_entrypoint_arguments = g_strdupv(*arguments + 1); + + g_autoptr(GError) error = nullptr; + if (!g_application_register(application, nullptr, &error)) { + g_warning("Failed to register: %s", error->message); + *exit_status = 1; + return TRUE; + } + + g_application_activate(application); + *exit_status = 0; + + return TRUE; +} + +// Implements GApplication::startup. +static void my_application_startup(GApplication* application) { + // MyApplication* self = MY_APPLICATION(object); + + // Perform any actions required at application startup. + + G_APPLICATION_CLASS(my_application_parent_class)->startup(application); +} + +// Implements GApplication::shutdown. +static void my_application_shutdown(GApplication* application) { + // MyApplication* self = MY_APPLICATION(object); + + // Perform any actions required at application shutdown. + + G_APPLICATION_CLASS(my_application_parent_class)->shutdown(application); +} + +// Implements GObject::dispose. +static void my_application_dispose(GObject* object) { + MyApplication* self = MY_APPLICATION(object); + g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev); + G_OBJECT_CLASS(my_application_parent_class)->dispose(object); +} + +static void my_application_class_init(MyApplicationClass* klass) { + G_APPLICATION_CLASS(klass)->activate = my_application_activate; + G_APPLICATION_CLASS(klass)->local_command_line = + my_application_local_command_line; + G_APPLICATION_CLASS(klass)->startup = my_application_startup; + G_APPLICATION_CLASS(klass)->shutdown = my_application_shutdown; + G_OBJECT_CLASS(klass)->dispose = my_application_dispose; +} + +static void my_application_init(MyApplication* self) {} + +MyApplication* my_application_new() { + // Set the program name to the application ID, which helps various systems + // like GTK and desktop environments map this running application to its + // corresponding .desktop file. This ensures better integration by allowing + // the application to be recognized beyond its binary name. + g_set_prgname(APPLICATION_ID); + + return MY_APPLICATION(g_object_new(my_application_get_type(), + "application-id", APPLICATION_ID, "flags", + G_APPLICATION_NON_UNIQUE, nullptr)); +} diff --git a/client/flutter_ui/linux/runner/my_application.h b/client/flutter_ui/linux/runner/my_application.h new file mode 100644 index 000000000..db16367a7 --- /dev/null +++ b/client/flutter_ui/linux/runner/my_application.h @@ -0,0 +1,21 @@ +#ifndef FLUTTER_MY_APPLICATION_H_ +#define FLUTTER_MY_APPLICATION_H_ + +#include + +G_DECLARE_FINAL_TYPE(MyApplication, + my_application, + MY, + APPLICATION, + GtkApplication) + +/** + * my_application_new: + * + * Creates a new Flutter-based application. + * + * Returns: a new #MyApplication. + */ +MyApplication* my_application_new(); + +#endif // FLUTTER_MY_APPLICATION_H_ diff --git a/client/flutter_ui/macos/.gitignore b/client/flutter_ui/macos/.gitignore new file mode 100644 index 000000000..746adbb6b --- /dev/null +++ b/client/flutter_ui/macos/.gitignore @@ -0,0 +1,7 @@ +# Flutter-related +**/Flutter/ephemeral/ +**/Pods/ + +# Xcode-related +**/dgph +**/xcuserdata/ diff --git a/client/flutter_ui/macos/Flutter/Flutter-Debug.xcconfig b/client/flutter_ui/macos/Flutter/Flutter-Debug.xcconfig new file mode 100644 index 000000000..4b81f9b2d --- /dev/null +++ b/client/flutter_ui/macos/Flutter/Flutter-Debug.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/client/flutter_ui/macos/Flutter/Flutter-Release.xcconfig b/client/flutter_ui/macos/Flutter/Flutter-Release.xcconfig new file mode 100644 index 000000000..5caa9d157 --- /dev/null +++ b/client/flutter_ui/macos/Flutter/Flutter-Release.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/client/flutter_ui/macos/Flutter/GeneratedPluginRegistrant.swift b/client/flutter_ui/macos/Flutter/GeneratedPluginRegistrant.swift new file mode 100644 index 000000000..17b0d5c9c --- /dev/null +++ b/client/flutter_ui/macos/Flutter/GeneratedPluginRegistrant.swift @@ -0,0 +1,18 @@ +// +// Generated file. Do not edit. +// + +import FlutterMacOS +import Foundation + +import local_notifier +import screen_retriever_macos +import tray_manager +import window_manager + +func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + LocalNotifierPlugin.register(with: registry.registrar(forPlugin: "LocalNotifierPlugin")) + ScreenRetrieverMacosPlugin.register(with: registry.registrar(forPlugin: "ScreenRetrieverMacosPlugin")) + TrayManagerPlugin.register(with: registry.registrar(forPlugin: "TrayManagerPlugin")) + WindowManagerPlugin.register(with: registry.registrar(forPlugin: "WindowManagerPlugin")) +} diff --git a/client/flutter_ui/macos/Podfile b/client/flutter_ui/macos/Podfile new file mode 100644 index 000000000..ff5ddb3b8 --- /dev/null +++ b/client/flutter_ui/macos/Podfile @@ -0,0 +1,42 @@ +platform :osx, '10.15' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\"" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_macos_podfile_setup + +target 'Runner' do + use_frameworks! + + flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) + target 'RunnerTests' do + inherit! :search_paths + end +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_macos_build_settings(target) + end +end diff --git a/client/flutter_ui/macos/Podfile.lock b/client/flutter_ui/macos/Podfile.lock new file mode 100644 index 000000000..4dfc3baef --- /dev/null +++ b/client/flutter_ui/macos/Podfile.lock @@ -0,0 +1,40 @@ +PODS: + - FlutterMacOS (1.0.0) + - local_notifier (0.1.0): + - FlutterMacOS + - screen_retriever_macos (0.0.1): + - FlutterMacOS + - tray_manager (0.0.1): + - FlutterMacOS + - window_manager (0.5.0): + - FlutterMacOS + +DEPENDENCIES: + - FlutterMacOS (from `Flutter/ephemeral`) + - local_notifier (from `Flutter/ephemeral/.symlinks/plugins/local_notifier/macos`) + - screen_retriever_macos (from `Flutter/ephemeral/.symlinks/plugins/screen_retriever_macos/macos`) + - tray_manager (from `Flutter/ephemeral/.symlinks/plugins/tray_manager/macos`) + - window_manager (from `Flutter/ephemeral/.symlinks/plugins/window_manager/macos`) + +EXTERNAL SOURCES: + FlutterMacOS: + :path: Flutter/ephemeral + local_notifier: + :path: Flutter/ephemeral/.symlinks/plugins/local_notifier/macos + screen_retriever_macos: + :path: Flutter/ephemeral/.symlinks/plugins/screen_retriever_macos/macos + tray_manager: + :path: Flutter/ephemeral/.symlinks/plugins/tray_manager/macos + window_manager: + :path: Flutter/ephemeral/.symlinks/plugins/window_manager/macos + +SPEC CHECKSUMS: + FlutterMacOS: d0db08ddef1a9af05a5ec4b724367152bb0500b1 + local_notifier: ebf072651e35ae5e47280ad52e2707375cb2ae4e + screen_retriever_macos: 452e51764a9e1cdb74b3c541238795849f21557f + tray_manager: a104b5c81b578d83f3c3d0f40a997c8b10810166 + window_manager: b729e31d38fb04905235df9ea896128991cad99e + +PODFILE CHECKSUM: 54d867c82ac51cbd61b565781b9fada492027009 + +COCOAPODS: 1.16.2 diff --git a/client/flutter_ui/macos/Runner.xcodeproj/project.pbxproj b/client/flutter_ui/macos/Runner.xcodeproj/project.pbxproj new file mode 100644 index 000000000..6edaedf27 --- /dev/null +++ b/client/flutter_ui/macos/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,801 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXAggregateTarget section */ + 33CC111A2044C6BA0003C045 /* Flutter Assemble */ = { + isa = PBXAggregateTarget; + buildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */; + buildPhases = ( + 33CC111E2044C6BF0003C045 /* ShellScript */, + ); + dependencies = ( + ); + name = "Flutter Assemble"; + productName = FLX; + }; +/* End PBXAggregateTarget section */ + +/* Begin PBXBuildFile section */ + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C80D7294CF71000263BE5 /* RunnerTests.swift */; }; + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; }; + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; }; + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; + 5F10F38F17483368E6B26C16 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2D1C698E330CDD6D9457E84F /* Pods_RunnerTests.framework */; }; + 6E2193E107D1C306C0B38295 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AA24562430C7E3798566E220 /* Pods_Runner.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC10EC2044A3C60003C045; + remoteInfo = Runner; + }; + 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC111A2044C6BA0003C045; + remoteInfo = FLX; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 33CC110E2044A8840003C045 /* Bundle Framework */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Bundle Framework"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 14CA49126DC810A7FD8021C0 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; + 2D1C698E330CDD6D9457E84F /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; + 33CC10ED2044A3C60003C045 /* netbird_flutter_ui.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = netbird_flutter_ui.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; + 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; + 33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = ""; }; + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = ""; }; + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = ""; }; + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = ""; }; + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = ""; }; + 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; + 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; + 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; + 3B081925C026B73446CD514F /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; + 5344037698CB477EF6AE75A3 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; + 97BFF106FF1D50C0EF3C4AF6 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; + AA24562430C7E3798566E220 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + E69F59E3113C82C71F7A2757 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + EB350F2E61DA77DD3D20E0EB /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 331C80D2294CF70F00263BE5 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 5F10F38F17483368E6B26C16 /* Pods_RunnerTests.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10EA2044A3C60003C045 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 6E2193E107D1C306C0B38295 /* Pods_Runner.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 16123F31EB7196617B509F9C /* Pods */ = { + isa = PBXGroup; + children = ( + 5344037698CB477EF6AE75A3 /* Pods-Runner.debug.xcconfig */, + E69F59E3113C82C71F7A2757 /* Pods-Runner.release.xcconfig */, + EB350F2E61DA77DD3D20E0EB /* Pods-Runner.profile.xcconfig */, + 97BFF106FF1D50C0EF3C4AF6 /* Pods-RunnerTests.debug.xcconfig */, + 3B081925C026B73446CD514F /* Pods-RunnerTests.release.xcconfig */, + 14CA49126DC810A7FD8021C0 /* Pods-RunnerTests.profile.xcconfig */, + ); + name = Pods; + path = Pods; + sourceTree = ""; + }; + 331C80D6294CF71000263BE5 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 331C80D7294CF71000263BE5 /* RunnerTests.swift */, + ); + path = RunnerTests; + sourceTree = ""; + }; + 33BA886A226E78AF003329D5 /* Configs */ = { + isa = PBXGroup; + children = ( + 33E5194F232828860026EE4D /* AppInfo.xcconfig */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */, + ); + path = Configs; + sourceTree = ""; + }; + 33CC10E42044A3C60003C045 = { + isa = PBXGroup; + children = ( + 33FAB671232836740065AC1E /* Runner */, + 33CEB47122A05771004F2AC0 /* Flutter */, + 331C80D6294CF71000263BE5 /* RunnerTests */, + 33CC10EE2044A3C60003C045 /* Products */, + D73912EC22F37F3D000D13A0 /* Frameworks */, + 16123F31EB7196617B509F9C /* Pods */, + ); + sourceTree = ""; + }; + 33CC10EE2044A3C60003C045 /* Products */ = { + isa = PBXGroup; + children = ( + 33CC10ED2044A3C60003C045 /* netbird_flutter_ui.app */, + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 33CC11242044D66E0003C045 /* Resources */ = { + isa = PBXGroup; + children = ( + 33CC10F22044A3C60003C045 /* Assets.xcassets */, + 33CC10F42044A3C60003C045 /* MainMenu.xib */, + 33CC10F72044A3C60003C045 /* Info.plist */, + ); + name = Resources; + path = ..; + sourceTree = ""; + }; + 33CEB47122A05771004F2AC0 /* Flutter */ = { + isa = PBXGroup; + children = ( + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */, + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */, + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */, + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */, + ); + path = Flutter; + sourceTree = ""; + }; + 33FAB671232836740065AC1E /* Runner */ = { + isa = PBXGroup; + children = ( + 33CC10F02044A3C60003C045 /* AppDelegate.swift */, + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */, + 33E51913231747F40026EE4D /* DebugProfile.entitlements */, + 33E51914231749380026EE4D /* Release.entitlements */, + 33CC11242044D66E0003C045 /* Resources */, + 33BA886A226E78AF003329D5 /* Configs */, + ); + path = Runner; + sourceTree = ""; + }; + D73912EC22F37F3D000D13A0 /* Frameworks */ = { + isa = PBXGroup; + children = ( + AA24562430C7E3798566E220 /* Pods_Runner.framework */, + 2D1C698E330CDD6D9457E84F /* Pods_RunnerTests.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 331C80D4294CF70F00263BE5 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + 13F875F4B0174355038870C8 /* [CP] Check Pods Manifest.lock */, + 331C80D1294CF70F00263BE5 /* Sources */, + 331C80D2294CF70F00263BE5 /* Frameworks */, + 331C80D3294CF70F00263BE5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 331C80DA294CF71000263BE5 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = 331C80D5294CF71000263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 33CC10EC2044A3C60003C045 /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 6D776BDDAB33DFA32528CFE2 /* [CP] Check Pods Manifest.lock */, + 33CC10E92044A3C60003C045 /* Sources */, + 33CC10EA2044A3C60003C045 /* Frameworks */, + 33CC10EB2044A3C60003C045 /* Resources */, + 33CC110E2044A8840003C045 /* Bundle Framework */, + 3399D490228B24CF009A79C7 /* ShellScript */, + DF9F03510A6543FA652C823E /* [CP] Embed Pods Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + 33CC11202044C79F0003C045 /* PBXTargetDependency */, + ); + name = Runner; + productName = Runner; + productReference = 33CC10ED2044A3C60003C045 /* netbird_flutter_ui.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 33CC10E52044A3C60003C045 /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = YES; + LastSwiftUpdateCheck = 0920; + LastUpgradeCheck = 1510; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 331C80D4294CF70F00263BE5 = { + CreatedOnToolsVersion = 14.0; + TestTargetID = 33CC10EC2044A3C60003C045; + }; + 33CC10EC2044A3C60003C045 = { + CreatedOnToolsVersion = 9.2; + LastSwiftMigration = 1100; + ProvisioningStyle = Automatic; + SystemCapabilities = { + com.apple.Sandbox = { + enabled = 1; + }; + }; + }; + 33CC111A2044C6BA0003C045 = { + CreatedOnToolsVersion = 9.2; + ProvisioningStyle = Manual; + }; + }; + }; + buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 33CC10E42044A3C60003C045; + productRefGroup = 33CC10EE2044A3C60003C045 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 33CC10EC2044A3C60003C045 /* Runner */, + 331C80D4294CF70F00263BE5 /* RunnerTests */, + 33CC111A2044C6BA0003C045 /* Flutter Assemble */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 331C80D3294CF70F00263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10EB2044A3C60003C045 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */, + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 13F875F4B0174355038870C8 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + 3399D490228B24CF009A79C7 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n"; + }; + 33CC111E2044C6BF0003C045 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + Flutter/ephemeral/FlutterInputs.xcfilelist, + ); + inputPaths = ( + Flutter/ephemeral/tripwire, + ); + outputFileListPaths = ( + Flutter/ephemeral/FlutterOutputs.xcfilelist, + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; + }; + 6D776BDDAB33DFA32528CFE2 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + DF9F03510A6543FA652C823E /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 331C80D1294CF70F00263BE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10E92044A3C60003C045 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */, + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */, + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 331C80DA294CF71000263BE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC10EC2044A3C60003C045 /* Runner */; + targetProxy = 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */; + }; + 33CC11202044C79F0003C045 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */; + targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 33CC10F42044A3C60003C045 /* MainMenu.xib */ = { + isa = PBXVariantGroup; + children = ( + 33CC10F52044A3C60003C045 /* Base */, + ); + name = MainMenu.xib; + path = Runner; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 331C80DB294CF71000263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 97BFF106FF1D50C0EF3C4AF6 /* Pods-RunnerTests.debug.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = io.netbird.netbirdFlutterUi.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/netbird_flutter_ui.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/netbird_flutter_ui"; + }; + name = Debug; + }; + 331C80DC294CF71000263BE5 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 3B081925C026B73446CD514F /* Pods-RunnerTests.release.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = io.netbird.netbirdFlutterUi.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/netbird_flutter_ui.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/netbird_flutter_ui"; + }; + name = Release; + }; + 331C80DD294CF71000263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 14CA49126DC810A7FD8021C0 /* Pods-RunnerTests.profile.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = io.netbird.netbirdFlutterUi.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/netbird_flutter_ui.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/netbird_flutter_ui"; + }; + name = Profile; + }; + 338D0CE9231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.15; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Profile; + }; + 338D0CEA231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Profile; + }; + 338D0CEB231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Profile; + }; + 33CC10F92044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.15; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 33CC10FA2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.15; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Release; + }; + 33CC10FC2044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 33CC10FD2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; + 33CC111C2044C6BA0003C045 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 33CC111D2044C6BA0003C045 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 331C80DB294CF71000263BE5 /* Debug */, + 331C80DC294CF71000263BE5 /* Release */, + 331C80DD294CF71000263BE5 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10F92044A3C60003C045 /* Debug */, + 33CC10FA2044A3C60003C045 /* Release */, + 338D0CE9231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10FC2044A3C60003C045 /* Debug */, + 33CC10FD2044A3C60003C045 /* Release */, + 338D0CEA231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC111C2044C6BA0003C045 /* Debug */, + 33CC111D2044C6BA0003C045 /* Release */, + 338D0CEB231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 33CC10E52044A3C60003C045 /* Project object */; +} diff --git a/client/flutter_ui/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/client/flutter_ui/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/client/flutter_ui/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/client/flutter_ui/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/client/flutter_ui/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 000000000..934e68713 --- /dev/null +++ b/client/flutter_ui/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/client/flutter_ui/macos/Runner.xcworkspace/contents.xcworkspacedata b/client/flutter_ui/macos/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..21a3cc14c --- /dev/null +++ b/client/flutter_ui/macos/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/client/flutter_ui/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/client/flutter_ui/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/client/flutter_ui/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/client/flutter_ui/macos/Runner/AppDelegate.swift b/client/flutter_ui/macos/Runner/AppDelegate.swift new file mode 100644 index 000000000..b3c176141 --- /dev/null +++ b/client/flutter_ui/macos/Runner/AppDelegate.swift @@ -0,0 +1,13 @@ +import Cocoa +import FlutterMacOS + +@main +class AppDelegate: FlutterAppDelegate { + override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { + return true + } + + override func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool { + return true + } +} diff --git a/client/flutter_ui/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/client/flutter_ui/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 000000000..a2ec33f19 --- /dev/null +++ b/client/flutter_ui/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,68 @@ +{ + "images" : [ + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_16.png", + "scale" : "1x" + }, + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "2x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "1x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_64.png", + "scale" : "2x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_128.png", + "scale" : "1x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "2x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "1x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "2x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "1x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_1024.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/client/flutter_ui/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png b/client/flutter_ui/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png new file mode 100644 index 0000000000000000000000000000000000000000..82b6f9d9a33e198f5747104729e1fcef999772a5 GIT binary patch literal 102994 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ⅅ8MglG&ER{i5lN315cO?EdHNLrg? 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 z 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 Pe7HEdAEg|=c=LY&YVNkY literal 0 HcmV?d00001 diff --git a/client/flutter_ui/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png b/client/flutter_ui/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png new file mode 100644 index 0000000000000000000000000000000000000000..13b35eba55c6dabc3aac36f33d859266c18fa0d0 GIT binary patch literal 5680 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 literal 0 HcmV?d00001 diff --git a/client/flutter_ui/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png b/client/flutter_ui/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png new file mode 100644 index 0000000000000000000000000000000000000000..0a3f5fa40fb3d1e0710331a48de5d256da3f275d GIT binary patch literal 520 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 literal 0 HcmV?d00001 diff --git a/client/flutter_ui/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png b/client/flutter_ui/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png new file mode 100644 index 0000000000000000000000000000000000000000..2f1632cfddf3d9dade342351e627a0a75609fb46 GIT binary patch literal 2218 zcmV;b2vzrqP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91K%fHv1ONa40RR91KmY&$07g+lumAuE6iGxuRCodHTWf3-RTMruyW6Fu zQYeUM04eX6D5c0FCjKKPrco1(K`<0SL=crI{PC3-^hZU0kQie$gh-5!7z6SH6Q0J% zqot*`H1q{R5fHFYS}dje@;kG=v$L0(yY0?wY2%*c?A&{2?!D*x?m71{of2gv!$5|C z3>qG_BW}7K_yUcT3A5C6QD<+{aq?x;MAUyAiJn#Jv8_zZtQ{P zTRzbL3U9!qVuZzS$xKU10KiW~Bgdcv1-!uAhQxf3a7q+dU6lj?yoO4Lq4TUN4}h{N z*fIM=SS8|C2$(T>w$`t@3Tka!(r!7W`x z-isCVgQD^mG-MJ;XtJuK3V{Vy72GQ83KRWsHU?e*wrhKk=ApIYeDqLi;JI1e zuvv}5^Dc=k7F7?nm3nIw$NVmU-+R>> zyqOR$-2SDpJ}Pt;^RkJytDVXNTsu|mI1`~G7yw`EJR?VkGfNdqK9^^8P`JdtTV&tX4CNcV4 z&N06nZa??Fw1AgQOUSE2AmPE@WO(Fvo`%m`cDgiv(fAeRA%3AGXUbsGw{7Q`cY;1BI#ac3iN$$Hw z0LT0;xc%=q)me?Y*$xI@GRAw?+}>=9D+KTk??-HJ4=A>`V&vKFS75@MKdSF1JTq{S zc1!^8?YA|t+uKigaq!sT;Z!&0F2=k7F0PIU;F$leJLaw2UI6FL^w}OG&!;+b%ya1c z1n+6-inU<0VM-Y_s5iTElq)ThyF?StVcebpGI znw#+zLx2@ah{$_2jn+@}(zJZ{+}_N9BM;z)0yr|gF-4=Iyu@hI*Lk=-A8f#bAzc9f z`Kd6K--x@t04swJVC3JK1cHY-Hq+=|PN-VO;?^_C#;coU6TDP7Bt`;{JTG;!+jj(` zw5cLQ-(Cz-Tlb`A^w7|R56Ce;Wmr0)$KWOUZ6ai0PhzPeHwdl0H(etP zUV`va_i0s-4#DkNM8lUlqI7>YQLf)(lz9Q3Uw`)nc(z3{m5ZE77Ul$V%m)E}3&8L0 z-XaU|eB~Is08eORPk;=<>!1w)Kf}FOVS2l&9~A+@R#koFJ$Czd%Y(ENTV&A~U(IPI z;UY+gf+&6ioZ=roly<0Yst8ck>(M=S?B-ys3mLdM&)ex!hbt+ol|T6CTS+Sc0jv(& z7ijdvFwBq;0a{%3GGwkDKTeG`b+lyj0jjS1OMkYnepCdoosNY`*zmBIo*981BU%%U z@~$z0V`OVtIbEx5pa|Tct|Lg#ZQf5OYMUMRD>Wdxm5SAqV2}3!ceE-M2 z@O~lQ0OiKQp}o9I;?uxCgYVV?FH|?Riri*U$Zi_`V2eiA>l zdSm6;SEm6#T+SpcE8Ro_f2AwxzI z44hfe^WE3!h@W3RDyA_H440cpmYkv*)6m1XazTqw%=E5Xv7^@^^T7Q2wxr+Z2kVYr + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/client/flutter_ui/macos/Runner/Configs/AppInfo.xcconfig b/client/flutter_ui/macos/Runner/Configs/AppInfo.xcconfig new file mode 100644 index 000000000..554dca22f --- /dev/null +++ b/client/flutter_ui/macos/Runner/Configs/AppInfo.xcconfig @@ -0,0 +1,14 @@ +// Application-level settings for the Runner target. +// +// This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the +// future. If not, the values below would default to using the project name when this becomes a +// 'flutter create' template. + +// The application's name. By default this is also the title of the Flutter window. +PRODUCT_NAME = netbird_flutter_ui + +// The application's bundle identifier +PRODUCT_BUNDLE_IDENTIFIER = io.netbird.netbirdFlutterUi + +// The copyright displayed in application information +PRODUCT_COPYRIGHT = Copyright © 2026 io.netbird. All rights reserved. diff --git a/client/flutter_ui/macos/Runner/Configs/Debug.xcconfig b/client/flutter_ui/macos/Runner/Configs/Debug.xcconfig new file mode 100644 index 000000000..36b0fd946 --- /dev/null +++ b/client/flutter_ui/macos/Runner/Configs/Debug.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Debug.xcconfig" +#include "Warnings.xcconfig" diff --git a/client/flutter_ui/macos/Runner/Configs/Release.xcconfig b/client/flutter_ui/macos/Runner/Configs/Release.xcconfig new file mode 100644 index 000000000..dff4f4956 --- /dev/null +++ b/client/flutter_ui/macos/Runner/Configs/Release.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Release.xcconfig" +#include "Warnings.xcconfig" diff --git a/client/flutter_ui/macos/Runner/Configs/Warnings.xcconfig b/client/flutter_ui/macos/Runner/Configs/Warnings.xcconfig new file mode 100644 index 000000000..42bcbf478 --- /dev/null +++ b/client/flutter_ui/macos/Runner/Configs/Warnings.xcconfig @@ -0,0 +1,13 @@ +WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings +GCC_WARN_UNDECLARED_SELECTOR = YES +CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES +CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE +CLANG_WARN__DUPLICATE_METHOD_MATCH = YES +CLANG_WARN_PRAGMA_PACK = YES +CLANG_WARN_STRICT_PROTOTYPES = YES +CLANG_WARN_COMMA = YES +GCC_WARN_STRICT_SELECTOR_MATCH = YES +CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES +CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES +GCC_WARN_SHADOW = YES +CLANG_WARN_UNREACHABLE_CODE = YES diff --git a/client/flutter_ui/macos/Runner/DebugProfile.entitlements b/client/flutter_ui/macos/Runner/DebugProfile.entitlements new file mode 100644 index 000000000..5d82b3df0 --- /dev/null +++ b/client/flutter_ui/macos/Runner/DebugProfile.entitlements @@ -0,0 +1,12 @@ + + + + + com.apple.security.cs.allow-jit + + com.apple.security.network.client + + com.apple.security.network.server + + + diff --git a/client/flutter_ui/macos/Runner/Info.plist b/client/flutter_ui/macos/Runner/Info.plist new file mode 100644 index 000000000..4789daa6a --- /dev/null +++ b/client/flutter_ui/macos/Runner/Info.plist @@ -0,0 +1,32 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIconFile + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSMinimumSystemVersion + $(MACOSX_DEPLOYMENT_TARGET) + NSHumanReadableCopyright + $(PRODUCT_COPYRIGHT) + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + + diff --git a/client/flutter_ui/macos/Runner/MainFlutterWindow.swift b/client/flutter_ui/macos/Runner/MainFlutterWindow.swift new file mode 100644 index 000000000..3cc05eb23 --- /dev/null +++ b/client/flutter_ui/macos/Runner/MainFlutterWindow.swift @@ -0,0 +1,15 @@ +import Cocoa +import FlutterMacOS + +class MainFlutterWindow: NSWindow { + override func awakeFromNib() { + let flutterViewController = FlutterViewController() + let windowFrame = self.frame + self.contentViewController = flutterViewController + self.setFrame(windowFrame, display: true) + + RegisterGeneratedPlugins(registry: flutterViewController) + + super.awakeFromNib() + } +} diff --git a/client/flutter_ui/macos/Runner/Release.entitlements b/client/flutter_ui/macos/Runner/Release.entitlements new file mode 100644 index 000000000..c326c8341 --- /dev/null +++ b/client/flutter_ui/macos/Runner/Release.entitlements @@ -0,0 +1,10 @@ + + + + + com.apple.security.network.client + + com.apple.security.network.server + + + diff --git a/client/flutter_ui/macos/RunnerTests/RunnerTests.swift b/client/flutter_ui/macos/RunnerTests/RunnerTests.swift new file mode 100644 index 000000000..61f3bd1fc --- /dev/null +++ b/client/flutter_ui/macos/RunnerTests/RunnerTests.swift @@ -0,0 +1,12 @@ +import Cocoa +import FlutterMacOS +import XCTest + +class RunnerTests: XCTestCase { + + func testExample() { + // If you add code to the Runner application, consider adding tests here. + // See https://developer.apple.com/documentation/xctest for more information about using XCTest. + } + +} diff --git a/client/flutter_ui/pubspec.lock b/client/flutter_ui/pubspec.lock new file mode 100644 index 000000000..344f398c8 --- /dev/null +++ b/client/flutter_ui/pubspec.lock @@ -0,0 +1,413 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + async: + dependency: transitive + description: + name: async + sha256: e2eb0491ba5ddb6177742d2da23904574082139b07c1e33b8503b9f46f3e1a37 + url: "https://pub.dev" + source: hosted + version: "2.13.1" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + characters: + dependency: transitive + description: + name: characters + sha256: faf38497bda5ead2a8c7615f4f7939df04333478bf32e4173fcb06d428b5716b + url: "https://pub.dev" + source: hosted + version: "1.4.1" + clock: + dependency: transitive + description: + name: clock + sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b + url: "https://pub.dev" + source: hosted + version: "1.1.2" + collection: + dependency: transitive + description: + name: collection + sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" + url: "https://pub.dev" + source: hosted + version: "1.19.1" + crypto: + dependency: transitive + description: + name: crypto + sha256: c8ea0233063ba03258fbcf2ca4d6dadfefe14f02fab57702265467a19f27fadf + url: "https://pub.dev" + source: hosted + version: "3.0.7" + fake_async: + dependency: transitive + description: + name: fake_async + sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" + url: "https://pub.dev" + source: hosted + version: "1.3.3" + fixnum: + dependency: "direct main" + description: + name: fixnum + sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be + url: "https://pub.dev" + source: hosted + version: "1.1.1" + flutter: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + google_cloud: + dependency: transitive + description: + name: google_cloud + sha256: fbcde933b2d8600c3cdb2328f8f4c47628ec29a39e9cef85dee535c7868993c4 + url: "https://pub.dev" + source: hosted + version: "0.4.1" + google_identity_services_web: + dependency: transitive + description: + name: google_identity_services_web + sha256: "5d187c46dc59e02646e10fe82665fc3884a9b71bc1c90c2b8b749316d33ee454" + url: "https://pub.dev" + source: hosted + version: "0.3.3+1" + googleapis_auth: + dependency: transitive + description: + name: googleapis_auth + sha256: "661738b763d3e524de69df53bf4e03943e4e01e98265cebcc6684871b06a5379" + url: "https://pub.dev" + source: hosted + version: "2.3.0" + grpc: + dependency: "direct main" + description: + name: grpc + sha256: "86be3a7d39ad865b214a7370021ac80e68939238b507730de6d97fc662cb2723" + url: "https://pub.dev" + source: hosted + version: "5.1.0" + http: + dependency: transitive + description: + name: http + sha256: "87721a4a50b19c7f1d49001e51409bddc46303966ce89a65af4f4e6004896412" + url: "https://pub.dev" + source: hosted + version: "1.6.0" + http2: + dependency: transitive + description: + name: http2 + sha256: "382d3aefc5bd6dc68c6b892d7664f29b5beb3251611ae946a98d35158a82bbfa" + url: "https://pub.dev" + source: hosted + version: "2.3.1" + http_parser: + dependency: transitive + description: + name: http_parser + sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571" + url: "https://pub.dev" + source: hosted + version: "4.1.2" + io: + dependency: transitive + description: + name: io + sha256: dfd5a80599cf0165756e3181807ed3e77daf6dd4137caaad72d0b7931597650b + url: "https://pub.dev" + source: hosted + version: "1.0.5" + json_annotation: + dependency: transitive + description: + name: json_annotation + sha256: cb09e7dac6210041fad964ed7fbee004f14258b4eca4040f72d1234062ace4c8 + url: "https://pub.dev" + source: hosted + version: "4.11.0" + leak_tracker: + dependency: transitive + description: + name: leak_tracker + sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de" + url: "https://pub.dev" + source: hosted + version: "11.0.2" + leak_tracker_flutter_testing: + dependency: transitive + description: + name: leak_tracker_flutter_testing + sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1" + url: "https://pub.dev" + source: hosted + version: "3.0.10" + leak_tracker_testing: + dependency: transitive + description: + name: leak_tracker_testing + sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1" + url: "https://pub.dev" + source: hosted + version: "3.0.2" + lints: + dependency: "direct dev" + description: + name: lints + sha256: "12f842a479589fea194fe5c5a3095abc7be0c1f2ddfa9a0e76aed1dbd26a87df" + url: "https://pub.dev" + source: hosted + version: "6.1.0" + local_notifier: + dependency: "direct main" + description: + name: local_notifier + sha256: f6cfc933c6fbc961f4e52b5c880f68e41b2d3cd29aad557cc654fd211093a025 + url: "https://pub.dev" + source: hosted + version: "0.1.6" + matcher: + dependency: transitive + description: + name: matcher + sha256: dc0b7dc7651697ea4ff3e69ef44b0407ea32c487a39fff6a4004fa585e901861 + url: "https://pub.dev" + source: hosted + version: "0.12.19" + material_color_utilities: + dependency: transitive + description: + name: material_color_utilities + sha256: "9c337007e82b1889149c82ed242ed1cb24a66044e30979c44912381e9be4c48b" + url: "https://pub.dev" + source: hosted + version: "0.13.0" + menu_base: + dependency: transitive + description: + name: menu_base + sha256: "820368014a171bd1241030278e6c2617354f492f5c703d7b7d4570a6b8b84405" + url: "https://pub.dev" + source: hosted + version: "0.1.1" + meta: + dependency: transitive + description: + name: meta + sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394" + url: "https://pub.dev" + source: hosted + version: "1.17.0" + path: + dependency: transitive + description: + name: path + sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" + url: "https://pub.dev" + source: hosted + version: "1.9.1" + plugin_platform_interface: + dependency: transitive + description: + name: plugin_platform_interface + sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" + url: "https://pub.dev" + source: hosted + version: "2.1.8" + protobuf: + dependency: "direct main" + description: + name: protobuf + sha256: "75ec242d22e950bdcc79ee38dd520ce4ee0bc491d7fadc4ea47694604d22bf06" + url: "https://pub.dev" + source: hosted + version: "6.0.0" + screen_retriever: + dependency: transitive + description: + name: screen_retriever + sha256: "570dbc8e4f70bac451e0efc9c9bb19fa2d6799a11e6ef04f946d7886d2e23d0c" + url: "https://pub.dev" + source: hosted + version: "0.2.0" + screen_retriever_linux: + dependency: transitive + description: + name: screen_retriever_linux + sha256: f7f8120c92ef0784e58491ab664d01efda79a922b025ff286e29aa123ea3dd18 + url: "https://pub.dev" + source: hosted + version: "0.2.0" + screen_retriever_macos: + dependency: transitive + description: + name: screen_retriever_macos + sha256: "71f956e65c97315dd661d71f828708bd97b6d358e776f1a30d5aa7d22d78a149" + url: "https://pub.dev" + source: hosted + version: "0.2.0" + screen_retriever_platform_interface: + dependency: transitive + description: + name: screen_retriever_platform_interface + sha256: ee197f4581ff0d5608587819af40490748e1e39e648d7680ecf95c05197240c0 + url: "https://pub.dev" + source: hosted + version: "0.2.0" + screen_retriever_windows: + dependency: transitive + description: + name: screen_retriever_windows + sha256: "449ee257f03ca98a57288ee526a301a430a344a161f9202b4fcc38576716fe13" + url: "https://pub.dev" + source: hosted + version: "0.2.0" + shelf: + dependency: transitive + description: + name: shelf + sha256: e7dd780a7ffb623c57850b33f43309312fc863fb6aa3d276a754bb299839ef12 + url: "https://pub.dev" + source: hosted + version: "1.4.2" + shortid: + dependency: transitive + description: + name: shortid + sha256: d0b40e3dbb50497dad107e19c54ca7de0d1a274eb9b4404991e443dadb9ebedb + url: "https://pub.dev" + source: hosted + version: "0.1.2" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + source_span: + dependency: transitive + description: + name: source_span + sha256: "56a02f1f4cd1a2d96303c0144c93bd6d909eea6bee6bf5a0e0b685edbd4c47ab" + url: "https://pub.dev" + source: hosted + version: "1.10.2" + stack_trace: + dependency: transitive + description: + name: stack_trace + sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" + url: "https://pub.dev" + source: hosted + version: "1.12.1" + stream_channel: + dependency: transitive + description: + name: stream_channel + sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + string_scanner: + dependency: transitive + description: + name: string_scanner + sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" + url: "https://pub.dev" + source: hosted + version: "1.4.1" + term_glyph: + dependency: transitive + description: + name: term_glyph + sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" + url: "https://pub.dev" + source: hosted + version: "1.2.2" + test_api: + dependency: transitive + description: + name: test_api + sha256: "8161c84903fd860b26bfdefb7963b3f0b68fee7adea0f59ef805ecca346f0c7a" + url: "https://pub.dev" + source: hosted + version: "0.7.10" + tray_manager: + dependency: "direct main" + description: + name: tray_manager + sha256: c5fd83b0ae4d80be6eaedfad87aaefab8787b333b8ebd064b0e442a81006035b + url: "https://pub.dev" + source: hosted + version: "0.5.2" + typed_data: + dependency: transitive + description: + name: typed_data + sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 + url: "https://pub.dev" + source: hosted + version: "1.4.0" + uuid: + dependency: transitive + description: + name: uuid + sha256: "1fef9e8e11e2991bb773070d4656b7bd5d850967a2456cfc83cf47925ba79489" + url: "https://pub.dev" + source: hosted + version: "4.5.3" + vector_math: + dependency: transitive + description: + name: vector_math + sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b + url: "https://pub.dev" + source: hosted + version: "2.2.0" + vm_service: + dependency: transitive + description: + name: vm_service + sha256: "046d3928e16fa4dc46e8350415661755ab759d9fc97fc21b5ab295f71e4f0499" + url: "https://pub.dev" + source: hosted + version: "15.1.0" + web: + dependency: transitive + description: + name: web + sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a" + url: "https://pub.dev" + source: hosted + version: "1.1.1" + window_manager: + dependency: "direct main" + description: + name: window_manager + sha256: "7eb6d6c4164ec08e1bf978d6e733f3cebe792e2a23fb07cbca25c2872bfdbdcd" + url: "https://pub.dev" + source: hosted + version: "0.5.1" +sdks: + dart: ">=3.9.0 <4.0.0" + flutter: ">=3.18.0-18.0.pre.54" diff --git a/client/flutter_ui/pubspec.yaml b/client/flutter_ui/pubspec.yaml new file mode 100644 index 000000000..09e5a36d2 --- /dev/null +++ b/client/flutter_ui/pubspec.yaml @@ -0,0 +1,28 @@ +name: netbird_flutter_ui +description: Experimental Flutter desktop UI for NetBird. +publish_to: none +version: 0.1.0 + +environment: + sdk: ^3.8.0 + +dependencies: + flutter: + sdk: flutter + fixnum: ^1.1.1 + grpc: ^5.1.0 + protobuf: ^6.0.0 + tray_manager: ^0.5.0 + window_manager: ^0.5.1 + local_notifier: ^0.1.6 + +dev_dependencies: + flutter_test: + sdk: flutter + lints: ^6.0.0 + +flutter: + uses-material-design: true + assets: + - assets/tray/ + diff --git a/client/flutter_ui/test/app_shell_test.dart b/client/flutter_ui/test/app_shell_test.dart new file mode 100644 index 000000000..e4b902318 --- /dev/null +++ b/client/flutter_ui/test/app_shell_test.dart @@ -0,0 +1,19 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:netbird_flutter_ui/src/app_shell.dart'; +import 'package:netbird_flutter_ui/src/daemon_client.dart'; + +void main() { + testWidgets('renders the status shell', (tester) async { + await tester.pumpWidget( + NetBirdFlutterApp( + client: FakeDaemonClient(daemonAddr: 'tcp://127.0.0.1:41731'), + ), + ); + + await tester.pump(); + + expect(find.text('Status'), findsWidgets); + expect(find.text('Connect'), findsOneWidget); + expect(find.text('Disconnect'), findsOneWidget); + }); +} diff --git a/client/flutter_ui/tool/bootstrap.sh b/client/flutter_ui/tool/bootstrap.sh new file mode 100755 index 000000000..514282934 --- /dev/null +++ b/client/flutter_ui/tool/bootstrap.sh @@ -0,0 +1,36 @@ +#!/usr/bin/env bash +set -euo pipefail + +project_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +tmp_dir="$(mktemp -d)" + +cleanup() { + rm -rf "$tmp_dir" +} +trap cleanup EXIT + +command -v flutter >/dev/null 2>&1 || { + echo "flutter is not installed" + exit 1 +} + +cp "$project_dir/pubspec.yaml" "$tmp_dir/pubspec.yaml" +cp "$project_dir/analysis_options.yaml" "$tmp_dir/analysis_options.yaml" +cp -R "$project_dir/lib" "$tmp_dir/lib" +cp -R "$project_dir/test" "$tmp_dir/test" + +flutter create \ + --platforms=windows,macos,linux \ + --project-name=netbird_flutter_ui \ + --org=io.netbird \ + "$project_dir" + +cp "$tmp_dir/pubspec.yaml" "$project_dir/pubspec.yaml" +cp "$tmp_dir/analysis_options.yaml" "$project_dir/analysis_options.yaml" +rm -rf "$project_dir/lib" +cp -R "$tmp_dir/lib" "$project_dir/lib" +rm -rf "$project_dir/test" +cp -R "$tmp_dir/test" "$project_dir/test" + +cd "$project_dir" +flutter pub get diff --git a/client/flutter_ui/tool/generate_proto.sh b/client/flutter_ui/tool/generate_proto.sh new file mode 100755 index 000000000..e0cd90dd8 --- /dev/null +++ b/client/flutter_ui/tool/generate_proto.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env bash +set -euo pipefail + +project_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +repo_dir="$(cd "$project_dir/../.." && pwd)" + +command -v protoc >/dev/null 2>&1 || { + echo "protoc is not installed" + exit 1 +} + +command -v dart >/dev/null 2>&1 || { + echo "dart is not installed" + exit 1 +} + +export PATH="$PATH:$HOME/.pub-cache/bin" + +if ! command -v protoc-gen-dart >/dev/null 2>&1; then + dart pub global activate protoc_plugin +fi + +mkdir -p "$project_dir/lib/src/generated" + +protoc \ + -I "$repo_dir/client/proto" \ + --dart_out=grpc:"$project_dir/lib/src/generated" \ + "$repo_dir/client/proto/daemon.proto" + diff --git a/client/flutter_ui/windows/.gitignore b/client/flutter_ui/windows/.gitignore new file mode 100644 index 000000000..d492d0d98 --- /dev/null +++ b/client/flutter_ui/windows/.gitignore @@ -0,0 +1,17 @@ +flutter/ephemeral/ + +# Visual Studio user-specific files. +*.suo +*.user +*.userosscache +*.sln.docstates + +# Visual Studio build-related files. +x64/ +x86/ + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ diff --git a/client/flutter_ui/windows/CMakeLists.txt b/client/flutter_ui/windows/CMakeLists.txt new file mode 100644 index 000000000..285b2ede1 --- /dev/null +++ b/client/flutter_ui/windows/CMakeLists.txt @@ -0,0 +1,108 @@ +# Project-level configuration. +cmake_minimum_required(VERSION 3.14) +project(netbird_flutter_ui LANGUAGES CXX) + +# The name of the executable created for the application. Change this to change +# the on-disk name of your application. +set(BINARY_NAME "netbird_flutter_ui") + +# Explicitly opt in to modern CMake behaviors to avoid warnings with recent +# versions of CMake. +cmake_policy(VERSION 3.14...3.25) + +# Define build configuration option. +get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) +if(IS_MULTICONFIG) + set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release" + CACHE STRING "" FORCE) +else() + if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE "Debug" CACHE + STRING "Flutter build mode" FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Profile" "Release") + endif() +endif() +# Define settings for the Profile build mode. +set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}") +set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}") +set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}") +set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}") + +# Use Unicode for all projects. +add_definitions(-DUNICODE -D_UNICODE) + +# Compilation settings that should be applied to most targets. +# +# Be cautious about adding new options here, as plugins use this function by +# default. In most cases, you should add new options to specific targets instead +# of modifying this function. +function(APPLY_STANDARD_SETTINGS TARGET) + target_compile_features(${TARGET} PUBLIC cxx_std_17) + target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100") + target_compile_options(${TARGET} PRIVATE /EHsc) + target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0") + target_compile_definitions(${TARGET} PRIVATE "$<$:_DEBUG>") +endfunction() + +# Flutter library and tool build rules. +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# Application build; see runner/CMakeLists.txt. +add_subdirectory("runner") + + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) + + +# === Installation === +# Support files are copied into place next to the executable, so that it can +# run in place. This is done instead of making a separate bundle (as on Linux) +# so that building and running from within Visual Studio will work. +set(BUILD_BUNDLE_DIR "$") +# Make the "install" step default, as it's required to run. +set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1) +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) +endif() + +set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") +set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}") + +install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +if(PLUGIN_BUNDLED_LIBRARIES) + install(FILES "${PLUGIN_BUNDLED_LIBRARIES}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() + +# Copy the native assets provided by the build.dart from all packages. +set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/windows/") +install(DIRECTORY "${NATIVE_ASSETS_DIR}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +# Fully re-copy the assets directory on each build to avoid having stale files +# from a previous install. +set(FLUTTER_ASSET_DIR_NAME "flutter_assets") +install(CODE " + file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") + " COMPONENT Runtime) +install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" + DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) + +# Install the AOT library on non-Debug builds only. +install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + CONFIGURATIONS Profile;Release + COMPONENT Runtime) diff --git a/client/flutter_ui/windows/flutter/CMakeLists.txt b/client/flutter_ui/windows/flutter/CMakeLists.txt new file mode 100644 index 000000000..903f4899d --- /dev/null +++ b/client/flutter_ui/windows/flutter/CMakeLists.txt @@ -0,0 +1,109 @@ +# This file controls Flutter-level build steps. It should not be edited. +cmake_minimum_required(VERSION 3.14) + +set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") + +# Configuration provided via flutter tool. +include(${EPHEMERAL_DIR}/generated_config.cmake) + +# TODO: Move the rest of this into files in ephemeral. See +# https://github.com/flutter/flutter/issues/57146. +set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper") + +# Set fallback configurations for older versions of the flutter tool. +if (NOT DEFINED FLUTTER_TARGET_PLATFORM) + set(FLUTTER_TARGET_PLATFORM "windows-x64") +endif() + +# === Flutter Library === +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll") + +# Published to parent scope for install step. +set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) +set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) +set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) +set(AOT_LIBRARY "${PROJECT_DIR}/build/windows/app.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "flutter_export.h" + "flutter_windows.h" + "flutter_messenger.h" + "flutter_plugin_registrar.h" + "flutter_texture_registrar.h" +) +list(TRANSFORM FLUTTER_LIBRARY_HEADERS PREPEND "${EPHEMERAL_DIR}/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}.lib") +add_dependencies(flutter flutter_assemble) + +# === Wrapper === +list(APPEND CPP_WRAPPER_SOURCES_CORE + "core_implementations.cc" + "standard_codec.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND "${WRAPPER_ROOT}/") +list(APPEND CPP_WRAPPER_SOURCES_PLUGIN + "plugin_registrar.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_PLUGIN PREPEND "${WRAPPER_ROOT}/") +list(APPEND CPP_WRAPPER_SOURCES_APP + "flutter_engine.cc" + "flutter_view_controller.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND "${WRAPPER_ROOT}/") + +# Wrapper sources needed for a plugin. +add_library(flutter_wrapper_plugin STATIC + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_PLUGIN} +) +apply_standard_settings(flutter_wrapper_plugin) +set_target_properties(flutter_wrapper_plugin PROPERTIES + POSITION_INDEPENDENT_CODE ON) +set_target_properties(flutter_wrapper_plugin PROPERTIES + CXX_VISIBILITY_PRESET hidden) +target_link_libraries(flutter_wrapper_plugin PUBLIC flutter) +target_include_directories(flutter_wrapper_plugin PUBLIC + "${WRAPPER_ROOT}/include" +) +add_dependencies(flutter_wrapper_plugin flutter_assemble) + +# Wrapper sources needed for the runner. +add_library(flutter_wrapper_app STATIC + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_APP} +) +apply_standard_settings(flutter_wrapper_app) +target_link_libraries(flutter_wrapper_app PUBLIC flutter) +target_include_directories(flutter_wrapper_app PUBLIC + "${WRAPPER_ROOT}/include" +) +add_dependencies(flutter_wrapper_app flutter_assemble) + +# === Flutter tool backend === +# _phony_ is a non-existent file to force this command to run every time, +# since currently there's no way to get a full input/output list from the +# flutter tool. +set(PHONY_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/_phony_") +set_source_files_properties("${PHONY_OUTPUT}" PROPERTIES SYMBOLIC TRUE) +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN} + ${CPP_WRAPPER_SOURCES_APP} + ${PHONY_OUTPUT} + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat" + ${FLUTTER_TARGET_PLATFORM} $ + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_PLUGIN} + ${CPP_WRAPPER_SOURCES_APP} +) diff --git a/client/flutter_ui/windows/flutter/generated_plugin_registrant.cc b/client/flutter_ui/windows/flutter/generated_plugin_registrant.cc new file mode 100644 index 000000000..7b43aeca9 --- /dev/null +++ b/client/flutter_ui/windows/flutter/generated_plugin_registrant.cc @@ -0,0 +1,23 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + +#include +#include +#include +#include + +void RegisterPlugins(flutter::PluginRegistry* registry) { + LocalNotifierPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("LocalNotifierPlugin")); + ScreenRetrieverWindowsPluginCApiRegisterWithRegistrar( + registry->GetRegistrarForPlugin("ScreenRetrieverWindowsPluginCApi")); + TrayManagerPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("TrayManagerPlugin")); + WindowManagerPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("WindowManagerPlugin")); +} diff --git a/client/flutter_ui/windows/flutter/generated_plugin_registrant.h b/client/flutter_ui/windows/flutter/generated_plugin_registrant.h new file mode 100644 index 000000000..dc139d85a --- /dev/null +++ b/client/flutter_ui/windows/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void RegisterPlugins(flutter::PluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/client/flutter_ui/windows/flutter/generated_plugins.cmake b/client/flutter_ui/windows/flutter/generated_plugins.cmake new file mode 100644 index 000000000..d702c47f8 --- /dev/null +++ b/client/flutter_ui/windows/flutter/generated_plugins.cmake @@ -0,0 +1,27 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST + local_notifier + screen_retriever_windows + tray_manager + window_manager +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) +endforeach(plugin) + +foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/client/flutter_ui/windows/runner/CMakeLists.txt b/client/flutter_ui/windows/runner/CMakeLists.txt new file mode 100644 index 000000000..394917c05 --- /dev/null +++ b/client/flutter_ui/windows/runner/CMakeLists.txt @@ -0,0 +1,40 @@ +cmake_minimum_required(VERSION 3.14) +project(runner LANGUAGES CXX) + +# Define the application target. To change its name, change BINARY_NAME in the +# top-level CMakeLists.txt, not the value here, or `flutter run` will no longer +# work. +# +# Any new source files that you add to the application should be added here. +add_executable(${BINARY_NAME} WIN32 + "flutter_window.cpp" + "main.cpp" + "utils.cpp" + "win32_window.cpp" + "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" + "Runner.rc" + "runner.exe.manifest" +) + +# Apply the standard set of build settings. This can be removed for applications +# that need different build settings. +apply_standard_settings(${BINARY_NAME}) + +# Add preprocessor definitions for the build version. +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION=\"${FLUTTER_VERSION}\"") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MAJOR=${FLUTTER_VERSION_MAJOR}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MINOR=${FLUTTER_VERSION_MINOR}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_PATCH=${FLUTTER_VERSION_PATCH}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_BUILD=${FLUTTER_VERSION_BUILD}") + +# Disable Windows macros that collide with C++ standard library functions. +target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX") + +# Add dependency libraries and include directories. Add any application-specific +# dependencies here. +target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app) +target_link_libraries(${BINARY_NAME} PRIVATE "dwmapi.lib") +target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") + +# Run the Flutter tool portions of the build. This must not be removed. +add_dependencies(${BINARY_NAME} flutter_assemble) diff --git a/client/flutter_ui/windows/runner/Runner.rc b/client/flutter_ui/windows/runner/Runner.rc new file mode 100644 index 000000000..9fd19e66b --- /dev/null +++ b/client/flutter_ui/windows/runner/Runner.rc @@ -0,0 +1,121 @@ +// Microsoft Visual C++ generated resource script. +// +#pragma code_page(65001) +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""winres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_APP_ICON ICON "resources\\app_icon.ico" + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +#if defined(FLUTTER_VERSION_MAJOR) && defined(FLUTTER_VERSION_MINOR) && defined(FLUTTER_VERSION_PATCH) && defined(FLUTTER_VERSION_BUILD) +#define VERSION_AS_NUMBER FLUTTER_VERSION_MAJOR,FLUTTER_VERSION_MINOR,FLUTTER_VERSION_PATCH,FLUTTER_VERSION_BUILD +#else +#define VERSION_AS_NUMBER 1,0,0,0 +#endif + +#if defined(FLUTTER_VERSION) +#define VERSION_AS_STRING FLUTTER_VERSION +#else +#define VERSION_AS_STRING "1.0.0" +#endif + +VS_VERSION_INFO VERSIONINFO + FILEVERSION VERSION_AS_NUMBER + PRODUCTVERSION VERSION_AS_NUMBER + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0x0L +#endif + FILEOS VOS__WINDOWS32 + FILETYPE VFT_APP + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904e4" + BEGIN + VALUE "CompanyName", "io.netbird" "\0" + VALUE "FileDescription", "netbird_flutter_ui" "\0" + VALUE "FileVersion", VERSION_AS_STRING "\0" + VALUE "InternalName", "netbird_flutter_ui" "\0" + VALUE "LegalCopyright", "Copyright (C) 2026 io.netbird. All rights reserved." "\0" + VALUE "OriginalFilename", "netbird_flutter_ui.exe" "\0" + VALUE "ProductName", "netbird_flutter_ui" "\0" + VALUE "ProductVersion", VERSION_AS_STRING "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1252 + END +END + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED diff --git a/client/flutter_ui/windows/runner/flutter_window.cpp b/client/flutter_ui/windows/runner/flutter_window.cpp new file mode 100644 index 000000000..955ee3038 --- /dev/null +++ b/client/flutter_ui/windows/runner/flutter_window.cpp @@ -0,0 +1,71 @@ +#include "flutter_window.h" + +#include + +#include "flutter/generated_plugin_registrant.h" + +FlutterWindow::FlutterWindow(const flutter::DartProject& project) + : project_(project) {} + +FlutterWindow::~FlutterWindow() {} + +bool FlutterWindow::OnCreate() { + if (!Win32Window::OnCreate()) { + return false; + } + + RECT frame = GetClientArea(); + + // The size here must match the window dimensions to avoid unnecessary surface + // creation / destruction in the startup path. + flutter_controller_ = std::make_unique( + frame.right - frame.left, frame.bottom - frame.top, project_); + // Ensure that basic setup of the controller was successful. + if (!flutter_controller_->engine() || !flutter_controller_->view()) { + return false; + } + RegisterPlugins(flutter_controller_->engine()); + SetChildContent(flutter_controller_->view()->GetNativeWindow()); + + flutter_controller_->engine()->SetNextFrameCallback([&]() { + this->Show(); + }); + + // Flutter can complete the first frame before the "show window" callback is + // registered. The following call ensures a frame is pending to ensure the + // window is shown. It is a no-op if the first frame hasn't completed yet. + flutter_controller_->ForceRedraw(); + + return true; +} + +void FlutterWindow::OnDestroy() { + if (flutter_controller_) { + flutter_controller_ = nullptr; + } + + Win32Window::OnDestroy(); +} + +LRESULT +FlutterWindow::MessageHandler(HWND hwnd, UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + // Give Flutter, including plugins, an opportunity to handle window messages. + if (flutter_controller_) { + std::optional result = + flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam, + lparam); + if (result) { + return *result; + } + } + + switch (message) { + case WM_FONTCHANGE: + flutter_controller_->engine()->ReloadSystemFonts(); + break; + } + + return Win32Window::MessageHandler(hwnd, message, wparam, lparam); +} diff --git a/client/flutter_ui/windows/runner/flutter_window.h b/client/flutter_ui/windows/runner/flutter_window.h new file mode 100644 index 000000000..6da0652f0 --- /dev/null +++ b/client/flutter_ui/windows/runner/flutter_window.h @@ -0,0 +1,33 @@ +#ifndef RUNNER_FLUTTER_WINDOW_H_ +#define RUNNER_FLUTTER_WINDOW_H_ + +#include +#include + +#include + +#include "win32_window.h" + +// A window that does nothing but host a Flutter view. +class FlutterWindow : public Win32Window { + public: + // Creates a new FlutterWindow hosting a Flutter view running |project|. + explicit FlutterWindow(const flutter::DartProject& project); + virtual ~FlutterWindow(); + + protected: + // Win32Window: + bool OnCreate() override; + void OnDestroy() override; + LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam, + LPARAM const lparam) noexcept override; + + private: + // The project to run. + flutter::DartProject project_; + + // The Flutter instance hosted by this window. + std::unique_ptr flutter_controller_; +}; + +#endif // RUNNER_FLUTTER_WINDOW_H_ diff --git a/client/flutter_ui/windows/runner/main.cpp b/client/flutter_ui/windows/runner/main.cpp new file mode 100644 index 000000000..e8432f24b --- /dev/null +++ b/client/flutter_ui/windows/runner/main.cpp @@ -0,0 +1,43 @@ +#include +#include +#include + +#include "flutter_window.h" +#include "utils.h" + +int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, + _In_ wchar_t *command_line, _In_ int show_command) { + // Attach to console when present (e.g., 'flutter run') or create a + // new console when running with a debugger. + if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) { + CreateAndAttachConsole(); + } + + // Initialize COM, so that it is available for use in the library and/or + // plugins. + ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); + + flutter::DartProject project(L"data"); + + std::vector command_line_arguments = + GetCommandLineArguments(); + + project.set_dart_entrypoint_arguments(std::move(command_line_arguments)); + + FlutterWindow window(project); + Win32Window::Point origin(10, 10); + Win32Window::Size size(1280, 720); + if (!window.Create(L"netbird_flutter_ui", origin, size)) { + return EXIT_FAILURE; + } + window.SetQuitOnClose(true); + + ::MSG msg; + while (::GetMessage(&msg, nullptr, 0, 0)) { + ::TranslateMessage(&msg); + ::DispatchMessage(&msg); + } + + ::CoUninitialize(); + return EXIT_SUCCESS; +} diff --git a/client/flutter_ui/windows/runner/resource.h b/client/flutter_ui/windows/runner/resource.h new file mode 100644 index 000000000..66a65d1e4 --- /dev/null +++ b/client/flutter_ui/windows/runner/resource.h @@ -0,0 +1,16 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by Runner.rc +// +#define IDI_APP_ICON 101 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/client/flutter_ui/windows/runner/resources/app_icon.ico b/client/flutter_ui/windows/runner/resources/app_icon.ico new file mode 100644 index 0000000000000000000000000000000000000000..c04e20caf6370ebb9253ad831cc31de4a9c965f6 GIT binary patch literal 33772 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 literal 0 HcmV?d00001 diff --git a/client/flutter_ui/windows/runner/runner.exe.manifest b/client/flutter_ui/windows/runner/runner.exe.manifest new file mode 100644 index 000000000..153653e8d --- /dev/null +++ b/client/flutter_ui/windows/runner/runner.exe.manifest @@ -0,0 +1,14 @@ + + + + + PerMonitorV2 + + + + + + + + + diff --git a/client/flutter_ui/windows/runner/utils.cpp b/client/flutter_ui/windows/runner/utils.cpp new file mode 100644 index 000000000..3a0b46511 --- /dev/null +++ b/client/flutter_ui/windows/runner/utils.cpp @@ -0,0 +1,65 @@ +#include "utils.h" + +#include +#include +#include +#include + +#include + +void CreateAndAttachConsole() { + if (::AllocConsole()) { + FILE *unused; + if (freopen_s(&unused, "CONOUT$", "w", stdout)) { + _dup2(_fileno(stdout), 1); + } + if (freopen_s(&unused, "CONOUT$", "w", stderr)) { + _dup2(_fileno(stdout), 2); + } + std::ios::sync_with_stdio(); + FlutterDesktopResyncOutputStreams(); + } +} + +std::vector GetCommandLineArguments() { + // Convert the UTF-16 command line arguments to UTF-8 for the Engine to use. + int argc; + wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc); + if (argv == nullptr) { + return std::vector(); + } + + std::vector command_line_arguments; + + // Skip the first argument as it's the binary name. + for (int i = 1; i < argc; i++) { + command_line_arguments.push_back(Utf8FromUtf16(argv[i])); + } + + ::LocalFree(argv); + + return command_line_arguments; +} + +std::string Utf8FromUtf16(const wchar_t* utf16_string) { + if (utf16_string == nullptr) { + return std::string(); + } + unsigned int target_length = ::WideCharToMultiByte( + CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, + -1, nullptr, 0, nullptr, nullptr) + -1; // remove the trailing null character + int input_length = (int)wcslen(utf16_string); + std::string utf8_string; + if (target_length == 0 || target_length > utf8_string.max_size()) { + return utf8_string; + } + utf8_string.resize(target_length); + int converted_length = ::WideCharToMultiByte( + CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, + input_length, utf8_string.data(), target_length, nullptr, nullptr); + if (converted_length == 0) { + return std::string(); + } + return utf8_string; +} diff --git a/client/flutter_ui/windows/runner/utils.h b/client/flutter_ui/windows/runner/utils.h new file mode 100644 index 000000000..3879d5475 --- /dev/null +++ b/client/flutter_ui/windows/runner/utils.h @@ -0,0 +1,19 @@ +#ifndef RUNNER_UTILS_H_ +#define RUNNER_UTILS_H_ + +#include +#include + +// Creates a console for the process, and redirects stdout and stderr to +// it for both the runner and the Flutter library. +void CreateAndAttachConsole(); + +// Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string +// encoded in UTF-8. Returns an empty std::string on failure. +std::string Utf8FromUtf16(const wchar_t* utf16_string); + +// Gets the command line arguments passed in as a std::vector, +// encoded in UTF-8. Returns an empty std::vector on failure. +std::vector GetCommandLineArguments(); + +#endif // RUNNER_UTILS_H_ diff --git a/client/flutter_ui/windows/runner/win32_window.cpp b/client/flutter_ui/windows/runner/win32_window.cpp new file mode 100644 index 000000000..60608d0fe --- /dev/null +++ b/client/flutter_ui/windows/runner/win32_window.cpp @@ -0,0 +1,288 @@ +#include "win32_window.h" + +#include +#include + +#include "resource.h" + +namespace { + +/// Window attribute that enables dark mode window decorations. +/// +/// Redefined in case the developer's machine has a Windows SDK older than +/// version 10.0.22000.0. +/// See: https://docs.microsoft.com/windows/win32/api/dwmapi/ne-dwmapi-dwmwindowattribute +#ifndef DWMWA_USE_IMMERSIVE_DARK_MODE +#define DWMWA_USE_IMMERSIVE_DARK_MODE 20 +#endif + +constexpr const wchar_t kWindowClassName[] = L"FLUTTER_RUNNER_WIN32_WINDOW"; + +/// Registry key for app theme preference. +/// +/// A value of 0 indicates apps should use dark mode. A non-zero or missing +/// value indicates apps should use light mode. +constexpr const wchar_t kGetPreferredBrightnessRegKey[] = + L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize"; +constexpr const wchar_t kGetPreferredBrightnessRegValue[] = L"AppsUseLightTheme"; + +// The number of Win32Window objects that currently exist. +static int g_active_window_count = 0; + +using EnableNonClientDpiScaling = BOOL __stdcall(HWND hwnd); + +// Scale helper to convert logical scaler values to physical using passed in +// scale factor +int Scale(int source, double scale_factor) { + return static_cast(source * scale_factor); +} + +// Dynamically loads the |EnableNonClientDpiScaling| from the User32 module. +// This API is only needed for PerMonitor V1 awareness mode. +void EnableFullDpiSupportIfAvailable(HWND hwnd) { + HMODULE user32_module = LoadLibraryA("User32.dll"); + if (!user32_module) { + return; + } + auto enable_non_client_dpi_scaling = + reinterpret_cast( + GetProcAddress(user32_module, "EnableNonClientDpiScaling")); + if (enable_non_client_dpi_scaling != nullptr) { + enable_non_client_dpi_scaling(hwnd); + } + FreeLibrary(user32_module); +} + +} // namespace + +// Manages the Win32Window's window class registration. +class WindowClassRegistrar { + public: + ~WindowClassRegistrar() = default; + + // Returns the singleton registrar instance. + static WindowClassRegistrar* GetInstance() { + if (!instance_) { + instance_ = new WindowClassRegistrar(); + } + return instance_; + } + + // Returns the name of the window class, registering the class if it hasn't + // previously been registered. + const wchar_t* GetWindowClass(); + + // Unregisters the window class. Should only be called if there are no + // instances of the window. + void UnregisterWindowClass(); + + private: + WindowClassRegistrar() = default; + + static WindowClassRegistrar* instance_; + + bool class_registered_ = false; +}; + +WindowClassRegistrar* WindowClassRegistrar::instance_ = nullptr; + +const wchar_t* WindowClassRegistrar::GetWindowClass() { + if (!class_registered_) { + WNDCLASS window_class{}; + window_class.hCursor = LoadCursor(nullptr, IDC_ARROW); + window_class.lpszClassName = kWindowClassName; + window_class.style = CS_HREDRAW | CS_VREDRAW; + window_class.cbClsExtra = 0; + window_class.cbWndExtra = 0; + window_class.hInstance = GetModuleHandle(nullptr); + window_class.hIcon = + LoadIcon(window_class.hInstance, MAKEINTRESOURCE(IDI_APP_ICON)); + window_class.hbrBackground = 0; + window_class.lpszMenuName = nullptr; + window_class.lpfnWndProc = Win32Window::WndProc; + RegisterClass(&window_class); + class_registered_ = true; + } + return kWindowClassName; +} + +void WindowClassRegistrar::UnregisterWindowClass() { + UnregisterClass(kWindowClassName, nullptr); + class_registered_ = false; +} + +Win32Window::Win32Window() { + ++g_active_window_count; +} + +Win32Window::~Win32Window() { + --g_active_window_count; + Destroy(); +} + +bool Win32Window::Create(const std::wstring& title, + const Point& origin, + const Size& size) { + Destroy(); + + const wchar_t* window_class = + WindowClassRegistrar::GetInstance()->GetWindowClass(); + + const POINT target_point = {static_cast(origin.x), + static_cast(origin.y)}; + HMONITOR monitor = MonitorFromPoint(target_point, MONITOR_DEFAULTTONEAREST); + UINT dpi = FlutterDesktopGetDpiForMonitor(monitor); + double scale_factor = dpi / 96.0; + + HWND window = CreateWindow( + window_class, title.c_str(), WS_OVERLAPPEDWINDOW, + Scale(origin.x, scale_factor), Scale(origin.y, scale_factor), + Scale(size.width, scale_factor), Scale(size.height, scale_factor), + nullptr, nullptr, GetModuleHandle(nullptr), this); + + if (!window) { + return false; + } + + UpdateTheme(window); + + return OnCreate(); +} + +bool Win32Window::Show() { + return ShowWindow(window_handle_, SW_SHOWNORMAL); +} + +// static +LRESULT CALLBACK Win32Window::WndProc(HWND const window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + if (message == WM_NCCREATE) { + auto window_struct = reinterpret_cast(lparam); + SetWindowLongPtr(window, GWLP_USERDATA, + reinterpret_cast(window_struct->lpCreateParams)); + + auto that = static_cast(window_struct->lpCreateParams); + EnableFullDpiSupportIfAvailable(window); + that->window_handle_ = window; + } else if (Win32Window* that = GetThisFromHandle(window)) { + return that->MessageHandler(window, message, wparam, lparam); + } + + return DefWindowProc(window, message, wparam, lparam); +} + +LRESULT +Win32Window::MessageHandler(HWND hwnd, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + switch (message) { + case WM_DESTROY: + window_handle_ = nullptr; + Destroy(); + if (quit_on_close_) { + PostQuitMessage(0); + } + return 0; + + case WM_DPICHANGED: { + auto newRectSize = reinterpret_cast(lparam); + LONG newWidth = newRectSize->right - newRectSize->left; + LONG newHeight = newRectSize->bottom - newRectSize->top; + + SetWindowPos(hwnd, nullptr, newRectSize->left, newRectSize->top, newWidth, + newHeight, SWP_NOZORDER | SWP_NOACTIVATE); + + return 0; + } + case WM_SIZE: { + RECT rect = GetClientArea(); + if (child_content_ != nullptr) { + // Size and position the child window. + MoveWindow(child_content_, rect.left, rect.top, rect.right - rect.left, + rect.bottom - rect.top, TRUE); + } + return 0; + } + + case WM_ACTIVATE: + if (child_content_ != nullptr) { + SetFocus(child_content_); + } + return 0; + + case WM_DWMCOLORIZATIONCOLORCHANGED: + UpdateTheme(hwnd); + return 0; + } + + return DefWindowProc(window_handle_, message, wparam, lparam); +} + +void Win32Window::Destroy() { + OnDestroy(); + + if (window_handle_) { + DestroyWindow(window_handle_); + window_handle_ = nullptr; + } + if (g_active_window_count == 0) { + WindowClassRegistrar::GetInstance()->UnregisterWindowClass(); + } +} + +Win32Window* Win32Window::GetThisFromHandle(HWND const window) noexcept { + return reinterpret_cast( + GetWindowLongPtr(window, GWLP_USERDATA)); +} + +void Win32Window::SetChildContent(HWND content) { + child_content_ = content; + SetParent(content, window_handle_); + RECT frame = GetClientArea(); + + MoveWindow(content, frame.left, frame.top, frame.right - frame.left, + frame.bottom - frame.top, true); + + SetFocus(child_content_); +} + +RECT Win32Window::GetClientArea() { + RECT frame; + GetClientRect(window_handle_, &frame); + return frame; +} + +HWND Win32Window::GetHandle() { + return window_handle_; +} + +void Win32Window::SetQuitOnClose(bool quit_on_close) { + quit_on_close_ = quit_on_close; +} + +bool Win32Window::OnCreate() { + // No-op; provided for subclasses. + return true; +} + +void Win32Window::OnDestroy() { + // No-op; provided for subclasses. +} + +void Win32Window::UpdateTheme(HWND const window) { + DWORD light_mode; + DWORD light_mode_size = sizeof(light_mode); + LSTATUS result = RegGetValue(HKEY_CURRENT_USER, kGetPreferredBrightnessRegKey, + kGetPreferredBrightnessRegValue, + RRF_RT_REG_DWORD, nullptr, &light_mode, + &light_mode_size); + + if (result == ERROR_SUCCESS) { + BOOL enable_dark_mode = light_mode == 0; + DwmSetWindowAttribute(window, DWMWA_USE_IMMERSIVE_DARK_MODE, + &enable_dark_mode, sizeof(enable_dark_mode)); + } +} diff --git a/client/flutter_ui/windows/runner/win32_window.h b/client/flutter_ui/windows/runner/win32_window.h new file mode 100644 index 000000000..e901dde68 --- /dev/null +++ b/client/flutter_ui/windows/runner/win32_window.h @@ -0,0 +1,102 @@ +#ifndef RUNNER_WIN32_WINDOW_H_ +#define RUNNER_WIN32_WINDOW_H_ + +#include + +#include +#include +#include + +// A class abstraction for a high DPI-aware Win32 Window. Intended to be +// inherited from by classes that wish to specialize with custom +// rendering and input handling +class Win32Window { + public: + struct Point { + unsigned int x; + unsigned int y; + Point(unsigned int x, unsigned int y) : x(x), y(y) {} + }; + + struct Size { + unsigned int width; + unsigned int height; + Size(unsigned int width, unsigned int height) + : width(width), height(height) {} + }; + + Win32Window(); + virtual ~Win32Window(); + + // Creates a win32 window with |title| that is positioned and sized using + // |origin| and |size|. New windows are created on the default monitor. Window + // sizes are specified to the OS in physical pixels, hence to ensure a + // consistent size this function will scale the inputted width and height as + // as appropriate for the default monitor. The window is invisible until + // |Show| is called. Returns true if the window was created successfully. + bool Create(const std::wstring& title, const Point& origin, const Size& size); + + // Show the current window. Returns true if the window was successfully shown. + bool Show(); + + // Release OS resources associated with window. + void Destroy(); + + // Inserts |content| into the window tree. + void SetChildContent(HWND content); + + // Returns the backing Window handle to enable clients to set icon and other + // window properties. Returns nullptr if the window has been destroyed. + HWND GetHandle(); + + // If true, closing this window will quit the application. + void SetQuitOnClose(bool quit_on_close); + + // Return a RECT representing the bounds of the current client area. + RECT GetClientArea(); + + protected: + // Processes and route salient window messages for mouse handling, + // size change and DPI. Delegates handling of these to member overloads that + // inheriting classes can handle. + virtual LRESULT MessageHandler(HWND window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept; + + // Called when CreateAndShow is called, allowing subclass window-related + // setup. Subclasses should return false if setup fails. + virtual bool OnCreate(); + + // Called when Destroy is called. + virtual void OnDestroy(); + + private: + friend class WindowClassRegistrar; + + // OS callback called by message pump. Handles the WM_NCCREATE message which + // is passed when the non-client area is being created and enables automatic + // non-client DPI scaling so that the non-client area automatically + // responds to changes in DPI. All other messages are handled by + // MessageHandler. + static LRESULT CALLBACK WndProc(HWND const window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept; + + // Retrieves a class instance pointer for |window| + static Win32Window* GetThisFromHandle(HWND const window) noexcept; + + // Update the window frame's theme to match the system theme. + static void UpdateTheme(HWND const window); + + bool quit_on_close_ = false; + + // window handle for top level window. + HWND window_handle_ = nullptr; + + // window handle for hosted content. + HWND child_content_ = nullptr; +}; + +#endif // RUNNER_WIN32_WINDOW_H_