From ff6aef5e2a772771bc99e1750fe510e093feba82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zolt=C3=A1n=20Papp?= Date: Thu, 11 Jun 2026 18:33:21 +0200 Subject: [PATCH] feat(ui): GUI debug logging follows daemon log level + debug bundle MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the daemon is set to debug/trace, the GUI now automatically writes a rotated gui-client.log in the user's config dir and the daemon's debug bundle collects it. The UI learns the level both at startup (daemon already in debug) and live, by piggybacking the existing SubscribeEvents stream: the daemon publishes a marked log-level-changed SystemEvent (and a per-subscription snapshot), which DaemonFeed routes to guilog.DebugLog instead of an OS toast. The UI registers its log path via a new RegisterUILog RPC so the root daemon, which can't resolve the user's config dir, knows where to find the file. Manual --log-file (any value) disables the daemon-driven file logging. Fix: client/ui SetLogLevel looked up proto.LogLevel_value with the lowercase logrus name, which never matched the uppercase enum keys and silently fell back to INFO — so trace/debug requests from the bundle flow had no effect. --- client/internal/debug/debug.go | 45 +- client/internal/debug/debug_logfiles_test.go | 25 +- client/proto/daemon.pb.go | 820 ++++++++++-------- client/proto/daemon.proto | 12 + client/proto/daemon_grpc.pb.go | 42 + client/proto/metadata.go | 30 + client/server/debug.go | 18 + client/server/event.go | 32 + client/server/server.go | 31 +- client/ui/CLAUDE.md | 15 +- .../src/contexts/DebugBundleContext.tsx | 9 +- client/ui/guilog/debuglog.go | 92 ++ client/ui/main.go | 35 +- client/ui/services/daemon_feed.go | 68 +- client/ui/services/debug.go | 20 +- client/ui/uilogpath.go | 41 + util/log.go | 55 +- 17 files changed, 971 insertions(+), 419 deletions(-) create mode 100644 client/proto/metadata.go create mode 100644 client/ui/guilog/debuglog.go create mode 100644 client/ui/uilogpath.go diff --git a/client/internal/debug/debug.go b/client/internal/debug/debug.go index 9ab18dd80..db8f33955 100644 --- a/client/internal/debug/debug.go +++ b/client/internal/debug/debug.go @@ -229,9 +229,16 @@ scutil_dns.txt (macOS only): const ( clientLogFile = "client.log" + uiLogFile = "gui-client.log" errorLogFile = "netbird.err" stdoutLogFile = "netbird.out" + // Rotated-log glob prefixes (base log name without extension) passed to + // addRotatedLogFiles. The daemon's own log and the GUI log live in the same + // dir, so the prefixes must be disjoint to keep their rotated siblings apart. + clientLogPrefix = "client" + uiLogPrefix = "gui-client" + darwinErrorLogPath = "/var/log/netbird.out.log" darwinStdoutLogPath = "/var/log/netbird.err.log" ) @@ -249,6 +256,7 @@ type BundleGenerator struct { statusRecorder *peer.Status syncResponse *mgmProto.SyncResponse logPath string + uiLogPath string tempDir string cpuProfile []byte capturePath string @@ -275,6 +283,7 @@ type GeneratorDependencies struct { StatusRecorder *peer.Status SyncResponse *mgmProto.SyncResponse LogPath string + UILogPath string // Absolute path to the desktop UI's gui-client.log, reported via RegisterUILog. Empty if no UI registered one. TempDir string // Directory for temporary bundle zip files. If empty, os.TempDir() is used. CPUProfile []byte CapturePath string @@ -298,6 +307,7 @@ func NewBundleGenerator(deps GeneratorDependencies, cfg BundleConfig) *BundleGen statusRecorder: deps.StatusRecorder, syncResponse: deps.SyncResponse, logPath: deps.LogPath, + uiLogPath: deps.UILogPath, tempDir: deps.TempDir, cpuProfile: deps.CPUProfile, capturePath: deps.CapturePath, @@ -408,6 +418,10 @@ func (g *BundleGenerator) createArchive() error { log.Errorf("failed to add logs to debug bundle: %v", err) } + if err := g.addUILog(); err != nil { + log.Errorf("failed to add UI log to debug bundle: %v", err) + } + if err := g.addUpdateLogs(); err != nil { log.Errorf("failed to add updater logs: %v", err) } @@ -972,7 +986,7 @@ func (g *BundleGenerator) addLogfile() error { return fmt.Errorf("add client log file to zip: %w", err) } - g.addRotatedLogFiles(logDir) + g.addRotatedLogFiles(logDir, clientLogPrefix) stdErrLogPath := filepath.Join(logDir, errorLogFile) stdoutLogPath := filepath.Join(logDir, stdoutLogFile) @@ -992,6 +1006,25 @@ func (g *BundleGenerator) addLogfile() error { return nil } +// addUILog adds the desktop UI's gui-client.log (and its rotated siblings) to +// the bundle. The path is reported by the UI via RegisterUILog; empty when no +// UI registered one (e.g. headless / server). Missing file is non-fatal — the +// UI only writes it while the daemon is in debug, so it's often absent. +func (g *BundleGenerator) addUILog() error { + if g.uiLogPath == "" { + log.Debugf("no UI log path registered, skipping in debug bundle") + return nil + } + + if err := g.addSingleLogfile(g.uiLogPath, uiLogFile); err != nil { + return fmt.Errorf("add UI log file to zip: %w", err) + } + + g.addRotatedLogFiles(filepath.Dir(g.uiLogPath), uiLogPrefix) + + return nil +} + // addSingleLogfile adds a single log file to the archive func (g *BundleGenerator) addSingleLogfile(logPath, targetName string) error { logFile, err := os.Open(logPath) @@ -1064,14 +1097,16 @@ func (g *BundleGenerator) addSingleLogFileGz(logPath, targetName string) error { return nil } -// addRotatedLogFiles adds rotated log files to the bundle based on logFileCount -func (g *BundleGenerator) addRotatedLogFiles(logDir string) { +// addRotatedLogFiles adds rotated log files to the bundle based on logFileCount. +// prefix is the base log name without extension (e.g. "client", "gui-client"); +// the glob matches both files rotated by us and by logrotate on linux. +func (g *BundleGenerator) addRotatedLogFiles(logDir, prefix string) { if g.logFileCount == 0 { return } - // This regex will match both logs rotated by us and logrotate on linux - pattern := filepath.Join(logDir, "client*.log.*") + // This pattern matches both logs rotated by us and logrotate on linux + pattern := filepath.Join(logDir, prefix+"*.log.*") files, err := filepath.Glob(pattern) if err != nil { log.Warnf("failed to glob rotated logs: %v", err) diff --git a/client/internal/debug/debug_logfiles_test.go b/client/internal/debug/debug_logfiles_test.go index f6473f979..3749b3e9b 100644 --- a/client/internal/debug/debug_logfiles_test.go +++ b/client/internal/debug/debug_logfiles_test.go @@ -40,6 +40,25 @@ func TestAddRotatedLogFiles_PicksUpAllVariants(t *testing.T) { require.NotContains(t, names, "other.log", "unrelated files should not be in bundle") } +// TestAddRotatedLogFiles_GUIPrefix asserts the prefix parameter scopes the glob +// to the GUI log: gui-client.log.* rotated siblings are picked up and the +// daemon's own client.log.* are not (and vice versa, covered above). This is +// the load-bearing check for the gui-client.log bundle collection — the old +// "client*.log.*" glob would have missed gui-client rotations. +func TestAddRotatedLogFiles_GUIPrefix(t *testing.T) { + dir := t.TempDir() + + writeFile(t, filepath.Join(dir, "gui-client.log.1"), "gui rotated\n") + writeGzFile(t, filepath.Join(dir, "gui-client.log.2.gz"), "gui rotated gz\n") + writeFile(t, filepath.Join(dir, "client.log.1"), "daemon rotated\n") + + names := runAddRotatedLogFilesPrefix(t, dir, "gui-client", 10) + + require.Contains(t, names, "gui-client.log.1", "gui-client rotated file should be in bundle") + require.Contains(t, names, "gui-client.log.2.gz", "gui-client gz rotated file should be in bundle") + require.NotContains(t, names, "client.log.1", "daemon rotated file must not match the gui-client prefix") +} + // TestAddRotatedLogFiles_RespectsLogFileCount asserts that only the newest // logFileCount rotated files are bundled, ordered by mtime. func TestAddRotatedLogFiles_RespectsLogFileCount(t *testing.T) { @@ -67,6 +86,10 @@ func TestAddRotatedLogFiles_RespectsLogFileCount(t *testing.T) { // runAddRotatedLogFiles calls addRotatedLogFiles against a fresh in-memory // zip writer and returns the set of entry names that ended up in the archive. func runAddRotatedLogFiles(t *testing.T, dir string, logFileCount uint32) map[string]struct{} { + return runAddRotatedLogFilesPrefix(t, dir, "client", logFileCount) +} + +func runAddRotatedLogFilesPrefix(t *testing.T, dir, prefix string, logFileCount uint32) map[string]struct{} { t.Helper() var buf bytes.Buffer @@ -74,7 +97,7 @@ func runAddRotatedLogFiles(t *testing.T, dir string, logFileCount uint32) map[st archive: zip.NewWriter(&buf), logFileCount: logFileCount, } - g.addRotatedLogFiles(dir) + g.addRotatedLogFiles(dir, prefix) require.NoError(t, g.archive.Close()) zr, err := zip.NewReader(bytes.NewReader(buf.Bytes()), int64(buf.Len())) diff --git a/client/proto/daemon.pb.go b/client/proto/daemon.pb.go index dfc3e3340..6286cbe91 100644 --- a/client/proto/daemon.pb.go +++ b/client/proto/daemon.pb.go @@ -192,7 +192,7 @@ func (x SystemEvent_Severity) Number() protoreflect.EnumNumber { // Deprecated: Use SystemEvent_Severity.Descriptor instead. func (SystemEvent_Severity) EnumDescriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{51, 0} + return file_daemon_proto_rawDescGZIP(), []int{53, 0} } type SystemEvent_Category int32 @@ -247,7 +247,7 @@ func (x SystemEvent_Category) Number() protoreflect.EnumNumber { // Deprecated: Use SystemEvent_Category.Descriptor instead. func (SystemEvent_Category) EnumDescriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{51, 1} + return file_daemon_proto_rawDescGZIP(), []int{53, 1} } type EmptyRequest struct { @@ -3043,6 +3043,86 @@ func (*SetLogLevelResponse) Descriptor() ([]byte, []int) { return file_daemon_proto_rawDescGZIP(), []int{36} } +type RegisterUILogRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Path string `protobuf:"bytes,1,opt,name=path,proto3" json:"path,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *RegisterUILogRequest) Reset() { + *x = RegisterUILogRequest{} + mi := &file_daemon_proto_msgTypes[37] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *RegisterUILogRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RegisterUILogRequest) ProtoMessage() {} + +func (x *RegisterUILogRequest) ProtoReflect() protoreflect.Message { + mi := &file_daemon_proto_msgTypes[37] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RegisterUILogRequest.ProtoReflect.Descriptor instead. +func (*RegisterUILogRequest) Descriptor() ([]byte, []int) { + return file_daemon_proto_rawDescGZIP(), []int{37} +} + +func (x *RegisterUILogRequest) GetPath() string { + if x != nil { + return x.Path + } + return "" +} + +type RegisterUILogResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *RegisterUILogResponse) Reset() { + *x = RegisterUILogResponse{} + mi := &file_daemon_proto_msgTypes[38] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *RegisterUILogResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RegisterUILogResponse) ProtoMessage() {} + +func (x *RegisterUILogResponse) ProtoReflect() protoreflect.Message { + mi := &file_daemon_proto_msgTypes[38] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RegisterUILogResponse.ProtoReflect.Descriptor instead. +func (*RegisterUILogResponse) Descriptor() ([]byte, []int) { + return file_daemon_proto_rawDescGZIP(), []int{38} +} + // State represents a daemon state entry type State struct { state protoimpl.MessageState `protogen:"open.v1"` @@ -3053,7 +3133,7 @@ type State struct { func (x *State) Reset() { *x = State{} - mi := &file_daemon_proto_msgTypes[37] + mi := &file_daemon_proto_msgTypes[39] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3065,7 +3145,7 @@ func (x *State) String() string { func (*State) ProtoMessage() {} func (x *State) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[37] + mi := &file_daemon_proto_msgTypes[39] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3078,7 +3158,7 @@ func (x *State) ProtoReflect() protoreflect.Message { // Deprecated: Use State.ProtoReflect.Descriptor instead. func (*State) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{37} + return file_daemon_proto_rawDescGZIP(), []int{39} } func (x *State) GetName() string { @@ -3097,7 +3177,7 @@ type ListStatesRequest struct { func (x *ListStatesRequest) Reset() { *x = ListStatesRequest{} - mi := &file_daemon_proto_msgTypes[38] + mi := &file_daemon_proto_msgTypes[40] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3109,7 +3189,7 @@ func (x *ListStatesRequest) String() string { func (*ListStatesRequest) ProtoMessage() {} func (x *ListStatesRequest) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[38] + mi := &file_daemon_proto_msgTypes[40] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3122,7 +3202,7 @@ func (x *ListStatesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListStatesRequest.ProtoReflect.Descriptor instead. func (*ListStatesRequest) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{38} + return file_daemon_proto_rawDescGZIP(), []int{40} } // ListStatesResponse contains a list of states @@ -3135,7 +3215,7 @@ type ListStatesResponse struct { func (x *ListStatesResponse) Reset() { *x = ListStatesResponse{} - mi := &file_daemon_proto_msgTypes[39] + mi := &file_daemon_proto_msgTypes[41] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3147,7 +3227,7 @@ func (x *ListStatesResponse) String() string { func (*ListStatesResponse) ProtoMessage() {} func (x *ListStatesResponse) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[39] + mi := &file_daemon_proto_msgTypes[41] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3160,7 +3240,7 @@ func (x *ListStatesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListStatesResponse.ProtoReflect.Descriptor instead. func (*ListStatesResponse) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{39} + return file_daemon_proto_rawDescGZIP(), []int{41} } func (x *ListStatesResponse) GetStates() []*State { @@ -3181,7 +3261,7 @@ type CleanStateRequest struct { func (x *CleanStateRequest) Reset() { *x = CleanStateRequest{} - mi := &file_daemon_proto_msgTypes[40] + mi := &file_daemon_proto_msgTypes[42] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3193,7 +3273,7 @@ func (x *CleanStateRequest) String() string { func (*CleanStateRequest) ProtoMessage() {} func (x *CleanStateRequest) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[40] + mi := &file_daemon_proto_msgTypes[42] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3206,7 +3286,7 @@ func (x *CleanStateRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CleanStateRequest.ProtoReflect.Descriptor instead. func (*CleanStateRequest) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{40} + return file_daemon_proto_rawDescGZIP(), []int{42} } func (x *CleanStateRequest) GetStateName() string { @@ -3233,7 +3313,7 @@ type CleanStateResponse struct { func (x *CleanStateResponse) Reset() { *x = CleanStateResponse{} - mi := &file_daemon_proto_msgTypes[41] + mi := &file_daemon_proto_msgTypes[43] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3245,7 +3325,7 @@ func (x *CleanStateResponse) String() string { func (*CleanStateResponse) ProtoMessage() {} func (x *CleanStateResponse) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[41] + mi := &file_daemon_proto_msgTypes[43] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3258,7 +3338,7 @@ func (x *CleanStateResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use CleanStateResponse.ProtoReflect.Descriptor instead. func (*CleanStateResponse) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{41} + return file_daemon_proto_rawDescGZIP(), []int{43} } func (x *CleanStateResponse) GetCleanedStates() int32 { @@ -3279,7 +3359,7 @@ type DeleteStateRequest struct { func (x *DeleteStateRequest) Reset() { *x = DeleteStateRequest{} - mi := &file_daemon_proto_msgTypes[42] + mi := &file_daemon_proto_msgTypes[44] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3291,7 +3371,7 @@ func (x *DeleteStateRequest) String() string { func (*DeleteStateRequest) ProtoMessage() {} func (x *DeleteStateRequest) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[42] + mi := &file_daemon_proto_msgTypes[44] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3304,7 +3384,7 @@ func (x *DeleteStateRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteStateRequest.ProtoReflect.Descriptor instead. func (*DeleteStateRequest) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{42} + return file_daemon_proto_rawDescGZIP(), []int{44} } func (x *DeleteStateRequest) GetStateName() string { @@ -3331,7 +3411,7 @@ type DeleteStateResponse struct { func (x *DeleteStateResponse) Reset() { *x = DeleteStateResponse{} - mi := &file_daemon_proto_msgTypes[43] + mi := &file_daemon_proto_msgTypes[45] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3343,7 +3423,7 @@ func (x *DeleteStateResponse) String() string { func (*DeleteStateResponse) ProtoMessage() {} func (x *DeleteStateResponse) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[43] + mi := &file_daemon_proto_msgTypes[45] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3356,7 +3436,7 @@ func (x *DeleteStateResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteStateResponse.ProtoReflect.Descriptor instead. func (*DeleteStateResponse) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{43} + return file_daemon_proto_rawDescGZIP(), []int{45} } func (x *DeleteStateResponse) GetDeletedStates() int32 { @@ -3375,7 +3455,7 @@ type SetSyncResponsePersistenceRequest struct { func (x *SetSyncResponsePersistenceRequest) Reset() { *x = SetSyncResponsePersistenceRequest{} - mi := &file_daemon_proto_msgTypes[44] + mi := &file_daemon_proto_msgTypes[46] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3387,7 +3467,7 @@ func (x *SetSyncResponsePersistenceRequest) String() string { func (*SetSyncResponsePersistenceRequest) ProtoMessage() {} func (x *SetSyncResponsePersistenceRequest) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[44] + mi := &file_daemon_proto_msgTypes[46] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3400,7 +3480,7 @@ func (x *SetSyncResponsePersistenceRequest) ProtoReflect() protoreflect.Message // Deprecated: Use SetSyncResponsePersistenceRequest.ProtoReflect.Descriptor instead. func (*SetSyncResponsePersistenceRequest) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{44} + return file_daemon_proto_rawDescGZIP(), []int{46} } func (x *SetSyncResponsePersistenceRequest) GetEnabled() bool { @@ -3418,7 +3498,7 @@ type SetSyncResponsePersistenceResponse struct { func (x *SetSyncResponsePersistenceResponse) Reset() { *x = SetSyncResponsePersistenceResponse{} - mi := &file_daemon_proto_msgTypes[45] + mi := &file_daemon_proto_msgTypes[47] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3430,7 +3510,7 @@ func (x *SetSyncResponsePersistenceResponse) String() string { func (*SetSyncResponsePersistenceResponse) ProtoMessage() {} func (x *SetSyncResponsePersistenceResponse) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[45] + mi := &file_daemon_proto_msgTypes[47] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3443,7 +3523,7 @@ func (x *SetSyncResponsePersistenceResponse) ProtoReflect() protoreflect.Message // Deprecated: Use SetSyncResponsePersistenceResponse.ProtoReflect.Descriptor instead. func (*SetSyncResponsePersistenceResponse) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{45} + return file_daemon_proto_rawDescGZIP(), []int{47} } type TCPFlags struct { @@ -3460,7 +3540,7 @@ type TCPFlags struct { func (x *TCPFlags) Reset() { *x = TCPFlags{} - mi := &file_daemon_proto_msgTypes[46] + mi := &file_daemon_proto_msgTypes[48] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3472,7 +3552,7 @@ func (x *TCPFlags) String() string { func (*TCPFlags) ProtoMessage() {} func (x *TCPFlags) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[46] + mi := &file_daemon_proto_msgTypes[48] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3485,7 +3565,7 @@ func (x *TCPFlags) ProtoReflect() protoreflect.Message { // Deprecated: Use TCPFlags.ProtoReflect.Descriptor instead. func (*TCPFlags) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{46} + return file_daemon_proto_rawDescGZIP(), []int{48} } func (x *TCPFlags) GetSyn() bool { @@ -3547,7 +3627,7 @@ type TracePacketRequest struct { func (x *TracePacketRequest) Reset() { *x = TracePacketRequest{} - mi := &file_daemon_proto_msgTypes[47] + mi := &file_daemon_proto_msgTypes[49] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3559,7 +3639,7 @@ func (x *TracePacketRequest) String() string { func (*TracePacketRequest) ProtoMessage() {} func (x *TracePacketRequest) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[47] + mi := &file_daemon_proto_msgTypes[49] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3572,7 +3652,7 @@ func (x *TracePacketRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use TracePacketRequest.ProtoReflect.Descriptor instead. func (*TracePacketRequest) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{47} + return file_daemon_proto_rawDescGZIP(), []int{49} } func (x *TracePacketRequest) GetSourceIp() string { @@ -3650,7 +3730,7 @@ type TraceStage struct { func (x *TraceStage) Reset() { *x = TraceStage{} - mi := &file_daemon_proto_msgTypes[48] + mi := &file_daemon_proto_msgTypes[50] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3662,7 +3742,7 @@ func (x *TraceStage) String() string { func (*TraceStage) ProtoMessage() {} func (x *TraceStage) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[48] + mi := &file_daemon_proto_msgTypes[50] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3675,7 +3755,7 @@ func (x *TraceStage) ProtoReflect() protoreflect.Message { // Deprecated: Use TraceStage.ProtoReflect.Descriptor instead. func (*TraceStage) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{48} + return file_daemon_proto_rawDescGZIP(), []int{50} } func (x *TraceStage) GetName() string { @@ -3716,7 +3796,7 @@ type TracePacketResponse struct { func (x *TracePacketResponse) Reset() { *x = TracePacketResponse{} - mi := &file_daemon_proto_msgTypes[49] + mi := &file_daemon_proto_msgTypes[51] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3728,7 +3808,7 @@ func (x *TracePacketResponse) String() string { func (*TracePacketResponse) ProtoMessage() {} func (x *TracePacketResponse) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[49] + mi := &file_daemon_proto_msgTypes[51] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3741,7 +3821,7 @@ func (x *TracePacketResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use TracePacketResponse.ProtoReflect.Descriptor instead. func (*TracePacketResponse) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{49} + return file_daemon_proto_rawDescGZIP(), []int{51} } func (x *TracePacketResponse) GetStages() []*TraceStage { @@ -3766,7 +3846,7 @@ type SubscribeRequest struct { func (x *SubscribeRequest) Reset() { *x = SubscribeRequest{} - mi := &file_daemon_proto_msgTypes[50] + mi := &file_daemon_proto_msgTypes[52] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3778,7 +3858,7 @@ func (x *SubscribeRequest) String() string { func (*SubscribeRequest) ProtoMessage() {} func (x *SubscribeRequest) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[50] + mi := &file_daemon_proto_msgTypes[52] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3791,7 +3871,7 @@ func (x *SubscribeRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use SubscribeRequest.ProtoReflect.Descriptor instead. func (*SubscribeRequest) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{50} + return file_daemon_proto_rawDescGZIP(), []int{52} } type SystemEvent struct { @@ -3809,7 +3889,7 @@ type SystemEvent struct { func (x *SystemEvent) Reset() { *x = SystemEvent{} - mi := &file_daemon_proto_msgTypes[51] + mi := &file_daemon_proto_msgTypes[53] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3821,7 +3901,7 @@ func (x *SystemEvent) String() string { func (*SystemEvent) ProtoMessage() {} func (x *SystemEvent) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[51] + mi := &file_daemon_proto_msgTypes[53] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3834,7 +3914,7 @@ func (x *SystemEvent) ProtoReflect() protoreflect.Message { // Deprecated: Use SystemEvent.ProtoReflect.Descriptor instead. func (*SystemEvent) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{51} + return file_daemon_proto_rawDescGZIP(), []int{53} } func (x *SystemEvent) GetId() string { @@ -3894,7 +3974,7 @@ type GetEventsRequest struct { func (x *GetEventsRequest) Reset() { *x = GetEventsRequest{} - mi := &file_daemon_proto_msgTypes[52] + mi := &file_daemon_proto_msgTypes[54] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3906,7 +3986,7 @@ func (x *GetEventsRequest) String() string { func (*GetEventsRequest) ProtoMessage() {} func (x *GetEventsRequest) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[52] + mi := &file_daemon_proto_msgTypes[54] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3919,7 +3999,7 @@ func (x *GetEventsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetEventsRequest.ProtoReflect.Descriptor instead. func (*GetEventsRequest) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{52} + return file_daemon_proto_rawDescGZIP(), []int{54} } type GetEventsResponse struct { @@ -3931,7 +4011,7 @@ type GetEventsResponse struct { func (x *GetEventsResponse) Reset() { *x = GetEventsResponse{} - mi := &file_daemon_proto_msgTypes[53] + mi := &file_daemon_proto_msgTypes[55] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3943,7 +4023,7 @@ func (x *GetEventsResponse) String() string { func (*GetEventsResponse) ProtoMessage() {} func (x *GetEventsResponse) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[53] + mi := &file_daemon_proto_msgTypes[55] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3956,7 +4036,7 @@ func (x *GetEventsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetEventsResponse.ProtoReflect.Descriptor instead. func (*GetEventsResponse) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{53} + return file_daemon_proto_rawDescGZIP(), []int{55} } func (x *GetEventsResponse) GetEvents() []*SystemEvent { @@ -3976,7 +4056,7 @@ type SwitchProfileRequest struct { func (x *SwitchProfileRequest) Reset() { *x = SwitchProfileRequest{} - mi := &file_daemon_proto_msgTypes[54] + mi := &file_daemon_proto_msgTypes[56] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3988,7 +4068,7 @@ func (x *SwitchProfileRequest) String() string { func (*SwitchProfileRequest) ProtoMessage() {} func (x *SwitchProfileRequest) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[54] + mi := &file_daemon_proto_msgTypes[56] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4001,7 +4081,7 @@ func (x *SwitchProfileRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use SwitchProfileRequest.ProtoReflect.Descriptor instead. func (*SwitchProfileRequest) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{54} + return file_daemon_proto_rawDescGZIP(), []int{56} } func (x *SwitchProfileRequest) GetProfileName() string { @@ -4026,7 +4106,7 @@ type SwitchProfileResponse struct { func (x *SwitchProfileResponse) Reset() { *x = SwitchProfileResponse{} - mi := &file_daemon_proto_msgTypes[55] + mi := &file_daemon_proto_msgTypes[57] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4038,7 +4118,7 @@ func (x *SwitchProfileResponse) String() string { func (*SwitchProfileResponse) ProtoMessage() {} func (x *SwitchProfileResponse) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[55] + mi := &file_daemon_proto_msgTypes[57] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4051,7 +4131,7 @@ func (x *SwitchProfileResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use SwitchProfileResponse.ProtoReflect.Descriptor instead. func (*SwitchProfileResponse) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{55} + return file_daemon_proto_rawDescGZIP(), []int{57} } type SetConfigRequest struct { @@ -4100,7 +4180,7 @@ type SetConfigRequest struct { func (x *SetConfigRequest) Reset() { *x = SetConfigRequest{} - mi := &file_daemon_proto_msgTypes[56] + mi := &file_daemon_proto_msgTypes[58] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4112,7 +4192,7 @@ func (x *SetConfigRequest) String() string { func (*SetConfigRequest) ProtoMessage() {} func (x *SetConfigRequest) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[56] + mi := &file_daemon_proto_msgTypes[58] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4125,7 +4205,7 @@ func (x *SetConfigRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use SetConfigRequest.ProtoReflect.Descriptor instead. func (*SetConfigRequest) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{56} + return file_daemon_proto_rawDescGZIP(), []int{58} } func (x *SetConfigRequest) GetUsername() string { @@ -4381,7 +4461,7 @@ type SetConfigResponse struct { func (x *SetConfigResponse) Reset() { *x = SetConfigResponse{} - mi := &file_daemon_proto_msgTypes[57] + mi := &file_daemon_proto_msgTypes[59] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4393,7 +4473,7 @@ func (x *SetConfigResponse) String() string { func (*SetConfigResponse) ProtoMessage() {} func (x *SetConfigResponse) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[57] + mi := &file_daemon_proto_msgTypes[59] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4406,7 +4486,7 @@ func (x *SetConfigResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use SetConfigResponse.ProtoReflect.Descriptor instead. func (*SetConfigResponse) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{57} + return file_daemon_proto_rawDescGZIP(), []int{59} } type AddProfileRequest struct { @@ -4419,7 +4499,7 @@ type AddProfileRequest struct { func (x *AddProfileRequest) Reset() { *x = AddProfileRequest{} - mi := &file_daemon_proto_msgTypes[58] + mi := &file_daemon_proto_msgTypes[60] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4431,7 +4511,7 @@ func (x *AddProfileRequest) String() string { func (*AddProfileRequest) ProtoMessage() {} func (x *AddProfileRequest) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[58] + mi := &file_daemon_proto_msgTypes[60] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4444,7 +4524,7 @@ func (x *AddProfileRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use AddProfileRequest.ProtoReflect.Descriptor instead. func (*AddProfileRequest) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{58} + return file_daemon_proto_rawDescGZIP(), []int{60} } func (x *AddProfileRequest) GetUsername() string { @@ -4469,7 +4549,7 @@ type AddProfileResponse struct { func (x *AddProfileResponse) Reset() { *x = AddProfileResponse{} - mi := &file_daemon_proto_msgTypes[59] + mi := &file_daemon_proto_msgTypes[61] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4481,7 +4561,7 @@ func (x *AddProfileResponse) String() string { func (*AddProfileResponse) ProtoMessage() {} func (x *AddProfileResponse) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[59] + mi := &file_daemon_proto_msgTypes[61] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4494,7 +4574,7 @@ func (x *AddProfileResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use AddProfileResponse.ProtoReflect.Descriptor instead. func (*AddProfileResponse) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{59} + return file_daemon_proto_rawDescGZIP(), []int{61} } type RemoveProfileRequest struct { @@ -4507,7 +4587,7 @@ type RemoveProfileRequest struct { func (x *RemoveProfileRequest) Reset() { *x = RemoveProfileRequest{} - mi := &file_daemon_proto_msgTypes[60] + mi := &file_daemon_proto_msgTypes[62] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4519,7 +4599,7 @@ func (x *RemoveProfileRequest) String() string { func (*RemoveProfileRequest) ProtoMessage() {} func (x *RemoveProfileRequest) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[60] + mi := &file_daemon_proto_msgTypes[62] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4532,7 +4612,7 @@ func (x *RemoveProfileRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use RemoveProfileRequest.ProtoReflect.Descriptor instead. func (*RemoveProfileRequest) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{60} + return file_daemon_proto_rawDescGZIP(), []int{62} } func (x *RemoveProfileRequest) GetUsername() string { @@ -4557,7 +4637,7 @@ type RemoveProfileResponse struct { func (x *RemoveProfileResponse) Reset() { *x = RemoveProfileResponse{} - mi := &file_daemon_proto_msgTypes[61] + mi := &file_daemon_proto_msgTypes[63] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4569,7 +4649,7 @@ func (x *RemoveProfileResponse) String() string { func (*RemoveProfileResponse) ProtoMessage() {} func (x *RemoveProfileResponse) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[61] + mi := &file_daemon_proto_msgTypes[63] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4582,7 +4662,7 @@ func (x *RemoveProfileResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use RemoveProfileResponse.ProtoReflect.Descriptor instead. func (*RemoveProfileResponse) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{61} + return file_daemon_proto_rawDescGZIP(), []int{63} } type ListProfilesRequest struct { @@ -4594,7 +4674,7 @@ type ListProfilesRequest struct { func (x *ListProfilesRequest) Reset() { *x = ListProfilesRequest{} - mi := &file_daemon_proto_msgTypes[62] + mi := &file_daemon_proto_msgTypes[64] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4606,7 +4686,7 @@ func (x *ListProfilesRequest) String() string { func (*ListProfilesRequest) ProtoMessage() {} func (x *ListProfilesRequest) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[62] + mi := &file_daemon_proto_msgTypes[64] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4619,7 +4699,7 @@ func (x *ListProfilesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListProfilesRequest.ProtoReflect.Descriptor instead. func (*ListProfilesRequest) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{62} + return file_daemon_proto_rawDescGZIP(), []int{64} } func (x *ListProfilesRequest) GetUsername() string { @@ -4638,7 +4718,7 @@ type ListProfilesResponse struct { func (x *ListProfilesResponse) Reset() { *x = ListProfilesResponse{} - mi := &file_daemon_proto_msgTypes[63] + mi := &file_daemon_proto_msgTypes[65] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4650,7 +4730,7 @@ func (x *ListProfilesResponse) String() string { func (*ListProfilesResponse) ProtoMessage() {} func (x *ListProfilesResponse) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[63] + mi := &file_daemon_proto_msgTypes[65] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4663,7 +4743,7 @@ func (x *ListProfilesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListProfilesResponse.ProtoReflect.Descriptor instead. func (*ListProfilesResponse) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{63} + return file_daemon_proto_rawDescGZIP(), []int{65} } func (x *ListProfilesResponse) GetProfiles() []*Profile { @@ -4683,7 +4763,7 @@ type Profile struct { func (x *Profile) Reset() { *x = Profile{} - mi := &file_daemon_proto_msgTypes[64] + mi := &file_daemon_proto_msgTypes[66] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4695,7 +4775,7 @@ func (x *Profile) String() string { func (*Profile) ProtoMessage() {} func (x *Profile) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[64] + mi := &file_daemon_proto_msgTypes[66] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4708,7 +4788,7 @@ func (x *Profile) ProtoReflect() protoreflect.Message { // Deprecated: Use Profile.ProtoReflect.Descriptor instead. func (*Profile) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{64} + return file_daemon_proto_rawDescGZIP(), []int{66} } func (x *Profile) GetName() string { @@ -4733,7 +4813,7 @@ type GetActiveProfileRequest struct { func (x *GetActiveProfileRequest) Reset() { *x = GetActiveProfileRequest{} - mi := &file_daemon_proto_msgTypes[65] + mi := &file_daemon_proto_msgTypes[67] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4745,7 +4825,7 @@ func (x *GetActiveProfileRequest) String() string { func (*GetActiveProfileRequest) ProtoMessage() {} func (x *GetActiveProfileRequest) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[65] + mi := &file_daemon_proto_msgTypes[67] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4758,7 +4838,7 @@ func (x *GetActiveProfileRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetActiveProfileRequest.ProtoReflect.Descriptor instead. func (*GetActiveProfileRequest) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{65} + return file_daemon_proto_rawDescGZIP(), []int{67} } type GetActiveProfileResponse struct { @@ -4771,7 +4851,7 @@ type GetActiveProfileResponse struct { func (x *GetActiveProfileResponse) Reset() { *x = GetActiveProfileResponse{} - mi := &file_daemon_proto_msgTypes[66] + mi := &file_daemon_proto_msgTypes[68] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4783,7 +4863,7 @@ func (x *GetActiveProfileResponse) String() string { func (*GetActiveProfileResponse) ProtoMessage() {} func (x *GetActiveProfileResponse) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[66] + mi := &file_daemon_proto_msgTypes[68] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4796,7 +4876,7 @@ func (x *GetActiveProfileResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetActiveProfileResponse.ProtoReflect.Descriptor instead. func (*GetActiveProfileResponse) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{66} + return file_daemon_proto_rawDescGZIP(), []int{68} } func (x *GetActiveProfileResponse) GetProfileName() string { @@ -4823,7 +4903,7 @@ type LogoutRequest struct { func (x *LogoutRequest) Reset() { *x = LogoutRequest{} - mi := &file_daemon_proto_msgTypes[67] + mi := &file_daemon_proto_msgTypes[69] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4835,7 +4915,7 @@ func (x *LogoutRequest) String() string { func (*LogoutRequest) ProtoMessage() {} func (x *LogoutRequest) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[67] + mi := &file_daemon_proto_msgTypes[69] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4848,7 +4928,7 @@ func (x *LogoutRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use LogoutRequest.ProtoReflect.Descriptor instead. func (*LogoutRequest) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{67} + return file_daemon_proto_rawDescGZIP(), []int{69} } func (x *LogoutRequest) GetProfileName() string { @@ -4873,7 +4953,7 @@ type LogoutResponse struct { func (x *LogoutResponse) Reset() { *x = LogoutResponse{} - mi := &file_daemon_proto_msgTypes[68] + mi := &file_daemon_proto_msgTypes[70] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4885,7 +4965,7 @@ func (x *LogoutResponse) String() string { func (*LogoutResponse) ProtoMessage() {} func (x *LogoutResponse) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[68] + mi := &file_daemon_proto_msgTypes[70] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4898,7 +4978,7 @@ func (x *LogoutResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use LogoutResponse.ProtoReflect.Descriptor instead. func (*LogoutResponse) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{68} + return file_daemon_proto_rawDescGZIP(), []int{70} } type GetFeaturesRequest struct { @@ -4909,7 +4989,7 @@ type GetFeaturesRequest struct { func (x *GetFeaturesRequest) Reset() { *x = GetFeaturesRequest{} - mi := &file_daemon_proto_msgTypes[69] + mi := &file_daemon_proto_msgTypes[71] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4921,7 +5001,7 @@ func (x *GetFeaturesRequest) String() string { func (*GetFeaturesRequest) ProtoMessage() {} func (x *GetFeaturesRequest) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[69] + mi := &file_daemon_proto_msgTypes[71] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4934,7 +5014,7 @@ func (x *GetFeaturesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetFeaturesRequest.ProtoReflect.Descriptor instead. func (*GetFeaturesRequest) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{69} + return file_daemon_proto_rawDescGZIP(), []int{71} } type GetFeaturesResponse struct { @@ -4948,7 +5028,7 @@ type GetFeaturesResponse struct { func (x *GetFeaturesResponse) Reset() { *x = GetFeaturesResponse{} - mi := &file_daemon_proto_msgTypes[70] + mi := &file_daemon_proto_msgTypes[72] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4960,7 +5040,7 @@ func (x *GetFeaturesResponse) String() string { func (*GetFeaturesResponse) ProtoMessage() {} func (x *GetFeaturesResponse) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[70] + mi := &file_daemon_proto_msgTypes[72] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4973,7 +5053,7 @@ func (x *GetFeaturesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetFeaturesResponse.ProtoReflect.Descriptor instead. func (*GetFeaturesResponse) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{70} + return file_daemon_proto_rawDescGZIP(), []int{72} } func (x *GetFeaturesResponse) GetDisableProfiles() bool { @@ -5005,7 +5085,7 @@ type TriggerUpdateRequest struct { func (x *TriggerUpdateRequest) Reset() { *x = TriggerUpdateRequest{} - mi := &file_daemon_proto_msgTypes[71] + mi := &file_daemon_proto_msgTypes[73] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5017,7 +5097,7 @@ func (x *TriggerUpdateRequest) String() string { func (*TriggerUpdateRequest) ProtoMessage() {} func (x *TriggerUpdateRequest) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[71] + mi := &file_daemon_proto_msgTypes[73] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5030,7 +5110,7 @@ func (x *TriggerUpdateRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use TriggerUpdateRequest.ProtoReflect.Descriptor instead. func (*TriggerUpdateRequest) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{71} + return file_daemon_proto_rawDescGZIP(), []int{73} } type TriggerUpdateResponse struct { @@ -5043,7 +5123,7 @@ type TriggerUpdateResponse struct { func (x *TriggerUpdateResponse) Reset() { *x = TriggerUpdateResponse{} - mi := &file_daemon_proto_msgTypes[72] + mi := &file_daemon_proto_msgTypes[74] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5055,7 +5135,7 @@ func (x *TriggerUpdateResponse) String() string { func (*TriggerUpdateResponse) ProtoMessage() {} func (x *TriggerUpdateResponse) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[72] + mi := &file_daemon_proto_msgTypes[74] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5068,7 +5148,7 @@ func (x *TriggerUpdateResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use TriggerUpdateResponse.ProtoReflect.Descriptor instead. func (*TriggerUpdateResponse) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{72} + return file_daemon_proto_rawDescGZIP(), []int{74} } func (x *TriggerUpdateResponse) GetSuccess() bool { @@ -5096,7 +5176,7 @@ type GetPeerSSHHostKeyRequest struct { func (x *GetPeerSSHHostKeyRequest) Reset() { *x = GetPeerSSHHostKeyRequest{} - mi := &file_daemon_proto_msgTypes[73] + mi := &file_daemon_proto_msgTypes[75] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5108,7 +5188,7 @@ func (x *GetPeerSSHHostKeyRequest) String() string { func (*GetPeerSSHHostKeyRequest) ProtoMessage() {} func (x *GetPeerSSHHostKeyRequest) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[73] + mi := &file_daemon_proto_msgTypes[75] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5121,7 +5201,7 @@ func (x *GetPeerSSHHostKeyRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetPeerSSHHostKeyRequest.ProtoReflect.Descriptor instead. func (*GetPeerSSHHostKeyRequest) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{73} + return file_daemon_proto_rawDescGZIP(), []int{75} } func (x *GetPeerSSHHostKeyRequest) GetPeerAddress() string { @@ -5148,7 +5228,7 @@ type GetPeerSSHHostKeyResponse struct { func (x *GetPeerSSHHostKeyResponse) Reset() { *x = GetPeerSSHHostKeyResponse{} - mi := &file_daemon_proto_msgTypes[74] + mi := &file_daemon_proto_msgTypes[76] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5160,7 +5240,7 @@ func (x *GetPeerSSHHostKeyResponse) String() string { func (*GetPeerSSHHostKeyResponse) ProtoMessage() {} func (x *GetPeerSSHHostKeyResponse) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[74] + mi := &file_daemon_proto_msgTypes[76] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5173,7 +5253,7 @@ func (x *GetPeerSSHHostKeyResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetPeerSSHHostKeyResponse.ProtoReflect.Descriptor instead. func (*GetPeerSSHHostKeyResponse) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{74} + return file_daemon_proto_rawDescGZIP(), []int{76} } func (x *GetPeerSSHHostKeyResponse) GetSshHostKey() []byte { @@ -5215,7 +5295,7 @@ type RequestJWTAuthRequest struct { func (x *RequestJWTAuthRequest) Reset() { *x = RequestJWTAuthRequest{} - mi := &file_daemon_proto_msgTypes[75] + mi := &file_daemon_proto_msgTypes[77] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5227,7 +5307,7 @@ func (x *RequestJWTAuthRequest) String() string { func (*RequestJWTAuthRequest) ProtoMessage() {} func (x *RequestJWTAuthRequest) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[75] + mi := &file_daemon_proto_msgTypes[77] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5240,7 +5320,7 @@ func (x *RequestJWTAuthRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use RequestJWTAuthRequest.ProtoReflect.Descriptor instead. func (*RequestJWTAuthRequest) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{75} + return file_daemon_proto_rawDescGZIP(), []int{77} } func (x *RequestJWTAuthRequest) GetHint() string { @@ -5273,7 +5353,7 @@ type RequestJWTAuthResponse struct { func (x *RequestJWTAuthResponse) Reset() { *x = RequestJWTAuthResponse{} - mi := &file_daemon_proto_msgTypes[76] + mi := &file_daemon_proto_msgTypes[78] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5285,7 +5365,7 @@ func (x *RequestJWTAuthResponse) String() string { func (*RequestJWTAuthResponse) ProtoMessage() {} func (x *RequestJWTAuthResponse) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[76] + mi := &file_daemon_proto_msgTypes[78] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5298,7 +5378,7 @@ func (x *RequestJWTAuthResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use RequestJWTAuthResponse.ProtoReflect.Descriptor instead. func (*RequestJWTAuthResponse) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{76} + return file_daemon_proto_rawDescGZIP(), []int{78} } func (x *RequestJWTAuthResponse) GetVerificationURI() string { @@ -5363,7 +5443,7 @@ type WaitJWTTokenRequest struct { func (x *WaitJWTTokenRequest) Reset() { *x = WaitJWTTokenRequest{} - mi := &file_daemon_proto_msgTypes[77] + mi := &file_daemon_proto_msgTypes[79] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5375,7 +5455,7 @@ func (x *WaitJWTTokenRequest) String() string { func (*WaitJWTTokenRequest) ProtoMessage() {} func (x *WaitJWTTokenRequest) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[77] + mi := &file_daemon_proto_msgTypes[79] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5388,7 +5468,7 @@ func (x *WaitJWTTokenRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use WaitJWTTokenRequest.ProtoReflect.Descriptor instead. func (*WaitJWTTokenRequest) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{77} + return file_daemon_proto_rawDescGZIP(), []int{79} } func (x *WaitJWTTokenRequest) GetDeviceCode() string { @@ -5420,7 +5500,7 @@ type WaitJWTTokenResponse struct { func (x *WaitJWTTokenResponse) Reset() { *x = WaitJWTTokenResponse{} - mi := &file_daemon_proto_msgTypes[78] + mi := &file_daemon_proto_msgTypes[80] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5432,7 +5512,7 @@ func (x *WaitJWTTokenResponse) String() string { func (*WaitJWTTokenResponse) ProtoMessage() {} func (x *WaitJWTTokenResponse) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[78] + mi := &file_daemon_proto_msgTypes[80] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5445,7 +5525,7 @@ func (x *WaitJWTTokenResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use WaitJWTTokenResponse.ProtoReflect.Descriptor instead. func (*WaitJWTTokenResponse) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{78} + return file_daemon_proto_rawDescGZIP(), []int{80} } func (x *WaitJWTTokenResponse) GetToken() string { @@ -5481,7 +5561,7 @@ type RequestExtendAuthSessionRequest struct { func (x *RequestExtendAuthSessionRequest) Reset() { *x = RequestExtendAuthSessionRequest{} - mi := &file_daemon_proto_msgTypes[79] + mi := &file_daemon_proto_msgTypes[81] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5493,7 +5573,7 @@ func (x *RequestExtendAuthSessionRequest) String() string { func (*RequestExtendAuthSessionRequest) ProtoMessage() {} func (x *RequestExtendAuthSessionRequest) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[79] + mi := &file_daemon_proto_msgTypes[81] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5506,7 +5586,7 @@ func (x *RequestExtendAuthSessionRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use RequestExtendAuthSessionRequest.ProtoReflect.Descriptor instead. func (*RequestExtendAuthSessionRequest) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{79} + return file_daemon_proto_rawDescGZIP(), []int{81} } func (x *RequestExtendAuthSessionRequest) GetHint() string { @@ -5537,7 +5617,7 @@ type RequestExtendAuthSessionResponse struct { func (x *RequestExtendAuthSessionResponse) Reset() { *x = RequestExtendAuthSessionResponse{} - mi := &file_daemon_proto_msgTypes[80] + mi := &file_daemon_proto_msgTypes[82] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5549,7 +5629,7 @@ func (x *RequestExtendAuthSessionResponse) String() string { func (*RequestExtendAuthSessionResponse) ProtoMessage() {} func (x *RequestExtendAuthSessionResponse) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[80] + mi := &file_daemon_proto_msgTypes[82] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5562,7 +5642,7 @@ func (x *RequestExtendAuthSessionResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use RequestExtendAuthSessionResponse.ProtoReflect.Descriptor instead. func (*RequestExtendAuthSessionResponse) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{80} + return file_daemon_proto_rawDescGZIP(), []int{82} } func (x *RequestExtendAuthSessionResponse) GetVerificationURI() string { @@ -5615,7 +5695,7 @@ type WaitExtendAuthSessionRequest struct { func (x *WaitExtendAuthSessionRequest) Reset() { *x = WaitExtendAuthSessionRequest{} - mi := &file_daemon_proto_msgTypes[81] + mi := &file_daemon_proto_msgTypes[83] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5627,7 +5707,7 @@ func (x *WaitExtendAuthSessionRequest) String() string { func (*WaitExtendAuthSessionRequest) ProtoMessage() {} func (x *WaitExtendAuthSessionRequest) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[81] + mi := &file_daemon_proto_msgTypes[83] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5640,7 +5720,7 @@ func (x *WaitExtendAuthSessionRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use WaitExtendAuthSessionRequest.ProtoReflect.Descriptor instead. func (*WaitExtendAuthSessionRequest) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{81} + return file_daemon_proto_rawDescGZIP(), []int{83} } func (x *WaitExtendAuthSessionRequest) GetDeviceCode() string { @@ -5669,7 +5749,7 @@ type WaitExtendAuthSessionResponse struct { func (x *WaitExtendAuthSessionResponse) Reset() { *x = WaitExtendAuthSessionResponse{} - mi := &file_daemon_proto_msgTypes[82] + mi := &file_daemon_proto_msgTypes[84] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5681,7 +5761,7 @@ func (x *WaitExtendAuthSessionResponse) String() string { func (*WaitExtendAuthSessionResponse) ProtoMessage() {} func (x *WaitExtendAuthSessionResponse) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[82] + mi := &file_daemon_proto_msgTypes[84] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5694,7 +5774,7 @@ func (x *WaitExtendAuthSessionResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use WaitExtendAuthSessionResponse.ProtoReflect.Descriptor instead. func (*WaitExtendAuthSessionResponse) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{82} + return file_daemon_proto_rawDescGZIP(), []int{84} } func (x *WaitExtendAuthSessionResponse) GetSessionExpiresAt() *timestamppb.Timestamp { @@ -5714,7 +5794,7 @@ type DismissSessionWarningRequest struct { func (x *DismissSessionWarningRequest) Reset() { *x = DismissSessionWarningRequest{} - mi := &file_daemon_proto_msgTypes[83] + mi := &file_daemon_proto_msgTypes[85] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5726,7 +5806,7 @@ func (x *DismissSessionWarningRequest) String() string { func (*DismissSessionWarningRequest) ProtoMessage() {} func (x *DismissSessionWarningRequest) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[83] + mi := &file_daemon_proto_msgTypes[85] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5739,7 +5819,7 @@ func (x *DismissSessionWarningRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DismissSessionWarningRequest.ProtoReflect.Descriptor instead. func (*DismissSessionWarningRequest) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{83} + return file_daemon_proto_rawDescGZIP(), []int{85} } // DismissSessionWarningResponse acknowledges the dismissal. Carries no @@ -5753,7 +5833,7 @@ type DismissSessionWarningResponse struct { func (x *DismissSessionWarningResponse) Reset() { *x = DismissSessionWarningResponse{} - mi := &file_daemon_proto_msgTypes[84] + mi := &file_daemon_proto_msgTypes[86] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5765,7 +5845,7 @@ func (x *DismissSessionWarningResponse) String() string { func (*DismissSessionWarningResponse) ProtoMessage() {} func (x *DismissSessionWarningResponse) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[84] + mi := &file_daemon_proto_msgTypes[86] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5778,7 +5858,7 @@ func (x *DismissSessionWarningResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use DismissSessionWarningResponse.ProtoReflect.Descriptor instead. func (*DismissSessionWarningResponse) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{84} + return file_daemon_proto_rawDescGZIP(), []int{86} } // StartCPUProfileRequest for starting CPU profiling @@ -5790,7 +5870,7 @@ type StartCPUProfileRequest struct { func (x *StartCPUProfileRequest) Reset() { *x = StartCPUProfileRequest{} - mi := &file_daemon_proto_msgTypes[85] + mi := &file_daemon_proto_msgTypes[87] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5802,7 +5882,7 @@ func (x *StartCPUProfileRequest) String() string { func (*StartCPUProfileRequest) ProtoMessage() {} func (x *StartCPUProfileRequest) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[85] + mi := &file_daemon_proto_msgTypes[87] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5815,7 +5895,7 @@ func (x *StartCPUProfileRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use StartCPUProfileRequest.ProtoReflect.Descriptor instead. func (*StartCPUProfileRequest) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{85} + return file_daemon_proto_rawDescGZIP(), []int{87} } // StartCPUProfileResponse confirms CPU profiling has started @@ -5827,7 +5907,7 @@ type StartCPUProfileResponse struct { func (x *StartCPUProfileResponse) Reset() { *x = StartCPUProfileResponse{} - mi := &file_daemon_proto_msgTypes[86] + mi := &file_daemon_proto_msgTypes[88] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5839,7 +5919,7 @@ func (x *StartCPUProfileResponse) String() string { func (*StartCPUProfileResponse) ProtoMessage() {} func (x *StartCPUProfileResponse) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[86] + mi := &file_daemon_proto_msgTypes[88] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5852,7 +5932,7 @@ func (x *StartCPUProfileResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use StartCPUProfileResponse.ProtoReflect.Descriptor instead. func (*StartCPUProfileResponse) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{86} + return file_daemon_proto_rawDescGZIP(), []int{88} } // StopCPUProfileRequest for stopping CPU profiling @@ -5864,7 +5944,7 @@ type StopCPUProfileRequest struct { func (x *StopCPUProfileRequest) Reset() { *x = StopCPUProfileRequest{} - mi := &file_daemon_proto_msgTypes[87] + mi := &file_daemon_proto_msgTypes[89] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5876,7 +5956,7 @@ func (x *StopCPUProfileRequest) String() string { func (*StopCPUProfileRequest) ProtoMessage() {} func (x *StopCPUProfileRequest) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[87] + mi := &file_daemon_proto_msgTypes[89] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5889,7 +5969,7 @@ func (x *StopCPUProfileRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use StopCPUProfileRequest.ProtoReflect.Descriptor instead. func (*StopCPUProfileRequest) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{87} + return file_daemon_proto_rawDescGZIP(), []int{89} } // StopCPUProfileResponse confirms CPU profiling has stopped @@ -5901,7 +5981,7 @@ type StopCPUProfileResponse struct { func (x *StopCPUProfileResponse) Reset() { *x = StopCPUProfileResponse{} - mi := &file_daemon_proto_msgTypes[88] + mi := &file_daemon_proto_msgTypes[90] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5913,7 +5993,7 @@ func (x *StopCPUProfileResponse) String() string { func (*StopCPUProfileResponse) ProtoMessage() {} func (x *StopCPUProfileResponse) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[88] + mi := &file_daemon_proto_msgTypes[90] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5926,7 +6006,7 @@ func (x *StopCPUProfileResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use StopCPUProfileResponse.ProtoReflect.Descriptor instead. func (*StopCPUProfileResponse) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{88} + return file_daemon_proto_rawDescGZIP(), []int{90} } type InstallerResultRequest struct { @@ -5937,7 +6017,7 @@ type InstallerResultRequest struct { func (x *InstallerResultRequest) Reset() { *x = InstallerResultRequest{} - mi := &file_daemon_proto_msgTypes[89] + mi := &file_daemon_proto_msgTypes[91] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5949,7 +6029,7 @@ func (x *InstallerResultRequest) String() string { func (*InstallerResultRequest) ProtoMessage() {} func (x *InstallerResultRequest) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[89] + mi := &file_daemon_proto_msgTypes[91] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5962,7 +6042,7 @@ func (x *InstallerResultRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use InstallerResultRequest.ProtoReflect.Descriptor instead. func (*InstallerResultRequest) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{89} + return file_daemon_proto_rawDescGZIP(), []int{91} } type InstallerResultResponse struct { @@ -5975,7 +6055,7 @@ type InstallerResultResponse struct { func (x *InstallerResultResponse) Reset() { *x = InstallerResultResponse{} - mi := &file_daemon_proto_msgTypes[90] + mi := &file_daemon_proto_msgTypes[92] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5987,7 +6067,7 @@ func (x *InstallerResultResponse) String() string { func (*InstallerResultResponse) ProtoMessage() {} func (x *InstallerResultResponse) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[90] + mi := &file_daemon_proto_msgTypes[92] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6000,7 +6080,7 @@ func (x *InstallerResultResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use InstallerResultResponse.ProtoReflect.Descriptor instead. func (*InstallerResultResponse) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{90} + return file_daemon_proto_rawDescGZIP(), []int{92} } func (x *InstallerResultResponse) GetSuccess() bool { @@ -6033,7 +6113,7 @@ type ExposeServiceRequest struct { func (x *ExposeServiceRequest) Reset() { *x = ExposeServiceRequest{} - mi := &file_daemon_proto_msgTypes[91] + mi := &file_daemon_proto_msgTypes[93] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6045,7 +6125,7 @@ func (x *ExposeServiceRequest) String() string { func (*ExposeServiceRequest) ProtoMessage() {} func (x *ExposeServiceRequest) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[91] + mi := &file_daemon_proto_msgTypes[93] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6058,7 +6138,7 @@ func (x *ExposeServiceRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ExposeServiceRequest.ProtoReflect.Descriptor instead. func (*ExposeServiceRequest) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{91} + return file_daemon_proto_rawDescGZIP(), []int{93} } func (x *ExposeServiceRequest) GetPort() uint32 { @@ -6129,7 +6209,7 @@ type ExposeServiceEvent struct { func (x *ExposeServiceEvent) Reset() { *x = ExposeServiceEvent{} - mi := &file_daemon_proto_msgTypes[92] + mi := &file_daemon_proto_msgTypes[94] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6141,7 +6221,7 @@ func (x *ExposeServiceEvent) String() string { func (*ExposeServiceEvent) ProtoMessage() {} func (x *ExposeServiceEvent) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[92] + mi := &file_daemon_proto_msgTypes[94] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6154,7 +6234,7 @@ func (x *ExposeServiceEvent) ProtoReflect() protoreflect.Message { // Deprecated: Use ExposeServiceEvent.ProtoReflect.Descriptor instead. func (*ExposeServiceEvent) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{92} + return file_daemon_proto_rawDescGZIP(), []int{94} } func (x *ExposeServiceEvent) GetEvent() isExposeServiceEvent_Event { @@ -6195,7 +6275,7 @@ type ExposeServiceReady struct { func (x *ExposeServiceReady) Reset() { *x = ExposeServiceReady{} - mi := &file_daemon_proto_msgTypes[93] + mi := &file_daemon_proto_msgTypes[95] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6207,7 +6287,7 @@ func (x *ExposeServiceReady) String() string { func (*ExposeServiceReady) ProtoMessage() {} func (x *ExposeServiceReady) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[93] + mi := &file_daemon_proto_msgTypes[95] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6220,7 +6300,7 @@ func (x *ExposeServiceReady) ProtoReflect() protoreflect.Message { // Deprecated: Use ExposeServiceReady.ProtoReflect.Descriptor instead. func (*ExposeServiceReady) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{93} + return file_daemon_proto_rawDescGZIP(), []int{95} } func (x *ExposeServiceReady) GetServiceName() string { @@ -6265,7 +6345,7 @@ type StartCaptureRequest struct { func (x *StartCaptureRequest) Reset() { *x = StartCaptureRequest{} - mi := &file_daemon_proto_msgTypes[94] + mi := &file_daemon_proto_msgTypes[96] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6277,7 +6357,7 @@ func (x *StartCaptureRequest) String() string { func (*StartCaptureRequest) ProtoMessage() {} func (x *StartCaptureRequest) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[94] + mi := &file_daemon_proto_msgTypes[96] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6290,7 +6370,7 @@ func (x *StartCaptureRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use StartCaptureRequest.ProtoReflect.Descriptor instead. func (*StartCaptureRequest) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{94} + return file_daemon_proto_rawDescGZIP(), []int{96} } func (x *StartCaptureRequest) GetTextOutput() bool { @@ -6344,7 +6424,7 @@ type CapturePacket struct { func (x *CapturePacket) Reset() { *x = CapturePacket{} - mi := &file_daemon_proto_msgTypes[95] + mi := &file_daemon_proto_msgTypes[97] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6356,7 +6436,7 @@ func (x *CapturePacket) String() string { func (*CapturePacket) ProtoMessage() {} func (x *CapturePacket) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[95] + mi := &file_daemon_proto_msgTypes[97] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6369,7 +6449,7 @@ func (x *CapturePacket) ProtoReflect() protoreflect.Message { // Deprecated: Use CapturePacket.ProtoReflect.Descriptor instead. func (*CapturePacket) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{95} + return file_daemon_proto_rawDescGZIP(), []int{97} } func (x *CapturePacket) GetData() []byte { @@ -6390,7 +6470,7 @@ type StartBundleCaptureRequest struct { func (x *StartBundleCaptureRequest) Reset() { *x = StartBundleCaptureRequest{} - mi := &file_daemon_proto_msgTypes[96] + mi := &file_daemon_proto_msgTypes[98] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6402,7 +6482,7 @@ func (x *StartBundleCaptureRequest) String() string { func (*StartBundleCaptureRequest) ProtoMessage() {} func (x *StartBundleCaptureRequest) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[96] + mi := &file_daemon_proto_msgTypes[98] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6415,7 +6495,7 @@ func (x *StartBundleCaptureRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use StartBundleCaptureRequest.ProtoReflect.Descriptor instead. func (*StartBundleCaptureRequest) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{96} + return file_daemon_proto_rawDescGZIP(), []int{98} } func (x *StartBundleCaptureRequest) GetTimeout() *durationpb.Duration { @@ -6433,7 +6513,7 @@ type StartBundleCaptureResponse struct { func (x *StartBundleCaptureResponse) Reset() { *x = StartBundleCaptureResponse{} - mi := &file_daemon_proto_msgTypes[97] + mi := &file_daemon_proto_msgTypes[99] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6445,7 +6525,7 @@ func (x *StartBundleCaptureResponse) String() string { func (*StartBundleCaptureResponse) ProtoMessage() {} func (x *StartBundleCaptureResponse) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[97] + mi := &file_daemon_proto_msgTypes[99] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6458,7 +6538,7 @@ func (x *StartBundleCaptureResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use StartBundleCaptureResponse.ProtoReflect.Descriptor instead. func (*StartBundleCaptureResponse) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{97} + return file_daemon_proto_rawDescGZIP(), []int{99} } type StopBundleCaptureRequest struct { @@ -6469,7 +6549,7 @@ type StopBundleCaptureRequest struct { func (x *StopBundleCaptureRequest) Reset() { *x = StopBundleCaptureRequest{} - mi := &file_daemon_proto_msgTypes[98] + mi := &file_daemon_proto_msgTypes[100] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6481,7 +6561,7 @@ func (x *StopBundleCaptureRequest) String() string { func (*StopBundleCaptureRequest) ProtoMessage() {} func (x *StopBundleCaptureRequest) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[98] + mi := &file_daemon_proto_msgTypes[100] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6494,7 +6574,7 @@ func (x *StopBundleCaptureRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use StopBundleCaptureRequest.ProtoReflect.Descriptor instead. func (*StopBundleCaptureRequest) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{98} + return file_daemon_proto_rawDescGZIP(), []int{100} } type StopBundleCaptureResponse struct { @@ -6505,7 +6585,7 @@ type StopBundleCaptureResponse struct { func (x *StopBundleCaptureResponse) Reset() { *x = StopBundleCaptureResponse{} - mi := &file_daemon_proto_msgTypes[99] + mi := &file_daemon_proto_msgTypes[101] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6517,7 +6597,7 @@ func (x *StopBundleCaptureResponse) String() string { func (*StopBundleCaptureResponse) ProtoMessage() {} func (x *StopBundleCaptureResponse) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[99] + mi := &file_daemon_proto_msgTypes[101] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6530,7 +6610,7 @@ func (x *StopBundleCaptureResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use StopBundleCaptureResponse.ProtoReflect.Descriptor instead. func (*StopBundleCaptureResponse) Descriptor() ([]byte, []int) { - return file_daemon_proto_rawDescGZIP(), []int{99} + return file_daemon_proto_rawDescGZIP(), []int{101} } type PortInfo_Range struct { @@ -6543,7 +6623,7 @@ type PortInfo_Range struct { func (x *PortInfo_Range) Reset() { *x = PortInfo_Range{} - mi := &file_daemon_proto_msgTypes[101] + mi := &file_daemon_proto_msgTypes[103] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6555,7 +6635,7 @@ func (x *PortInfo_Range) String() string { func (*PortInfo_Range) ProtoMessage() {} func (x *PortInfo_Range) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[101] + mi := &file_daemon_proto_msgTypes[103] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6863,7 +6943,10 @@ const file_daemon_proto_rawDesc = "" + "\x05level\x18\x01 \x01(\x0e2\x10.daemon.LogLevelR\x05level\"<\n" + "\x12SetLogLevelRequest\x12&\n" + "\x05level\x18\x01 \x01(\x0e2\x10.daemon.LogLevelR\x05level\"\x15\n" + - "\x13SetLogLevelResponse\"\x1b\n" + + "\x13SetLogLevelResponse\"*\n" + + "\x14RegisterUILogRequest\x12\x12\n" + + "\x04path\x18\x01 \x01(\tR\x04path\"\x17\n" + + "\x15RegisterUILogResponse\"\x1b\n" + "\x05State\x12\x12\n" + "\x04name\x18\x01 \x01(\tR\x04name\"\x13\n" + "\x11ListStatesRequest\";\n" + @@ -7164,7 +7247,7 @@ const file_daemon_proto_rawDesc = "" + "\n" + "EXPOSE_UDP\x10\x03\x12\x0e\n" + "\n" + - "EXPOSE_TLS\x10\x042\xb6\x1a\n" + + "EXPOSE_TLS\x10\x042\x86\x1b\n" + "\rDaemonService\x126\n" + "\x05Login\x12\x14.daemon.LoginRequest\x1a\x15.daemon.LoginResponse\"\x00\x12K\n" + "\fWaitSSOLogin\x12\x1b.daemon.WaitSSOLoginRequest\x1a\x1c.daemon.WaitSSOLoginResponse\"\x00\x12-\n" + @@ -7192,6 +7275,7 @@ const file_daemon_proto_rawDesc = "" + "\x11StopBundleCapture\x12 .daemon.StopBundleCaptureRequest\x1a!.daemon.StopBundleCaptureResponse\"\x00\x12D\n" + "\x0fSubscribeEvents\x12\x18.daemon.SubscribeRequest\x1a\x13.daemon.SystemEvent\"\x000\x01\x12B\n" + "\tGetEvents\x12\x18.daemon.GetEventsRequest\x1a\x19.daemon.GetEventsResponse\"\x00\x12N\n" + + "\rRegisterUILog\x12\x1c.daemon.RegisterUILogRequest\x1a\x1d.daemon.RegisterUILogResponse\"\x00\x12N\n" + "\rSwitchProfile\x12\x1c.daemon.SwitchProfileRequest\x1a\x1d.daemon.SwitchProfileResponse\"\x00\x12B\n" + "\tSetConfig\x12\x18.daemon.SetConfigRequest\x1a\x19.daemon.SetConfigResponse\"\x00\x12E\n" + "\n" + @@ -7226,7 +7310,7 @@ func file_daemon_proto_rawDescGZIP() []byte { } var file_daemon_proto_enumTypes = make([]protoimpl.EnumInfo, 4) -var file_daemon_proto_msgTypes = make([]protoimpl.MessageInfo, 103) +var file_daemon_proto_msgTypes = make([]protoimpl.MessageInfo, 105) var file_daemon_proto_goTypes = []any{ (LogLevel)(0), // 0: daemon.LogLevel (ExposeProtocol)(0), // 1: daemon.ExposeProtocol @@ -7269,82 +7353,84 @@ var file_daemon_proto_goTypes = []any{ (*GetLogLevelResponse)(nil), // 38: daemon.GetLogLevelResponse (*SetLogLevelRequest)(nil), // 39: daemon.SetLogLevelRequest (*SetLogLevelResponse)(nil), // 40: daemon.SetLogLevelResponse - (*State)(nil), // 41: daemon.State - (*ListStatesRequest)(nil), // 42: daemon.ListStatesRequest - (*ListStatesResponse)(nil), // 43: daemon.ListStatesResponse - (*CleanStateRequest)(nil), // 44: daemon.CleanStateRequest - (*CleanStateResponse)(nil), // 45: daemon.CleanStateResponse - (*DeleteStateRequest)(nil), // 46: daemon.DeleteStateRequest - (*DeleteStateResponse)(nil), // 47: daemon.DeleteStateResponse - (*SetSyncResponsePersistenceRequest)(nil), // 48: daemon.SetSyncResponsePersistenceRequest - (*SetSyncResponsePersistenceResponse)(nil), // 49: daemon.SetSyncResponsePersistenceResponse - (*TCPFlags)(nil), // 50: daemon.TCPFlags - (*TracePacketRequest)(nil), // 51: daemon.TracePacketRequest - (*TraceStage)(nil), // 52: daemon.TraceStage - (*TracePacketResponse)(nil), // 53: daemon.TracePacketResponse - (*SubscribeRequest)(nil), // 54: daemon.SubscribeRequest - (*SystemEvent)(nil), // 55: daemon.SystemEvent - (*GetEventsRequest)(nil), // 56: daemon.GetEventsRequest - (*GetEventsResponse)(nil), // 57: daemon.GetEventsResponse - (*SwitchProfileRequest)(nil), // 58: daemon.SwitchProfileRequest - (*SwitchProfileResponse)(nil), // 59: daemon.SwitchProfileResponse - (*SetConfigRequest)(nil), // 60: daemon.SetConfigRequest - (*SetConfigResponse)(nil), // 61: daemon.SetConfigResponse - (*AddProfileRequest)(nil), // 62: daemon.AddProfileRequest - (*AddProfileResponse)(nil), // 63: daemon.AddProfileResponse - (*RemoveProfileRequest)(nil), // 64: daemon.RemoveProfileRequest - (*RemoveProfileResponse)(nil), // 65: daemon.RemoveProfileResponse - (*ListProfilesRequest)(nil), // 66: daemon.ListProfilesRequest - (*ListProfilesResponse)(nil), // 67: daemon.ListProfilesResponse - (*Profile)(nil), // 68: daemon.Profile - (*GetActiveProfileRequest)(nil), // 69: daemon.GetActiveProfileRequest - (*GetActiveProfileResponse)(nil), // 70: daemon.GetActiveProfileResponse - (*LogoutRequest)(nil), // 71: daemon.LogoutRequest - (*LogoutResponse)(nil), // 72: daemon.LogoutResponse - (*GetFeaturesRequest)(nil), // 73: daemon.GetFeaturesRequest - (*GetFeaturesResponse)(nil), // 74: daemon.GetFeaturesResponse - (*TriggerUpdateRequest)(nil), // 75: daemon.TriggerUpdateRequest - (*TriggerUpdateResponse)(nil), // 76: daemon.TriggerUpdateResponse - (*GetPeerSSHHostKeyRequest)(nil), // 77: daemon.GetPeerSSHHostKeyRequest - (*GetPeerSSHHostKeyResponse)(nil), // 78: daemon.GetPeerSSHHostKeyResponse - (*RequestJWTAuthRequest)(nil), // 79: daemon.RequestJWTAuthRequest - (*RequestJWTAuthResponse)(nil), // 80: daemon.RequestJWTAuthResponse - (*WaitJWTTokenRequest)(nil), // 81: daemon.WaitJWTTokenRequest - (*WaitJWTTokenResponse)(nil), // 82: daemon.WaitJWTTokenResponse - (*RequestExtendAuthSessionRequest)(nil), // 83: daemon.RequestExtendAuthSessionRequest - (*RequestExtendAuthSessionResponse)(nil), // 84: daemon.RequestExtendAuthSessionResponse - (*WaitExtendAuthSessionRequest)(nil), // 85: daemon.WaitExtendAuthSessionRequest - (*WaitExtendAuthSessionResponse)(nil), // 86: daemon.WaitExtendAuthSessionResponse - (*DismissSessionWarningRequest)(nil), // 87: daemon.DismissSessionWarningRequest - (*DismissSessionWarningResponse)(nil), // 88: daemon.DismissSessionWarningResponse - (*StartCPUProfileRequest)(nil), // 89: daemon.StartCPUProfileRequest - (*StartCPUProfileResponse)(nil), // 90: daemon.StartCPUProfileResponse - (*StopCPUProfileRequest)(nil), // 91: daemon.StopCPUProfileRequest - (*StopCPUProfileResponse)(nil), // 92: daemon.StopCPUProfileResponse - (*InstallerResultRequest)(nil), // 93: daemon.InstallerResultRequest - (*InstallerResultResponse)(nil), // 94: daemon.InstallerResultResponse - (*ExposeServiceRequest)(nil), // 95: daemon.ExposeServiceRequest - (*ExposeServiceEvent)(nil), // 96: daemon.ExposeServiceEvent - (*ExposeServiceReady)(nil), // 97: daemon.ExposeServiceReady - (*StartCaptureRequest)(nil), // 98: daemon.StartCaptureRequest - (*CapturePacket)(nil), // 99: daemon.CapturePacket - (*StartBundleCaptureRequest)(nil), // 100: daemon.StartBundleCaptureRequest - (*StartBundleCaptureResponse)(nil), // 101: daemon.StartBundleCaptureResponse - (*StopBundleCaptureRequest)(nil), // 102: daemon.StopBundleCaptureRequest - (*StopBundleCaptureResponse)(nil), // 103: daemon.StopBundleCaptureResponse - nil, // 104: daemon.Network.ResolvedIPsEntry - (*PortInfo_Range)(nil), // 105: daemon.PortInfo.Range - nil, // 106: daemon.SystemEvent.MetadataEntry - (*durationpb.Duration)(nil), // 107: google.protobuf.Duration - (*timestamppb.Timestamp)(nil), // 108: google.protobuf.Timestamp + (*RegisterUILogRequest)(nil), // 41: daemon.RegisterUILogRequest + (*RegisterUILogResponse)(nil), // 42: daemon.RegisterUILogResponse + (*State)(nil), // 43: daemon.State + (*ListStatesRequest)(nil), // 44: daemon.ListStatesRequest + (*ListStatesResponse)(nil), // 45: daemon.ListStatesResponse + (*CleanStateRequest)(nil), // 46: daemon.CleanStateRequest + (*CleanStateResponse)(nil), // 47: daemon.CleanStateResponse + (*DeleteStateRequest)(nil), // 48: daemon.DeleteStateRequest + (*DeleteStateResponse)(nil), // 49: daemon.DeleteStateResponse + (*SetSyncResponsePersistenceRequest)(nil), // 50: daemon.SetSyncResponsePersistenceRequest + (*SetSyncResponsePersistenceResponse)(nil), // 51: daemon.SetSyncResponsePersistenceResponse + (*TCPFlags)(nil), // 52: daemon.TCPFlags + (*TracePacketRequest)(nil), // 53: daemon.TracePacketRequest + (*TraceStage)(nil), // 54: daemon.TraceStage + (*TracePacketResponse)(nil), // 55: daemon.TracePacketResponse + (*SubscribeRequest)(nil), // 56: daemon.SubscribeRequest + (*SystemEvent)(nil), // 57: daemon.SystemEvent + (*GetEventsRequest)(nil), // 58: daemon.GetEventsRequest + (*GetEventsResponse)(nil), // 59: daemon.GetEventsResponse + (*SwitchProfileRequest)(nil), // 60: daemon.SwitchProfileRequest + (*SwitchProfileResponse)(nil), // 61: daemon.SwitchProfileResponse + (*SetConfigRequest)(nil), // 62: daemon.SetConfigRequest + (*SetConfigResponse)(nil), // 63: daemon.SetConfigResponse + (*AddProfileRequest)(nil), // 64: daemon.AddProfileRequest + (*AddProfileResponse)(nil), // 65: daemon.AddProfileResponse + (*RemoveProfileRequest)(nil), // 66: daemon.RemoveProfileRequest + (*RemoveProfileResponse)(nil), // 67: daemon.RemoveProfileResponse + (*ListProfilesRequest)(nil), // 68: daemon.ListProfilesRequest + (*ListProfilesResponse)(nil), // 69: daemon.ListProfilesResponse + (*Profile)(nil), // 70: daemon.Profile + (*GetActiveProfileRequest)(nil), // 71: daemon.GetActiveProfileRequest + (*GetActiveProfileResponse)(nil), // 72: daemon.GetActiveProfileResponse + (*LogoutRequest)(nil), // 73: daemon.LogoutRequest + (*LogoutResponse)(nil), // 74: daemon.LogoutResponse + (*GetFeaturesRequest)(nil), // 75: daemon.GetFeaturesRequest + (*GetFeaturesResponse)(nil), // 76: daemon.GetFeaturesResponse + (*TriggerUpdateRequest)(nil), // 77: daemon.TriggerUpdateRequest + (*TriggerUpdateResponse)(nil), // 78: daemon.TriggerUpdateResponse + (*GetPeerSSHHostKeyRequest)(nil), // 79: daemon.GetPeerSSHHostKeyRequest + (*GetPeerSSHHostKeyResponse)(nil), // 80: daemon.GetPeerSSHHostKeyResponse + (*RequestJWTAuthRequest)(nil), // 81: daemon.RequestJWTAuthRequest + (*RequestJWTAuthResponse)(nil), // 82: daemon.RequestJWTAuthResponse + (*WaitJWTTokenRequest)(nil), // 83: daemon.WaitJWTTokenRequest + (*WaitJWTTokenResponse)(nil), // 84: daemon.WaitJWTTokenResponse + (*RequestExtendAuthSessionRequest)(nil), // 85: daemon.RequestExtendAuthSessionRequest + (*RequestExtendAuthSessionResponse)(nil), // 86: daemon.RequestExtendAuthSessionResponse + (*WaitExtendAuthSessionRequest)(nil), // 87: daemon.WaitExtendAuthSessionRequest + (*WaitExtendAuthSessionResponse)(nil), // 88: daemon.WaitExtendAuthSessionResponse + (*DismissSessionWarningRequest)(nil), // 89: daemon.DismissSessionWarningRequest + (*DismissSessionWarningResponse)(nil), // 90: daemon.DismissSessionWarningResponse + (*StartCPUProfileRequest)(nil), // 91: daemon.StartCPUProfileRequest + (*StartCPUProfileResponse)(nil), // 92: daemon.StartCPUProfileResponse + (*StopCPUProfileRequest)(nil), // 93: daemon.StopCPUProfileRequest + (*StopCPUProfileResponse)(nil), // 94: daemon.StopCPUProfileResponse + (*InstallerResultRequest)(nil), // 95: daemon.InstallerResultRequest + (*InstallerResultResponse)(nil), // 96: daemon.InstallerResultResponse + (*ExposeServiceRequest)(nil), // 97: daemon.ExposeServiceRequest + (*ExposeServiceEvent)(nil), // 98: daemon.ExposeServiceEvent + (*ExposeServiceReady)(nil), // 99: daemon.ExposeServiceReady + (*StartCaptureRequest)(nil), // 100: daemon.StartCaptureRequest + (*CapturePacket)(nil), // 101: daemon.CapturePacket + (*StartBundleCaptureRequest)(nil), // 102: daemon.StartBundleCaptureRequest + (*StartBundleCaptureResponse)(nil), // 103: daemon.StartBundleCaptureResponse + (*StopBundleCaptureRequest)(nil), // 104: daemon.StopBundleCaptureRequest + (*StopBundleCaptureResponse)(nil), // 105: daemon.StopBundleCaptureResponse + nil, // 106: daemon.Network.ResolvedIPsEntry + (*PortInfo_Range)(nil), // 107: daemon.PortInfo.Range + nil, // 108: daemon.SystemEvent.MetadataEntry + (*durationpb.Duration)(nil), // 109: google.protobuf.Duration + (*timestamppb.Timestamp)(nil), // 110: google.protobuf.Timestamp } var file_daemon_proto_depIdxs = []int32{ - 107, // 0: daemon.LoginRequest.dnsRouteInterval:type_name -> google.protobuf.Duration + 109, // 0: daemon.LoginRequest.dnsRouteInterval:type_name -> google.protobuf.Duration 25, // 1: daemon.StatusResponse.fullStatus:type_name -> daemon.FullStatus - 108, // 2: daemon.StatusResponse.sessionExpiresAt:type_name -> google.protobuf.Timestamp - 108, // 3: daemon.PeerState.connStatusUpdate:type_name -> google.protobuf.Timestamp - 108, // 4: daemon.PeerState.lastWireguardHandshake:type_name -> google.protobuf.Timestamp - 107, // 5: daemon.PeerState.latency:type_name -> google.protobuf.Duration + 110, // 2: daemon.StatusResponse.sessionExpiresAt:type_name -> google.protobuf.Timestamp + 110, // 3: daemon.PeerState.connStatusUpdate:type_name -> google.protobuf.Timestamp + 110, // 4: daemon.PeerState.lastWireguardHandshake:type_name -> google.protobuf.Timestamp + 109, // 5: daemon.PeerState.latency:type_name -> google.protobuf.Duration 23, // 6: daemon.SSHServerState.sessions:type_name -> daemon.SSHSessionInfo 20, // 7: daemon.FullStatus.managementState:type_name -> daemon.ManagementState 19, // 8: daemon.FullStatus.signalState:type_name -> daemon.SignalState @@ -7352,31 +7438,31 @@ var file_daemon_proto_depIdxs = []int32{ 17, // 10: daemon.FullStatus.peers:type_name -> daemon.PeerState 21, // 11: daemon.FullStatus.relays:type_name -> daemon.RelayState 22, // 12: daemon.FullStatus.dns_servers:type_name -> daemon.NSGroupState - 55, // 13: daemon.FullStatus.events:type_name -> daemon.SystemEvent + 57, // 13: daemon.FullStatus.events:type_name -> daemon.SystemEvent 24, // 14: daemon.FullStatus.sshServerState:type_name -> daemon.SSHServerState 31, // 15: daemon.ListNetworksResponse.routes:type_name -> daemon.Network - 104, // 16: daemon.Network.resolvedIPs:type_name -> daemon.Network.ResolvedIPsEntry - 105, // 17: daemon.PortInfo.range:type_name -> daemon.PortInfo.Range + 106, // 16: daemon.Network.resolvedIPs:type_name -> daemon.Network.ResolvedIPsEntry + 107, // 17: daemon.PortInfo.range:type_name -> daemon.PortInfo.Range 32, // 18: daemon.ForwardingRule.destinationPort:type_name -> daemon.PortInfo 32, // 19: daemon.ForwardingRule.translatedPort:type_name -> daemon.PortInfo 33, // 20: daemon.ForwardingRulesResponse.rules:type_name -> daemon.ForwardingRule 0, // 21: daemon.GetLogLevelResponse.level:type_name -> daemon.LogLevel 0, // 22: daemon.SetLogLevelRequest.level:type_name -> daemon.LogLevel - 41, // 23: daemon.ListStatesResponse.states:type_name -> daemon.State - 50, // 24: daemon.TracePacketRequest.tcp_flags:type_name -> daemon.TCPFlags - 52, // 25: daemon.TracePacketResponse.stages:type_name -> daemon.TraceStage + 43, // 23: daemon.ListStatesResponse.states:type_name -> daemon.State + 52, // 24: daemon.TracePacketRequest.tcp_flags:type_name -> daemon.TCPFlags + 54, // 25: daemon.TracePacketResponse.stages:type_name -> daemon.TraceStage 2, // 26: daemon.SystemEvent.severity:type_name -> daemon.SystemEvent.Severity 3, // 27: daemon.SystemEvent.category:type_name -> daemon.SystemEvent.Category - 108, // 28: daemon.SystemEvent.timestamp:type_name -> google.protobuf.Timestamp - 106, // 29: daemon.SystemEvent.metadata:type_name -> daemon.SystemEvent.MetadataEntry - 55, // 30: daemon.GetEventsResponse.events:type_name -> daemon.SystemEvent - 107, // 31: daemon.SetConfigRequest.dnsRouteInterval:type_name -> google.protobuf.Duration - 68, // 32: daemon.ListProfilesResponse.profiles:type_name -> daemon.Profile - 108, // 33: daemon.WaitExtendAuthSessionResponse.sessionExpiresAt:type_name -> google.protobuf.Timestamp + 110, // 28: daemon.SystemEvent.timestamp:type_name -> google.protobuf.Timestamp + 108, // 29: daemon.SystemEvent.metadata:type_name -> daemon.SystemEvent.MetadataEntry + 57, // 30: daemon.GetEventsResponse.events:type_name -> daemon.SystemEvent + 109, // 31: daemon.SetConfigRequest.dnsRouteInterval:type_name -> google.protobuf.Duration + 70, // 32: daemon.ListProfilesResponse.profiles:type_name -> daemon.Profile + 110, // 33: daemon.WaitExtendAuthSessionResponse.sessionExpiresAt:type_name -> google.protobuf.Timestamp 1, // 34: daemon.ExposeServiceRequest.protocol:type_name -> daemon.ExposeProtocol - 97, // 35: daemon.ExposeServiceEvent.ready:type_name -> daemon.ExposeServiceReady - 107, // 36: daemon.StartCaptureRequest.duration:type_name -> google.protobuf.Duration - 107, // 37: daemon.StartBundleCaptureRequest.timeout:type_name -> google.protobuf.Duration + 99, // 35: daemon.ExposeServiceEvent.ready:type_name -> daemon.ExposeServiceReady + 109, // 36: daemon.StartCaptureRequest.duration:type_name -> google.protobuf.Duration + 109, // 37: daemon.StartBundleCaptureRequest.timeout:type_name -> google.protobuf.Duration 30, // 38: daemon.Network.ResolvedIPsEntry.value:type_name -> daemon.IPList 5, // 39: daemon.DaemonService.Login:input_type -> daemon.LoginRequest 7, // 40: daemon.DaemonService.WaitSSOLogin:input_type -> daemon.WaitSSOLoginRequest @@ -7392,80 +7478,82 @@ var file_daemon_proto_depIdxs = []int32{ 35, // 50: daemon.DaemonService.DebugBundle:input_type -> daemon.DebugBundleRequest 37, // 51: daemon.DaemonService.GetLogLevel:input_type -> daemon.GetLogLevelRequest 39, // 52: daemon.DaemonService.SetLogLevel:input_type -> daemon.SetLogLevelRequest - 42, // 53: daemon.DaemonService.ListStates:input_type -> daemon.ListStatesRequest - 44, // 54: daemon.DaemonService.CleanState:input_type -> daemon.CleanStateRequest - 46, // 55: daemon.DaemonService.DeleteState:input_type -> daemon.DeleteStateRequest - 48, // 56: daemon.DaemonService.SetSyncResponsePersistence:input_type -> daemon.SetSyncResponsePersistenceRequest - 51, // 57: daemon.DaemonService.TracePacket:input_type -> daemon.TracePacketRequest - 98, // 58: daemon.DaemonService.StartCapture:input_type -> daemon.StartCaptureRequest - 100, // 59: daemon.DaemonService.StartBundleCapture:input_type -> daemon.StartBundleCaptureRequest - 102, // 60: daemon.DaemonService.StopBundleCapture:input_type -> daemon.StopBundleCaptureRequest - 54, // 61: daemon.DaemonService.SubscribeEvents:input_type -> daemon.SubscribeRequest - 56, // 62: daemon.DaemonService.GetEvents:input_type -> daemon.GetEventsRequest - 58, // 63: daemon.DaemonService.SwitchProfile:input_type -> daemon.SwitchProfileRequest - 60, // 64: daemon.DaemonService.SetConfig:input_type -> daemon.SetConfigRequest - 62, // 65: daemon.DaemonService.AddProfile:input_type -> daemon.AddProfileRequest - 64, // 66: daemon.DaemonService.RemoveProfile:input_type -> daemon.RemoveProfileRequest - 66, // 67: daemon.DaemonService.ListProfiles:input_type -> daemon.ListProfilesRequest - 69, // 68: daemon.DaemonService.GetActiveProfile:input_type -> daemon.GetActiveProfileRequest - 71, // 69: daemon.DaemonService.Logout:input_type -> daemon.LogoutRequest - 73, // 70: daemon.DaemonService.GetFeatures:input_type -> daemon.GetFeaturesRequest - 75, // 71: daemon.DaemonService.TriggerUpdate:input_type -> daemon.TriggerUpdateRequest - 77, // 72: daemon.DaemonService.GetPeerSSHHostKey:input_type -> daemon.GetPeerSSHHostKeyRequest - 79, // 73: daemon.DaemonService.RequestJWTAuth:input_type -> daemon.RequestJWTAuthRequest - 81, // 74: daemon.DaemonService.WaitJWTToken:input_type -> daemon.WaitJWTTokenRequest - 83, // 75: daemon.DaemonService.RequestExtendAuthSession:input_type -> daemon.RequestExtendAuthSessionRequest - 85, // 76: daemon.DaemonService.WaitExtendAuthSession:input_type -> daemon.WaitExtendAuthSessionRequest - 87, // 77: daemon.DaemonService.DismissSessionWarning:input_type -> daemon.DismissSessionWarningRequest - 89, // 78: daemon.DaemonService.StartCPUProfile:input_type -> daemon.StartCPUProfileRequest - 91, // 79: daemon.DaemonService.StopCPUProfile:input_type -> daemon.StopCPUProfileRequest - 93, // 80: daemon.DaemonService.GetInstallerResult:input_type -> daemon.InstallerResultRequest - 95, // 81: daemon.DaemonService.ExposeService:input_type -> daemon.ExposeServiceRequest - 6, // 82: daemon.DaemonService.Login:output_type -> daemon.LoginResponse - 8, // 83: daemon.DaemonService.WaitSSOLogin:output_type -> daemon.WaitSSOLoginResponse - 10, // 84: daemon.DaemonService.Up:output_type -> daemon.UpResponse - 12, // 85: daemon.DaemonService.Status:output_type -> daemon.StatusResponse - 12, // 86: daemon.DaemonService.SubscribeStatus:output_type -> daemon.StatusResponse - 14, // 87: daemon.DaemonService.Down:output_type -> daemon.DownResponse - 16, // 88: daemon.DaemonService.GetConfig:output_type -> daemon.GetConfigResponse - 27, // 89: daemon.DaemonService.ListNetworks:output_type -> daemon.ListNetworksResponse - 29, // 90: daemon.DaemonService.SelectNetworks:output_type -> daemon.SelectNetworksResponse - 29, // 91: daemon.DaemonService.DeselectNetworks:output_type -> daemon.SelectNetworksResponse - 34, // 92: daemon.DaemonService.ForwardingRules:output_type -> daemon.ForwardingRulesResponse - 36, // 93: daemon.DaemonService.DebugBundle:output_type -> daemon.DebugBundleResponse - 38, // 94: daemon.DaemonService.GetLogLevel:output_type -> daemon.GetLogLevelResponse - 40, // 95: daemon.DaemonService.SetLogLevel:output_type -> daemon.SetLogLevelResponse - 43, // 96: daemon.DaemonService.ListStates:output_type -> daemon.ListStatesResponse - 45, // 97: daemon.DaemonService.CleanState:output_type -> daemon.CleanStateResponse - 47, // 98: daemon.DaemonService.DeleteState:output_type -> daemon.DeleteStateResponse - 49, // 99: daemon.DaemonService.SetSyncResponsePersistence:output_type -> daemon.SetSyncResponsePersistenceResponse - 53, // 100: daemon.DaemonService.TracePacket:output_type -> daemon.TracePacketResponse - 99, // 101: daemon.DaemonService.StartCapture:output_type -> daemon.CapturePacket - 101, // 102: daemon.DaemonService.StartBundleCapture:output_type -> daemon.StartBundleCaptureResponse - 103, // 103: daemon.DaemonService.StopBundleCapture:output_type -> daemon.StopBundleCaptureResponse - 55, // 104: daemon.DaemonService.SubscribeEvents:output_type -> daemon.SystemEvent - 57, // 105: daemon.DaemonService.GetEvents:output_type -> daemon.GetEventsResponse - 59, // 106: daemon.DaemonService.SwitchProfile:output_type -> daemon.SwitchProfileResponse - 61, // 107: daemon.DaemonService.SetConfig:output_type -> daemon.SetConfigResponse - 63, // 108: daemon.DaemonService.AddProfile:output_type -> daemon.AddProfileResponse - 65, // 109: daemon.DaemonService.RemoveProfile:output_type -> daemon.RemoveProfileResponse - 67, // 110: daemon.DaemonService.ListProfiles:output_type -> daemon.ListProfilesResponse - 70, // 111: daemon.DaemonService.GetActiveProfile:output_type -> daemon.GetActiveProfileResponse - 72, // 112: daemon.DaemonService.Logout:output_type -> daemon.LogoutResponse - 74, // 113: daemon.DaemonService.GetFeatures:output_type -> daemon.GetFeaturesResponse - 76, // 114: daemon.DaemonService.TriggerUpdate:output_type -> daemon.TriggerUpdateResponse - 78, // 115: daemon.DaemonService.GetPeerSSHHostKey:output_type -> daemon.GetPeerSSHHostKeyResponse - 80, // 116: daemon.DaemonService.RequestJWTAuth:output_type -> daemon.RequestJWTAuthResponse - 82, // 117: daemon.DaemonService.WaitJWTToken:output_type -> daemon.WaitJWTTokenResponse - 84, // 118: daemon.DaemonService.RequestExtendAuthSession:output_type -> daemon.RequestExtendAuthSessionResponse - 86, // 119: daemon.DaemonService.WaitExtendAuthSession:output_type -> daemon.WaitExtendAuthSessionResponse - 88, // 120: daemon.DaemonService.DismissSessionWarning:output_type -> daemon.DismissSessionWarningResponse - 90, // 121: daemon.DaemonService.StartCPUProfile:output_type -> daemon.StartCPUProfileResponse - 92, // 122: daemon.DaemonService.StopCPUProfile:output_type -> daemon.StopCPUProfileResponse - 94, // 123: daemon.DaemonService.GetInstallerResult:output_type -> daemon.InstallerResultResponse - 96, // 124: daemon.DaemonService.ExposeService:output_type -> daemon.ExposeServiceEvent - 82, // [82:125] is the sub-list for method output_type - 39, // [39:82] is the sub-list for method input_type + 44, // 53: daemon.DaemonService.ListStates:input_type -> daemon.ListStatesRequest + 46, // 54: daemon.DaemonService.CleanState:input_type -> daemon.CleanStateRequest + 48, // 55: daemon.DaemonService.DeleteState:input_type -> daemon.DeleteStateRequest + 50, // 56: daemon.DaemonService.SetSyncResponsePersistence:input_type -> daemon.SetSyncResponsePersistenceRequest + 53, // 57: daemon.DaemonService.TracePacket:input_type -> daemon.TracePacketRequest + 100, // 58: daemon.DaemonService.StartCapture:input_type -> daemon.StartCaptureRequest + 102, // 59: daemon.DaemonService.StartBundleCapture:input_type -> daemon.StartBundleCaptureRequest + 104, // 60: daemon.DaemonService.StopBundleCapture:input_type -> daemon.StopBundleCaptureRequest + 56, // 61: daemon.DaemonService.SubscribeEvents:input_type -> daemon.SubscribeRequest + 58, // 62: daemon.DaemonService.GetEvents:input_type -> daemon.GetEventsRequest + 41, // 63: daemon.DaemonService.RegisterUILog:input_type -> daemon.RegisterUILogRequest + 60, // 64: daemon.DaemonService.SwitchProfile:input_type -> daemon.SwitchProfileRequest + 62, // 65: daemon.DaemonService.SetConfig:input_type -> daemon.SetConfigRequest + 64, // 66: daemon.DaemonService.AddProfile:input_type -> daemon.AddProfileRequest + 66, // 67: daemon.DaemonService.RemoveProfile:input_type -> daemon.RemoveProfileRequest + 68, // 68: daemon.DaemonService.ListProfiles:input_type -> daemon.ListProfilesRequest + 71, // 69: daemon.DaemonService.GetActiveProfile:input_type -> daemon.GetActiveProfileRequest + 73, // 70: daemon.DaemonService.Logout:input_type -> daemon.LogoutRequest + 75, // 71: daemon.DaemonService.GetFeatures:input_type -> daemon.GetFeaturesRequest + 77, // 72: daemon.DaemonService.TriggerUpdate:input_type -> daemon.TriggerUpdateRequest + 79, // 73: daemon.DaemonService.GetPeerSSHHostKey:input_type -> daemon.GetPeerSSHHostKeyRequest + 81, // 74: daemon.DaemonService.RequestJWTAuth:input_type -> daemon.RequestJWTAuthRequest + 83, // 75: daemon.DaemonService.WaitJWTToken:input_type -> daemon.WaitJWTTokenRequest + 85, // 76: daemon.DaemonService.RequestExtendAuthSession:input_type -> daemon.RequestExtendAuthSessionRequest + 87, // 77: daemon.DaemonService.WaitExtendAuthSession:input_type -> daemon.WaitExtendAuthSessionRequest + 89, // 78: daemon.DaemonService.DismissSessionWarning:input_type -> daemon.DismissSessionWarningRequest + 91, // 79: daemon.DaemonService.StartCPUProfile:input_type -> daemon.StartCPUProfileRequest + 93, // 80: daemon.DaemonService.StopCPUProfile:input_type -> daemon.StopCPUProfileRequest + 95, // 81: daemon.DaemonService.GetInstallerResult:input_type -> daemon.InstallerResultRequest + 97, // 82: daemon.DaemonService.ExposeService:input_type -> daemon.ExposeServiceRequest + 6, // 83: daemon.DaemonService.Login:output_type -> daemon.LoginResponse + 8, // 84: daemon.DaemonService.WaitSSOLogin:output_type -> daemon.WaitSSOLoginResponse + 10, // 85: daemon.DaemonService.Up:output_type -> daemon.UpResponse + 12, // 86: daemon.DaemonService.Status:output_type -> daemon.StatusResponse + 12, // 87: daemon.DaemonService.SubscribeStatus:output_type -> daemon.StatusResponse + 14, // 88: daemon.DaemonService.Down:output_type -> daemon.DownResponse + 16, // 89: daemon.DaemonService.GetConfig:output_type -> daemon.GetConfigResponse + 27, // 90: daemon.DaemonService.ListNetworks:output_type -> daemon.ListNetworksResponse + 29, // 91: daemon.DaemonService.SelectNetworks:output_type -> daemon.SelectNetworksResponse + 29, // 92: daemon.DaemonService.DeselectNetworks:output_type -> daemon.SelectNetworksResponse + 34, // 93: daemon.DaemonService.ForwardingRules:output_type -> daemon.ForwardingRulesResponse + 36, // 94: daemon.DaemonService.DebugBundle:output_type -> daemon.DebugBundleResponse + 38, // 95: daemon.DaemonService.GetLogLevel:output_type -> daemon.GetLogLevelResponse + 40, // 96: daemon.DaemonService.SetLogLevel:output_type -> daemon.SetLogLevelResponse + 45, // 97: daemon.DaemonService.ListStates:output_type -> daemon.ListStatesResponse + 47, // 98: daemon.DaemonService.CleanState:output_type -> daemon.CleanStateResponse + 49, // 99: daemon.DaemonService.DeleteState:output_type -> daemon.DeleteStateResponse + 51, // 100: daemon.DaemonService.SetSyncResponsePersistence:output_type -> daemon.SetSyncResponsePersistenceResponse + 55, // 101: daemon.DaemonService.TracePacket:output_type -> daemon.TracePacketResponse + 101, // 102: daemon.DaemonService.StartCapture:output_type -> daemon.CapturePacket + 103, // 103: daemon.DaemonService.StartBundleCapture:output_type -> daemon.StartBundleCaptureResponse + 105, // 104: daemon.DaemonService.StopBundleCapture:output_type -> daemon.StopBundleCaptureResponse + 57, // 105: daemon.DaemonService.SubscribeEvents:output_type -> daemon.SystemEvent + 59, // 106: daemon.DaemonService.GetEvents:output_type -> daemon.GetEventsResponse + 42, // 107: daemon.DaemonService.RegisterUILog:output_type -> daemon.RegisterUILogResponse + 61, // 108: daemon.DaemonService.SwitchProfile:output_type -> daemon.SwitchProfileResponse + 63, // 109: daemon.DaemonService.SetConfig:output_type -> daemon.SetConfigResponse + 65, // 110: daemon.DaemonService.AddProfile:output_type -> daemon.AddProfileResponse + 67, // 111: daemon.DaemonService.RemoveProfile:output_type -> daemon.RemoveProfileResponse + 69, // 112: daemon.DaemonService.ListProfiles:output_type -> daemon.ListProfilesResponse + 72, // 113: daemon.DaemonService.GetActiveProfile:output_type -> daemon.GetActiveProfileResponse + 74, // 114: daemon.DaemonService.Logout:output_type -> daemon.LogoutResponse + 76, // 115: daemon.DaemonService.GetFeatures:output_type -> daemon.GetFeaturesResponse + 78, // 116: daemon.DaemonService.TriggerUpdate:output_type -> daemon.TriggerUpdateResponse + 80, // 117: daemon.DaemonService.GetPeerSSHHostKey:output_type -> daemon.GetPeerSSHHostKeyResponse + 82, // 118: daemon.DaemonService.RequestJWTAuth:output_type -> daemon.RequestJWTAuthResponse + 84, // 119: daemon.DaemonService.WaitJWTToken:output_type -> daemon.WaitJWTTokenResponse + 86, // 120: daemon.DaemonService.RequestExtendAuthSession:output_type -> daemon.RequestExtendAuthSessionResponse + 88, // 121: daemon.DaemonService.WaitExtendAuthSession:output_type -> daemon.WaitExtendAuthSessionResponse + 90, // 122: daemon.DaemonService.DismissSessionWarning:output_type -> daemon.DismissSessionWarningResponse + 92, // 123: daemon.DaemonService.StartCPUProfile:output_type -> daemon.StartCPUProfileResponse + 94, // 124: daemon.DaemonService.StopCPUProfile:output_type -> daemon.StopCPUProfileResponse + 96, // 125: daemon.DaemonService.GetInstallerResult:output_type -> daemon.InstallerResultResponse + 98, // 126: daemon.DaemonService.ExposeService:output_type -> daemon.ExposeServiceEvent + 83, // [83:127] is the sub-list for method output_type + 39, // [39:83] is the sub-list for method input_type 39, // [39:39] is the sub-list for extension type_name 39, // [39:39] is the sub-list for extension extendee 0, // [0:39] is the sub-list for field type_name @@ -7483,14 +7571,14 @@ func file_daemon_proto_init() { (*PortInfo_Port)(nil), (*PortInfo_Range_)(nil), } - file_daemon_proto_msgTypes[47].OneofWrappers = []any{} - file_daemon_proto_msgTypes[48].OneofWrappers = []any{} - file_daemon_proto_msgTypes[54].OneofWrappers = []any{} + file_daemon_proto_msgTypes[49].OneofWrappers = []any{} + file_daemon_proto_msgTypes[50].OneofWrappers = []any{} file_daemon_proto_msgTypes[56].OneofWrappers = []any{} - file_daemon_proto_msgTypes[67].OneofWrappers = []any{} - file_daemon_proto_msgTypes[75].OneofWrappers = []any{} - file_daemon_proto_msgTypes[79].OneofWrappers = []any{} - file_daemon_proto_msgTypes[92].OneofWrappers = []any{ + file_daemon_proto_msgTypes[58].OneofWrappers = []any{} + file_daemon_proto_msgTypes[69].OneofWrappers = []any{} + file_daemon_proto_msgTypes[77].OneofWrappers = []any{} + file_daemon_proto_msgTypes[81].OneofWrappers = []any{} + file_daemon_proto_msgTypes[94].OneofWrappers = []any{ (*ExposeServiceEvent_Ready)(nil), } type x struct{} @@ -7499,7 +7587,7 @@ func file_daemon_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_daemon_proto_rawDesc), len(file_daemon_proto_rawDesc)), NumEnums: 4, - NumMessages: 103, + NumMessages: 105, NumExtensions: 0, NumServices: 1, }, diff --git a/client/proto/daemon.proto b/client/proto/daemon.proto index 01d35d5c0..0b95e0811 100644 --- a/client/proto/daemon.proto +++ b/client/proto/daemon.proto @@ -85,6 +85,11 @@ service DaemonService { rpc GetEvents(GetEventsRequest) returns (GetEventsResponse) {} + // RegisterUILog records the desktop UI's absolute log path so the daemon's + // debug bundle can collect it (the daemon runs as root and can't resolve the + // user's config dir). + rpc RegisterUILog(RegisterUILogRequest) returns (RegisterUILogResponse) {} + rpc SwitchProfile(SwitchProfileRequest) returns (SwitchProfileResponse) {} rpc SetConfig(SetConfigRequest) returns (SetConfigResponse) {} @@ -547,6 +552,13 @@ message SetLogLevelRequest { message SetLogLevelResponse { } +message RegisterUILogRequest { + string path = 1; +} + +message RegisterUILogResponse { +} + // State represents a daemon state entry message State { string name = 1; diff --git a/client/proto/daemon_grpc.pb.go b/client/proto/daemon_grpc.pb.go index 72ce14b19..7a4e1201f 100644 --- a/client/proto/daemon_grpc.pb.go +++ b/client/proto/daemon_grpc.pb.go @@ -68,6 +68,10 @@ type DaemonServiceClient interface { StopBundleCapture(ctx context.Context, in *StopBundleCaptureRequest, opts ...grpc.CallOption) (*StopBundleCaptureResponse, error) SubscribeEvents(ctx context.Context, in *SubscribeRequest, opts ...grpc.CallOption) (DaemonService_SubscribeEventsClient, error) GetEvents(ctx context.Context, in *GetEventsRequest, opts ...grpc.CallOption) (*GetEventsResponse, error) + // RegisterUILog records the desktop UI's absolute log path so the daemon's + // debug bundle can collect it (the daemon runs as root and can't resolve the + // user's config dir). + RegisterUILog(ctx context.Context, in *RegisterUILogRequest, opts ...grpc.CallOption) (*RegisterUILogResponse, error) SwitchProfile(ctx context.Context, in *SwitchProfileRequest, opts ...grpc.CallOption) (*SwitchProfileResponse, error) SetConfig(ctx context.Context, in *SetConfigRequest, opts ...grpc.CallOption) (*SetConfigResponse, error) AddProfile(ctx context.Context, in *AddProfileRequest, opts ...grpc.CallOption) (*AddProfileResponse, error) @@ -404,6 +408,15 @@ func (c *daemonServiceClient) GetEvents(ctx context.Context, in *GetEventsReques return out, nil } +func (c *daemonServiceClient) RegisterUILog(ctx context.Context, in *RegisterUILogRequest, opts ...grpc.CallOption) (*RegisterUILogResponse, error) { + out := new(RegisterUILogResponse) + err := c.cc.Invoke(ctx, "/daemon.DaemonService/RegisterUILog", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *daemonServiceClient) SwitchProfile(ctx context.Context, in *SwitchProfileRequest, opts ...grpc.CallOption) (*SwitchProfileResponse, error) { out := new(SwitchProfileResponse) err := c.cc.Invoke(ctx, "/daemon.DaemonService/SwitchProfile", in, out, opts...) @@ -652,6 +665,10 @@ type DaemonServiceServer interface { StopBundleCapture(context.Context, *StopBundleCaptureRequest) (*StopBundleCaptureResponse, error) SubscribeEvents(*SubscribeRequest, DaemonService_SubscribeEventsServer) error GetEvents(context.Context, *GetEventsRequest) (*GetEventsResponse, error) + // RegisterUILog records the desktop UI's absolute log path so the daemon's + // debug bundle can collect it (the daemon runs as root and can't resolve the + // user's config dir). + RegisterUILog(context.Context, *RegisterUILogRequest) (*RegisterUILogResponse, error) SwitchProfile(context.Context, *SwitchProfileRequest) (*SwitchProfileResponse, error) SetConfig(context.Context, *SetConfigRequest) (*SetConfigResponse, error) AddProfile(context.Context, *AddProfileRequest) (*AddProfileResponse, error) @@ -772,6 +789,9 @@ func (UnimplementedDaemonServiceServer) SubscribeEvents(*SubscribeRequest, Daemo func (UnimplementedDaemonServiceServer) GetEvents(context.Context, *GetEventsRequest) (*GetEventsResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method GetEvents not implemented") } +func (UnimplementedDaemonServiceServer) RegisterUILog(context.Context, *RegisterUILogRequest) (*RegisterUILogResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method RegisterUILog not implemented") +} func (UnimplementedDaemonServiceServer) SwitchProfile(context.Context, *SwitchProfileRequest) (*SwitchProfileResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method SwitchProfile not implemented") } @@ -1283,6 +1303,24 @@ func _DaemonService_GetEvents_Handler(srv interface{}, ctx context.Context, dec return interceptor(ctx, in, info, handler) } +func _DaemonService_RegisterUILog_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(RegisterUILogRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(DaemonServiceServer).RegisterUILog(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/daemon.DaemonService/RegisterUILog", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(DaemonServiceServer).RegisterUILog(ctx, req.(*RegisterUILogRequest)) + } + return interceptor(ctx, in, info, handler) +} + func _DaemonService_SwitchProfile_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(SwitchProfileRequest) if err := dec(in); err != nil { @@ -1719,6 +1757,10 @@ var DaemonService_ServiceDesc = grpc.ServiceDesc{ MethodName: "GetEvents", Handler: _DaemonService_GetEvents_Handler, }, + { + MethodName: "RegisterUILog", + Handler: _DaemonService_RegisterUILog_Handler, + }, { MethodName: "SwitchProfile", Handler: _DaemonService_SwitchProfile_Handler, diff --git a/client/proto/metadata.go b/client/proto/metadata.go new file mode 100644 index 000000000..10a3187bd --- /dev/null +++ b/client/proto/metadata.go @@ -0,0 +1,30 @@ +package proto + +// SystemEvent metadata markers. The daemon stamps these on internal control +// events it publishes over SubscribeEvents (profile-list refresh, log-level +// change); the desktop UI recognises them and acts on them instead of +// surfacing them as user-facing notifications. +// +// These live in the proto package — the shared contract both the daemon +// (client/server) and the UI (client/ui/services) already import — so producer +// and consumer reference the same constant rather than duplicating literals. +// This file is hand-written and not touched by protoc. +const ( + // MetadataKindKey is the SystemEvent.metadata key carrying the event-kind + // marker (one of the MetadataKind* values below). + MetadataKindKey = "kind" + + // MetadataKindProfileListChanged marks a CLI-driven profile add/remove that + // should nudge the UI's profile views to refresh. + MetadataKindProfileListChanged = "profile-list-changed" + // MetadataKindLogLevelChanged marks a daemon log-level change (or the + // per-subscription snapshot) that drives the GUI's file logging on/off. + MetadataKindLogLevelChanged = "log-level-changed" + + // MetadataProfileKey carries the profile name for + // MetadataKindProfileListChanged. + MetadataProfileKey = "profile" + // MetadataLevelKey carries the lowercase logrus level name for + // MetadataKindLogLevelChanged. + MetadataLevelKey = "level" +) diff --git a/client/server/debug.go b/client/server/debug.go index e754743bd..0b6ac4b53 100644 --- a/client/server/debug.go +++ b/client/server/debug.go @@ -67,6 +67,7 @@ func (s *Server) DebugBundle(_ context.Context, req *proto.DebugBundleRequest) ( StatusRecorder: s.statusRecorder, SyncResponse: syncResponse, LogPath: s.logFile, + UILogPath: s.uiLogPath, CPUProfile: cpuProfileData, CapturePath: capturePath, RefreshStatus: refreshStatus, @@ -127,9 +128,26 @@ func (s *Server) SetLogLevel(_ context.Context, req *proto.SetLogLevelRequest) ( log.Infof("Log level set to %s", level.String()) + // Signal the desktop UI so it can attach/detach its gui-client.log. Rides + // the SubscribeEvents stream as a marked event (see publishLogLevelChanged). + s.publishLogLevelChanged(level.String()) + return &proto.SetLogLevelResponse{}, nil } +// RegisterUILog records the desktop UI's absolute log path so DebugBundle can +// collect the GUI log. The daemon runs as root and can't resolve the user's +// config dir, so the UI reports it. Last-writer-wins (one UI per socket). +func (s *Server) RegisterUILog(_ context.Context, req *proto.RegisterUILogRequest) (*proto.RegisterUILogResponse, error) { + s.mutex.Lock() + defer s.mutex.Unlock() + + s.uiLogPath = req.GetPath() + log.Infof("registered UI log path: %s", s.uiLogPath) + + return &proto.RegisterUILogResponse{}, nil +} + // SetSyncResponsePersistence sets the sync response persistence for the server. func (s *Server) SetSyncResponsePersistence(_ context.Context, req *proto.SetSyncResponsePersistenceRequest) (*proto.SetSyncResponsePersistenceResponse, error) { s.mutex.Lock() diff --git a/client/server/event.go b/client/server/event.go index d93151c96..753a051e7 100644 --- a/client/server/event.go +++ b/client/server/event.go @@ -1,7 +1,9 @@ package server import ( + "github.com/google/uuid" log "github.com/sirupsen/logrus" + "google.golang.org/protobuf/types/known/timestamppb" "github.com/netbirdio/netbird/client/proto" ) @@ -16,6 +18,15 @@ func (s *Server) SubscribeEvents(req *proto.SubscribeRequest, stream proto.Daemo log.Debug("client subscribed to events") s.startUpdateManagerForGUI() + // Replay the current log level to this subscriber so a freshly-connected UI + // learns it even when the daemon was already started with --log-level debug + // (the change-driven publishLogLevelChanged only fires on SetLogLevel). Sent + // directly on this stream rather than via PublishEvent so it reaches only + // the new subscriber, not every connected client. + if err := s.sendCurrentLogLevel(stream); err != nil { + return err + } + for { select { case event := <-subscription.Events(): @@ -28,3 +39,24 @@ func (s *Server) SubscribeEvents(req *proto.SubscribeRequest, stream proto.Daemo } } } + +// sendCurrentLogLevel sends a marked log-level-changed SystemEvent carrying the +// daemon's current level directly to one subscriber. Mirrors the shape +// publishLogLevelChanged emits so the UI's dispatchSystemEvent handles both the +// same way. +func (s *Server) sendCurrentLogLevel(stream proto.DaemonService_SubscribeEventsServer) error { + level := log.GetLevel().String() + event := &proto.SystemEvent{ + Id: uuid.New().String(), + Severity: proto.SystemEvent_INFO, + Category: proto.SystemEvent_SYSTEM, + Message: "Log level changed", + Metadata: map[string]string{proto.MetadataKindKey: proto.MetadataKindLogLevelChanged, proto.MetadataLevelKey: level}, + Timestamp: timestamppb.Now(), + } + if err := stream.Send(event); err != nil { + log.Warnf("error sending initial log level event: %v", err) + return err + } + return nil +} diff --git a/client/server/server.go b/client/server/server.go index 20f80743e..9fa3bf507 100644 --- a/client/server/server.go +++ b/client/server/server.go @@ -67,6 +67,12 @@ type Server struct { logFile string + // uiLogPath is the desktop UI's absolute log path, reported via + // RegisterUILog. Guarded by mutex. Consumed by DebugBundle so the bundle + // can collect the GUI log even though the daemon runs as root and can't + // resolve the user's config dir. Last-writer-wins (one UI per socket). + uiLogPath string + oauthAuthFlow oauthAuthFlow // extendAuthSessionFlow holds the pending PKCE flow created by // RequestExtendAuthSession until WaitExtendAuthSession resolves it. @@ -1916,8 +1922,8 @@ func (s *Server) RemoveProfile(ctx context.Context, msg *proto.RemoveProfileRequ // a marked INFO/SYSTEM event over SubscribeEvents: the UI's dispatchSystemEvent // recognises the metadata "kind" marker and translates it into its internal // profile-changed signal that both the tray menu and the React profile views -// already subscribe to (see client/ui/services/daemon_feed.go, -// MetadataKindProfileListChanged). userMessage is intentionally empty so this +// already subscribe to (see proto.MetadataKindProfileListChanged, recognised in +// client/ui/services/daemon_feed.go). userMessage is intentionally empty so this // stays a silent refresh signal rather than a user-facing notification. func (s *Server) publishProfileListChanged(profileName string) { s.statusRecorder.PublishEvent( @@ -1925,7 +1931,26 @@ func (s *Server) publishProfileListChanged(profileName string) { proto.SystemEvent_SYSTEM, "Profile list changed", "", - map[string]string{"kind": "profile-list-changed", "profile": profileName}, + map[string]string{proto.MetadataKindKey: proto.MetadataKindProfileListChanged, proto.MetadataProfileKey: profileName}, + ) +} + +// publishLogLevelChanged signals the desktop UI that the daemon log level +// changed, so it can attach/detach its rotated gui-client.log. Like +// publishProfileListChanged, this rides the SubscribeEvents stream as a marked +// INFO/SYSTEM event (kind "log-level-changed", level the lowercase logrus +// name); the UI's dispatchSystemEvent recognises the marker and routes it to +// the logging toggle instead of an OS toast (userMessage is empty so it stays +// a silent control signal). The "level" value matches log.Level.String() +// (e.g. "debug", "info") so the UI can parse it directly. See +// proto.MetadataKindLogLevelChanged, recognised in client/ui/services/daemon_feed.go. +func (s *Server) publishLogLevelChanged(level string) { + s.statusRecorder.PublishEvent( + proto.SystemEvent_INFO, + proto.SystemEvent_SYSTEM, + "Log level changed", + "", + map[string]string{proto.MetadataKindKey: proto.MetadataKindLogLevelChanged, proto.MetadataLevelKey: level}, ) } diff --git a/client/ui/CLAUDE.md b/client/ui/CLAUDE.md index a1b8bcb0d..db2e2bdb2 100644 --- a/client/ui/CLAUDE.md +++ b/client/ui/CLAUDE.md @@ -7,7 +7,7 @@ This is the Wails v3 desktop UI for NetBird. Go services live in `services/`; th ## Layout ### Go (top-level package `main`) -- `main.go` — app entry. Builds the shared gRPC `Conn`, constructs services, registers them with Wails, creates the main webview window, then starts (in order) the Linux SNI watcher → tray → `peers.Watch` → `app.Run`. CLI flags: `--daemon-addr`, `--log-file` (repeatable; first user-provided value drops the seeded `console` default), `--log-level` (`trace|debug|info|warn|error`, default `info`). +- `main.go` — app entry. Builds the shared gRPC `Conn`, constructs services, registers them with Wails, creates the main webview window, then starts (in order) the Linux SNI watcher → tray → `peers.Watch` → `app.Run`. CLI flags: `--daemon-addr`, `--log-file` (repeatable; default is **empty** so "no flag" is distinguishable from explicit `--log-file console` — when empty `parseFlagsAndInitLog` falls back to `console` for `InitLog` and returns `userSetLogFile=false`), `--log-level` (`trace|debug|info|warn|error`, default `info`). See "GUI debug logging" below for what `userSetLogFile` gates. - `tray.go` — `Tray` struct + menu. Subscribes to `EventStatus`, `EventSystem`, `EventUpdateAvailable`, `EventUpdateProgress`. Owns per-status icon/dot, Profiles submenu, Connect/Disconnect swap, About → Update, session-expired toast. - **Tray menu updates go through `relayoutMenu` (whole-tree rebuild), never in-place submenu mutation.** Any dynamic menu change — Profiles submenu (`tray_profiles.go loadProfiles` → caches rows under `profilesMu`, then `fillProfileSubmenu`), Exit Node submenu (`tray_exitnodes.go refreshExitNodes` → `fillExitNodeSubmenu`), daemon-version row (`tray_status.go`), and the About → Update row (`tray_update.go applyState` → `onMenuChange` callback) — rebuilds the entire menu via `Tray.relayoutMenu` (`buildMenu()` + repaint cached state + single `t.tray.SetMenu`). Serialised by `menuMu`. **Why:** on KDE/Plasma the StatusNotifierItem host caches a submenu's layout the first time it's opened (`GetLayout` for that submenu id) and never re-fetches it on a `LayoutUpdated(parent=0)` signal — so the old `submenu.Clear()`+`Add()` left both the visible rows AND the click→id mapping frozen on the first snapshot. Because `Clear()`+`Add()` allocates fresh monotonic item ids each time (Wails `menuitem.go`), clicks then sent ids the rebuilt `itemMap` no longer knew, and silently no-op'd ("Manage Profiles" stopped responding after the first switch). `buildMenu()` allocates a brand-new submenu container id each relayout, which Plasma treats as unseen and re-queries on next open — fixing both the stale paint and the dead clicks. Confirmed via `dbus-monitor`: a re-opened submenu issued no `GetLayout` until its container id changed. The whole-tree `SetMenu` also subsumes the older darwin detached-NSMenu workaround. `fill*Submenu` helpers are pure UI (read caches, no daemon fetch, no `SetMenu`) so `relayoutMenu` never recurses back into the fetchers. - `tray_linux.go` — `init()` sets `WEBKIT_DISABLE_DMABUF_RENDERER=1` (blank-white window on VMs / minimal WMs) and `WEBKIT_DISABLE_COMPOSITING_MODE=1` (Intel/Mesa SIGSEGV in `g_application_run` via unimplemented DRM-format-modifier paths — DMABUF-disable alone doesn't cover the GL compositor). Both are skipped if the user already set the var. Also `WEBKIT_DISABLE_SANDBOX_THIS_IS_DANGEROUS=1` when unprivileged userns are blocked. @@ -35,7 +35,7 @@ All services live in `services/` and assume a build tag `!android && !ios && !fr | `Peers` | `peers.go` | Daemon status snapshot + two long-running streams (`SubscribeStatus` → `EventStatus`, `SubscribeEvents` → `EventSystem`). Emits synthetic `StatusDaemonUnavailable` when the socket is unreachable. Owns the profile-switch suppression filter (`BeginProfileSwitch` / `CancelProfileSwitch` / `shouldSuppress`). Fan-outs update metadata into dedicated `EventUpdateAvailable` / `EventUpdateProgress` events. | | `Networks` | `network.go` | `List` / `Select` / `Deselect` of routed networks. | | `Forwarding` | `forwarding.go` | `List` exposed/forwarded services from the daemon's reverse-proxy table. | -| `Debug` | `debug.go` | `Bundle` (debug bundle creation + optional upload) / `Get|SetLogLevel` / `RevealFile` (cross-platform "show in file manager"). | +| `Debug` | `debug.go` | `Bundle` (debug bundle creation + optional upload) / `Get|SetLogLevel` / `RegisterUILog` (report the GUI log path to the daemon for bundle collection) / `RevealFile` (cross-platform "show in file manager"). | | `Update` | `update.go` | `GetState` / `Trigger` (enforced installer) / `GetInstallerResult` / `Quit`. The install-progress UI lives in its own auxiliary window (`/#/dialog/install-progress`), opened by `WindowManager.OpenInstallProgress` — the daemon goes unreachable mid-install so it can't be inside the main window. | | `WindowManager` | `windowmanager.go` | `OpenSettings(tab)` / `OpenBrowserLogin(uri)` / `CloseBrowserLogin` / `OpenSessionExpiration(seconds)` / `CloseSessionExpiration` / `OpenInstallProgress(version)` / `CloseInstallProgress` / `OpenWelcome` / `CloseWelcome` / `OpenError(title, message)` / `CloseError` / `OpenMain`. `OpenSettings("")` opens the General tab; pass a tab id (e.g. `"profiles"`) to deep-link, encoded as `?tab=…` in the start URL. `OpenInstallProgress` is `AlwaysOnTop` and hides every other visible window for the duration of the install (restored on close). `OpenMain` is the handoff path from the welcome window to the main UI (avoids depending on the tray). Auxiliary windows are created on first open and **destroyed** on close (Wails-recommended singleton pattern; prevents the macOS dock-reopen from resurrecting hidden windows). | | `I18n` | `i18n.go` | Thin facade over `i18n.Bundle`. `Languages()` returns the shipped locales (`_index.json`); `Bundle(code)` returns the full key→text map for one language so the React layer can drive its own translation library. | @@ -50,6 +50,17 @@ All services live in `services/` and assume a build tag `!android && !ios && !fr - Pinned versions (see `daemon.pb.go` header): `protoc v7.34.1`, `protoc-gen-go v1.36.6`. CI's `proto-version-check` workflow fails on mismatch. - After proto regen, also regen Wails bindings so the TS layer picks up new fields. +## GUI debug logging + +When the daemon is put into **debug**/**trace** level, the GUI automatically writes a rotated `gui-client.log` in `os.UserConfigDir()/netbird/` and the daemon's **debug bundle** collects it. Pieces: + +- **`uilogpath.go`** (package `main`) — `uiLogPath()` resolves the path; `newDebugLog(userSetLogFile)` builds the `guilog.DebugLog` (disabled when the user passed `--log-file`, or when the config dir can't be resolved). +- **`guilog/debuglog.go` — `guilog.DebugLog`** (own package, **not** a Wails service — no React binding) — owns the file-logging side effects. `Apply(level)`: on debug/trace attaches `gui-client.log` alongside the console (via `util.SetLogOutputs`, MultiWriter, rotated by timberjack like the daemon log) and raises the logrus level; on a higher level detaches the file and restores `info`. Idempotent (`fileOn` guard) so the startup replay + a racing change-event are harmless. The `gui-client.log` is left on disk on quit (rotated by timberjack) for the debug bundle — there's no shutdown cleanup. `Path()` returns "" when disabled so the daemon won't try to collect a file the GUI never writes. +- **Activation rule:** any `--log-file` (even `console`) is a manual override → the controller is disabled and never touches logging. Only the *absence* of `--log-file` enables the daemon-driven `gui-client.log`. This is why `parseFlagsAndInitLog` seeds the flag default empty (Layout note above). +- **Level signalling — no new stream.** The daemon publishes a **marked `SystemEvent`** (`metadata[proto.MetadataKindKey]==proto.MetadataKindLogLevelChanged`, `metadata[proto.MetadataLevelKey]==`) on the existing `SubscribeEvents` stream. `DaemonFeed.dispatchSystemEvent` recognises the marker and routes it to the controller's `Apply` instead of an OS toast (same pattern as `proto.MetadataKindProfileListChanged`). The controller is injected into `NewDaemonFeed` (a `services.LogController` interface — no exported setter, so the Wails-bound `DaemonFeed` gains no binding), and `DaemonFeed` **re-registers the UI log path** (`RegisterUILog` RPC) on every event-stream (re)connect, so a daemon restart re-learns it. Startup case (daemon already in debug) is covered daemon-side: `Server.SubscribeEvents` (`client/server/event.go`) sends the current level once to each new subscriber; `SetLogLevel` publishes on change (`publishLogLevelChanged` in `client/server/server.go`). The metadata key/value markers live in `client/proto/metadata.go` so producer (daemon) and consumer (UI) share one definition. +- **Daemon side of the bundle:** `Server.RegisterUILog` stores the path in `Server.uiLogPath`; `DebugBundle` passes it to `debug.GeneratorDependencies.UILogPath`; `BundleGenerator.addUILog` adds `gui-client.log` + rotated siblings (`addRotatedLogFiles(dir, "gui-client")` — the glob is prefix-parametrised so it doesn't collide with the daemon's own `client*.log.*`). Missing file is non-fatal (the GUI only writes it while in debug). +- **JS-side logs/errors** already reach the same logrus pipeline via `frontend/src/lib/logs.ts` → `services.UILog.Log`, so once the file is attached, frontend console/`unhandledrejection`/`error` output is captured too. Go-side uncaught-goroutine panics go to stderr only (out of scope). + ## Events bus `main.go` registers five typed events for the frontend: `netbird:status` (`Status`), `netbird:event` (`SystemEvent`), `netbird:profile:changed` (`ProfileRef`), `netbird:update:available` (`UpdateAvailable`), `netbird:update:progress` (`UpdateProgress`). `netbird:profile:changed` fires from `ProfileSwitcher.SwitchActive` after a successful daemon-side switch — both the React `ProfileContext` and the tray subscribe so a flip driven from one surface paints in the others (the daemon itself does not emit a profile event). Plus three plain-string events: diff --git a/client/ui/frontend/src/contexts/DebugBundleContext.tsx b/client/ui/frontend/src/contexts/DebugBundleContext.tsx index ea7ddc3b4..c623effc1 100644 --- a/client/ui/frontend/src/contexts/DebugBundleContext.tsx +++ b/client/ui/frontend/src/contexts/DebugBundleContext.tsx @@ -8,6 +8,11 @@ import { useProfile } from "@/contexts/ProfileContext.tsx"; const NETBIRD_UPLOAD_URL = "https://upload.debug.netbird.io/upload-url"; const TRACE_LOG_FILE_COUNT = 5; const PLAIN_LOG_FILE_COUNT = 1; +// Lowercase logrus level name sent to Debug.SetLogLevel (the Go binding +// upper-cases before the proto enum lookup). Raising to trace is what drives +// the daemon's verbose logging and the GUI's gui-client.log during a bundle. +const TRACE_LOG_LEVEL = "trace"; +const DEFAULT_LOG_LEVEL = "info"; export type DebugStage = | { kind: "idle" } @@ -68,7 +73,7 @@ const runTracePhase = async ( // empty } throwIfAborted(signal); - await DebugSvc.SetLogLevel({ level: "trace" }); + await DebugSvc.SetLogLevel({ level: TRACE_LOG_LEVEL }); level.raised = true; throwIfAborted(signal); @@ -123,7 +128,7 @@ const useDebugBundle = () => { const signal = ctrl.signal; const uploadUrl = upload ? NETBIRD_UPLOAD_URL : ""; - const level: LevelState = { original: "info", raised: false }; + const level: LevelState = { original: DEFAULT_LOG_LEVEL, raised: false }; try { if (trace) { diff --git a/client/ui/guilog/debuglog.go b/client/ui/guilog/debuglog.go new file mode 100644 index 000000000..fe24f3be6 --- /dev/null +++ b/client/ui/guilog/debuglog.go @@ -0,0 +1,92 @@ +//go:build !android && !ios && !freebsd && !js + +// Package guilog manages the desktop UI's own file log (gui-client.log), which +// follows the daemon's log level: when the daemon is in debug/trace the GUI +// attaches a rotated file alongside the console so its (and the React frontend's +// forwarded) output is captured for the debug bundle. It is intentionally not a +// Wails service — it has no frontend-facing methods and generates no TS +// bindings — so it lives outside client/ui/services. +package guilog + +import ( + "sync" + + log "github.com/sirupsen/logrus" + + "github.com/netbirdio/netbird/util" +) + +// DebugLog is the daemon-debug-driven GUI file log. The daemon publishes a +// marked "log-level-changed" SystemEvent over SubscribeEvents (both on change +// and once per new subscription, so a daemon already in debug is picked up at +// startup); services.DaemonFeed routes it here via Apply. +// +// When the daemon is in debug/trace and the GUI owns its log (no manual +// --log-file), it attaches a rotated gui-client.log alongside the console and +// raises the logrus level; back to a higher level it detaches the file and +// restores info. The file is left on disk (rotated by timberjack) for the debug +// bundle to collect. When the user set --log-file explicitly, it is disabled and +// never touches logging. +type DebugLog struct { + uiPath string + enabled bool + + mu sync.Mutex + fileOn bool +} + +// NewDebugLog builds the GUI debug log. uiPath is the absolute gui-client.log +// path; enabled is false when the user passed --log-file (manual override), in +// which case it leaves logging untouched. +func NewDebugLog(uiPath string, enabled bool) *DebugLog { + return &DebugLog{uiPath: uiPath, enabled: enabled} +} + +// Path returns the GUI log path to register with the daemon, or "" when the GUI +// doesn't own its log (manual --log-file) — in that case the daemon shouldn't +// try to collect a gui-client.log the GUI never writes. +func (d *DebugLog) Path() string { + if !d.enabled { + return "" + } + return d.uiPath +} + +// Apply reacts to a daemon log level (the lowercase logrus name, e.g. "debug"). +// Idempotent: repeated identical levels are no-ops, so the startup replay plus a +// racing change-event do no harm. +func (d *DebugLog) Apply(level string) { + if !d.enabled { + return + } + + // "debug or more verbose" (debug/trace) turns the file log on; anything less + // verbose turns it off. Compare numerically against logrus' own levels so + // there are no hard-coded level-name literals. + lvl, err := log.ParseLevel(level) + if err != nil { + lvl = log.InfoLevel + } + debug := lvl >= log.DebugLevel + + d.mu.Lock() + defer d.mu.Unlock() + + switch { + case debug && !d.fileOn: + if err := util.SetLogOutputs(log.StandardLogger(), util.LogConsole, d.uiPath); err != nil { + log.Errorf("attach GUI file log %s: %v", d.uiPath, err) + return + } + log.SetLevel(lvl) + d.fileOn = true + log.Infof("GUI file logging enabled (daemon level %s), writing to %s", level, d.uiPath) + case !debug && d.fileOn: + if err := util.SetLogOutputs(log.StandardLogger(), util.LogConsole); err != nil { + log.Errorf("detach GUI file log: %v", err) + } + log.SetLevel(log.InfoLevel) + d.fileOn = false + log.Infof("GUI file logging disabled (daemon level: %s)", level) + } +} diff --git a/client/ui/main.go b/client/ui/main.go index afe5f63dd..6c12b57c2 100644 --- a/client/ui/main.go +++ b/client/ui/main.go @@ -84,9 +84,16 @@ func init() { } func main() { - daemonAddr := parseFlagsAndInitLog() + daemonAddr, userSetLogFile := parseFlagsAndInitLog() conn := NewConn(daemonAddr) + // GUI file logging: when the user didn't pass --log-file, the GUI manages a + // gui-client.log that follows the daemon's debug level (attached when the + // daemon is in debug/trace, detached otherwise, rotated by timberjack) and is + // included in the debug bundle. It rides DaemonFeed's SubscribeEvents stream + // (passed into NewDaemonFeed below; see guilog.DebugLog). + debugLog := newDebugLog(userSetLogFile) + // tray is captured in the SingleInstance callback below; the var is // declared before app.New so the closure has a stable reference. var tray *Tray @@ -103,7 +110,7 @@ func main() { // Wails-bound facade over the holder plus the install RPCs. updaterHolder := updater.NewHolder(app.Event) update := services.NewUpdate(conn, updaterHolder) - daemonFeed := services.NewDaemonFeed(conn, app.Event, updaterHolder) + daemonFeed := services.NewDaemonFeed(conn, app.Event, updaterHolder, debugLog) notifier := notifications.New() // macOS won't surface any toast until the app has requested permission; // the request runs after ApplicationStarted so the notifier's Startup has @@ -230,18 +237,30 @@ func requestNotificationAuthorization(notifier *notifications.NotificationServic } // parseFlagsAndInitLog parses the CLI flags, initialises the logger, and -// returns the resolved daemon gRPC address. -func parseFlagsAndInitLog() string { +// returns the resolved daemon gRPC address plus userSetLogFile — true when the +// user passed --log-file explicitly. userSetLogFile is the manual-override +// signal: when true the GUI leaves logging alone (the daemon's debug level +// won't attach gui-client.log); when false the GUI manages a per-session +// gui-client.log driven by the daemon level. The default seed is empty (not +// "console") so "no flag" and an explicit "--log-file console" are +// distinguishable; an empty result falls back to console for InitLog. +func parseFlagsAndInitLog() (string, bool) { daemonAddr := flag.String("daemon-addr", DaemonAddr(), "Daemon gRPC address: unix:///path or tcp://host:port") - logFiles := &stringList{values: []string{"console"}} - flag.Var(logFiles, "log-file", "Log destination. Repeat to log to multiple targets at once, e.g. `--log-file console --log-file Y:/netbird-ui.log`. Each value is one of: console, syslog, or a file path. File destinations are rotated by lumberjack (same as the daemon). Defaults to console.") + logFiles := &stringList{} + flag.Var(logFiles, "log-file", "Log destination. Repeat to log to multiple targets at once, e.g. `--log-file console --log-file Y:/netbird-ui.log`. Each value is one of: console, syslog, or a file path. File destinations are rotated by lumberjack (same as the daemon). Defaults to console. Passing any value disables the daemon-debug-driven gui-client.log.") logLevel := flag.String("log-level", "info", "Log level: trace|debug|info|warn|error.") flag.Parse() - if err := util.InitLog(*logLevel, logFiles.values...); err != nil { + userSetLogFile := len(logFiles.values) > 0 + targets := logFiles.values + if !userSetLogFile { + targets = []string{"console"} + } + + if err := util.InitLog(*logLevel, targets...); err != nil { log.Fatalf("init log: %v", err) } - return *daemonAddr + return *daemonAddr, userSetLogFile } // newApplication constructs the Wails application. onSecondInstance is invoked diff --git a/client/ui/services/daemon_feed.go b/client/ui/services/daemon_feed.go index bc1c24481..92e749283 100644 --- a/client/ui/services/daemon_feed.go +++ b/client/ui/services/daemon_feed.go @@ -46,20 +46,11 @@ const ( // tray (Go side) so the frontend stays passive on this flow. EventSessionWarning = "netbird:session:warning" - // MetadataKindProfileListChanged is the SystemEvent.metadata["kind"] - // marker the daemon stamps on the INFO/SYSTEM event it publishes after a - // CLI-driven AddProfile / RemoveProfile (the daemon emits no dedicated - // profile RPC event). dispatchSystemEvent recognises it and re-emits the - // existing EventProfileChanged so the tray and React profile views refresh - // — closing the gap the SubscribeStatus path can't, since a profile - // add/remove doesn't change the daemon's status string (the tray's - // iconChanged guard would swallow it). The daemon side hard-codes the same - // string literal in client/server/server.go (client/server cannot import - // this UI package). - MetadataKindProfileListChanged = "profile-list-changed" - // metadataKindKey is the SystemEvent.metadata key the "kind" marker lives - // under. Kept in sync with the daemon-side literal in client/server. - metadataKindKey = "kind" + // The SystemEvent.metadata markers the daemon stamps on its internal + // control events live in the shared proto package + // (proto.MetadataKind*/MetadataKindKey/MetadataLevelKey) so producer + // (client/server) and consumer (here) reference the same constants. See + // dispatchSystemEvent for how they're recognised. // StatusDaemonUnavailable is the synthetic Status the UI emits when the // daemon's gRPC socket is unreachable (daemon not running, socket @@ -198,6 +189,13 @@ type DaemonFeed struct { conn DaemonConn emitter Emitter updater *updater.Holder + // logCtl reacts to the daemon's log level (delivered as a marked + // SystemEvent over the same SubscribeEvents stream) by attaching/detaching + // the GUI file log. nil when the GUI doesn't manage its log (server build / + // not wired), in which case the marker is ignored. Held as a narrow + // interface so this package doesn't depend on client/ui/guilog (the concrete + // type lives there; main passes it into NewDaemonFeed). + logCtl LogController mu sync.Mutex cancel context.CancelFunc @@ -217,8 +215,24 @@ type DaemonFeed struct { switchLoginWatchUntil time.Time } -func NewDaemonFeed(conn DaemonConn, emitter Emitter, updaterHolder *updater.Holder) *DaemonFeed { - return &DaemonFeed{conn: conn, emitter: emitter, updater: updaterHolder} +// LogController is the subset of client/ui/guilog.DebugLog that DaemonFeed +// drives: Apply turns the GUI file log on/off for a daemon level, Path is the +// gui-client.log path to register with the daemon (empty when the GUI doesn't +// own its log). Kept as an interface so services doesn't import guilog. The +// daemon delivers log-level changes as marked SystemEvents on the same +// SubscribeEvents stream this feed consumes, so it rides along here rather than +// opening a second daemon subscription. +type LogController interface { + Apply(level string) + Path() string +} + +// NewDaemonFeed builds the feed. logCtl may be nil (server build / GUI log not +// managed), in which case log-level markers on the event stream are ignored. +// Injected at construction rather than via a setter so DaemonFeed (a Wails +// service) exposes no extra method to the binding generator. +func NewDaemonFeed(conn DaemonConn, emitter Emitter, updaterHolder *updater.Holder, logCtl LogController) *DaemonFeed { + return &DaemonFeed{conn: conn, emitter: emitter, updater: updaterHolder, logCtl: logCtl} } // BeginProfileSwitch is called by ProfileSwitcher at the start of a switch @@ -525,6 +539,17 @@ func (s *DaemonFeed) subscribeAndStreamEvents(ctx context.Context) error { if err != nil { return fmt.Errorf("subscribe: %w", err) } + + // Re-register the GUI log path on every (re)connect so a daemon restart + // re-learns it and a later debug bundle still finds the file. Best-effort — + // a failure here must not abort the event stream. Done even when file + // logging is off (enabled but not in debug), so the path is known ahead of + // any debug toggle. + if s.logCtl != nil && s.logCtl.Path() != "" { + if _, err := cli.RegisterUILog(ctx, &proto.RegisterUILogRequest{Path: s.logCtl.Path()}); err != nil { + log.Warnf("register UI log path: %v", err) + } + } for { ev, err := stream.Recv() if err != nil { @@ -549,10 +574,19 @@ func (s *DaemonFeed) dispatchSystemEvent(ev *proto.SystemEvent) { // ProfileContext.refresh already subscribe to) and stop — it's an internal // refresh signal, not a user-facing notification, so it must not reach the // Recent Events list or fire an OS toast. - if se.Metadata[metadataKindKey] == MetadataKindProfileListChanged { + if se.Metadata[proto.MetadataKindKey] == proto.MetadataKindProfileListChanged { s.emitter.Emit(EventProfileChanged, ProfileRef{}) return } + // A marked log-level-changed event drives the GUI file log on/off. It's an + // internal control signal, not a user-facing notification — handle and stop + // so it never reaches the Recent Events list or fires an OS toast. + if se.Metadata[proto.MetadataKindKey] == proto.MetadataKindLogLevelChanged { + if s.logCtl != nil { + s.logCtl.Apply(se.Metadata[proto.MetadataLevelKey]) + } + return + } s.emitter.Emit(EventDaemonNotification, se) if warn, ok := authsession.WarningFromMetadata(se.Metadata); ok { s.emitter.Emit(EventSessionWarning, warn) diff --git a/client/ui/services/debug.go b/client/ui/services/debug.go index 1a129dbc6..64afe38d0 100644 --- a/client/ui/services/debug.go +++ b/client/ui/services/debug.go @@ -8,6 +8,7 @@ import ( "os/exec" "path/filepath" "runtime" + "strings" "github.com/netbirdio/netbird/client/proto" "github.com/netbirdio/netbird/version" @@ -99,12 +100,29 @@ func (s *Debug) RevealFile(_ context.Context, path string) error { return cmd.Start() } +// RegisterUILog tells the daemon the absolute path of the GUI's log file so +// the daemon's debug bundle can collect it (the daemon runs as root and can't +// resolve the user's config dir). Called by LogLevelWatcher on each daemon +// (re)connect. +func (s *Debug) RegisterUILog(ctx context.Context, path string) error { + cli, err := s.conn.Client() + if err != nil { + return err + } + _, err = cli.RegisterUILog(ctx, &proto.RegisterUILogRequest{Path: path}) + return err +} + func (s *Debug) SetLogLevel(ctx context.Context, lvl LogLevel) error { cli, err := s.conn.Client() if err != nil { return err } - level, ok := proto.LogLevel_value[lvl.Level] + // proto.LogLevel_value keys are the enum names (TRACE/DEBUG/INFO/...), but + // callers (the React side, GetLogLevel) use the lowercase logrus names + // ("trace"/"debug"/...). Upper-case before the lookup so a lowercase level + // doesn't silently fall back to INFO. + level, ok := proto.LogLevel_value[strings.ToUpper(lvl.Level)] if !ok { level = int32(proto.LogLevel_INFO) } diff --git a/client/ui/uilogpath.go b/client/ui/uilogpath.go new file mode 100644 index 000000000..bfe80ee7d --- /dev/null +++ b/client/ui/uilogpath.go @@ -0,0 +1,41 @@ +//go:build !android && !ios && !freebsd && !js + +package main + +import ( + "os" + "path/filepath" + + log "github.com/sirupsen/logrus" + + "github.com/netbirdio/netbird/client/ui/guilog" +) + +// uiLogFileName is the base name of the GUI's log. Rotated siblings +// (gui-client.log.*, *.gz) share the prefix; the daemon's debug bundle globs +// "gui-client*.log.*" to collect them (see addUILog in client/internal/debug). +const uiLogFileName = "gui-client.log" + +// uiLogPath resolves os.UserConfigDir()/netbird/gui-client.log — the per-OS-user +// path the GUI writes its log to while the daemon is in debug, and the path it +// registers with the daemon for debug-bundle collection. Native separators are +// preserved (the daemon os.Open()s this path). +func uiLogPath() (string, error) { + dir, err := os.UserConfigDir() + if err != nil { + return "", err + } + return filepath.Join(dir, "netbird", uiLogFileName), nil +} + +// newDebugLog builds the GUI debug log. userSetLogFile disables it (manual +// --log-file override). If the config dir can't be resolved it's created +// disabled, so the GUI keeps working without file logging. +func newDebugLog(userSetLogFile bool) *guilog.DebugLog { + path, err := uiLogPath() + if err != nil { + log.Warnf("resolve GUI log path: %v; GUI file logging disabled", err) + return guilog.NewDebugLog("", false) + } + return guilog.NewDebugLog(path, !userSetLogFile) +} diff --git a/util/log.go b/util/log.go index 3896ff6bc..623b11e0f 100644 --- a/util/log.go +++ b/util/log.go @@ -40,6 +40,45 @@ func InitLogger(logger *log.Logger, logLevel string, logs ...string) error { if err != nil { return fmt.Errorf("failed parsing log-level %s: %w", logLevel, err) } + + logFmt, err := buildWriters(logger, logs...) + if err != nil { + return err + } + + switch logFmt { + case "json": + formatter.SetJSONFormatter(logger) + case "syslog": + formatter.SetSyslogFormatter(logger) + default: + formatter.SetTextFormatter(logger) + } + logger.SetLevel(level) + + setGRPCLibLogger(logger) + + return nil +} + +// SetLogOutputs re-points an already-initialized logger to the given targets +// (console/syslog/file), with the same target semantics as InitLogger, but +// without re-parsing the level or resetting the formatter. The desktop GUI uses +// it to attach the rotated gui-client.log alongside the console when the daemon +// enters debug, and drop back to console-only when it leaves. +func SetLogOutputs(logger *log.Logger, logs ...string) error { + if _, err := buildWriters(logger, logs...); err != nil { + return err + } + setGRPCLibLogger(logger) + return nil +} + +// buildWriters resolves the given log targets to writers and points the logger +// at them (single writer or MultiWriter). It returns the log format implied by +// the targets (syslog forces "syslog"; otherwise the NB_LOG_FORMAT env value). +// Shared by InitLogger and SetLogOutputs. +func buildWriters(logger *log.Logger, logs ...string) (string, error) { var writers []io.Writer logFmt := os.Getenv("NB_LOG_FORMAT") @@ -61,7 +100,7 @@ func InitLogger(logger *log.Logger, logLevel string, logs ...string) error { default: writer, err := setupLogFile(logPath, isRotationDisabled(logger)) if err != nil { - return fmt.Errorf("failed setting up log file: %s, %w", logPath, err) + return "", fmt.Errorf("failed setting up log file: %s, %w", logPath, err) } writers = append(writers, writer) } @@ -73,19 +112,7 @@ func InitLogger(logger *log.Logger, logLevel string, logs ...string) error { logger.SetOutput(writers[0]) } - switch logFmt { - case "json": - formatter.SetJSONFormatter(logger) - case "syslog": - formatter.SetSyslogFormatter(logger) - default: - formatter.SetTextFormatter(logger) - } - logger.SetLevel(level) - - setGRPCLibLogger(logger) - - return nil + return logFmt, nil } // FindFirstLogPath returns the first logs entry that could be a log path, that is neither empty, nor a special value