diff --git a/client/proto/daemon.pb.go b/client/proto/daemon.pb.go index 6fbb09958..465124dbe 100644 --- a/client/proto/daemon.pb.go +++ b/client/proto/daemon.pb.go @@ -6930,6 +6930,78 @@ func (*StopBundleCaptureResponse) Descriptor() ([]byte, []int) { return file_daemon_proto_rawDescGZIP(), []int{106} } +type DownAsyncRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DownAsyncRequest) Reset() { + *x = DownAsyncRequest{} + mi := &file_daemon_proto_msgTypes[107] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DownAsyncRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DownAsyncRequest) ProtoMessage() {} + +func (x *DownAsyncRequest) ProtoReflect() protoreflect.Message { + mi := &file_daemon_proto_msgTypes[107] + 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 DownAsyncRequest.ProtoReflect.Descriptor instead. +func (*DownAsyncRequest) Descriptor() ([]byte, []int) { + return file_daemon_proto_rawDescGZIP(), []int{107} +} + +type DownAsyncResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DownAsyncResponse) Reset() { + *x = DownAsyncResponse{} + mi := &file_daemon_proto_msgTypes[108] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DownAsyncResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DownAsyncResponse) ProtoMessage() {} + +func (x *DownAsyncResponse) ProtoReflect() protoreflect.Message { + mi := &file_daemon_proto_msgTypes[108] + 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 DownAsyncResponse.ProtoReflect.Descriptor instead. +func (*DownAsyncResponse) Descriptor() ([]byte, []int) { + return file_daemon_proto_rawDescGZIP(), []int{108} +} + type PortInfo_Range struct { state protoimpl.MessageState `protogen:"open.v1"` Start uint32 `protobuf:"varint,1,opt,name=start,proto3" json:"start,omitempty"` @@ -6940,7 +7012,7 @@ type PortInfo_Range struct { func (x *PortInfo_Range) Reset() { *x = PortInfo_Range{} - mi := &file_daemon_proto_msgTypes[108] + mi := &file_daemon_proto_msgTypes[110] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6952,7 +7024,7 @@ func (x *PortInfo_Range) String() string { func (*PortInfo_Range) ProtoMessage() {} func (x *PortInfo_Range) ProtoReflect() protoreflect.Message { - mi := &file_daemon_proto_msgTypes[108] + mi := &file_daemon_proto_msgTypes[110] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7565,7 +7637,9 @@ const file_daemon_proto_rawDesc = "" + "\atimeout\x18\x01 \x01(\v2\x19.google.protobuf.DurationR\atimeout\"\x1c\n" + "\x1aStartBundleCaptureResponse\"\x1a\n" + "\x18StopBundleCaptureRequest\"\x1b\n" + - "\x19StopBundleCaptureResponse*b\n" + + "\x19StopBundleCaptureResponse\"\x12\n" + + "\x10DownAsyncRequest\"\x13\n" + + "\x11DownAsyncResponse*b\n" + "\bLogLevel\x12\v\n" + "\aUNKNOWN\x10\x00\x12\t\n" + "\x05PANIC\x10\x01\x12\t\n" + @@ -7583,7 +7657,7 @@ const file_daemon_proto_rawDesc = "" + "\n" + "EXPOSE_UDP\x10\x03\x12\x0e\n" + "\n" + - "EXPOSE_TLS\x10\x042\xa3\x1c\n" + + "EXPOSE_TLS\x10\x042\xe7\x1c\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" + @@ -7591,6 +7665,7 @@ const file_daemon_proto_rawDesc = "" + "\x06Status\x12\x15.daemon.StatusRequest\x1a\x16.daemon.StatusResponse\"\x00\x12D\n" + "\x0fSubscribeStatus\x12\x15.daemon.StatusRequest\x1a\x16.daemon.StatusResponse\"\x000\x01\x123\n" + "\x04Down\x12\x13.daemon.DownRequest\x1a\x14.daemon.DownResponse\"\x00\x12B\n" + + "\tDownAsync\x12\x18.daemon.DownAsyncRequest\x1a\x19.daemon.DownAsyncResponse\"\x00\x12B\n" + "\tGetConfig\x12\x18.daemon.GetConfigRequest\x1a\x19.daemon.GetConfigResponse\"\x00\x12K\n" + "\fListNetworks\x12\x1b.daemon.ListNetworksRequest\x1a\x1c.daemon.ListNetworksResponse\"\x00\x12Q\n" + "\x0eSelectNetworks\x12\x1d.daemon.SelectNetworksRequest\x1a\x1e.daemon.SelectNetworksResponse\"\x00\x12S\n" + @@ -7648,7 +7723,7 @@ func file_daemon_proto_rawDescGZIP() []byte { } var file_daemon_proto_enumTypes = make([]protoimpl.EnumInfo, 4) -var file_daemon_proto_msgTypes = make([]protoimpl.MessageInfo, 110) +var file_daemon_proto_msgTypes = make([]protoimpl.MessageInfo, 112) var file_daemon_proto_goTypes = []any{ (LogLevel)(0), // 0: daemon.LogLevel (ExposeProtocol)(0), // 1: daemon.ExposeProtocol @@ -7761,19 +7836,21 @@ var file_daemon_proto_goTypes = []any{ (*StartBundleCaptureResponse)(nil), // 108: daemon.StartBundleCaptureResponse (*StopBundleCaptureRequest)(nil), // 109: daemon.StopBundleCaptureRequest (*StopBundleCaptureResponse)(nil), // 110: daemon.StopBundleCaptureResponse - nil, // 111: daemon.Network.ResolvedIPsEntry - (*PortInfo_Range)(nil), // 112: daemon.PortInfo.Range - nil, // 113: daemon.SystemEvent.MetadataEntry - (*durationpb.Duration)(nil), // 114: google.protobuf.Duration - (*timestamppb.Timestamp)(nil), // 115: google.protobuf.Timestamp + (*DownAsyncRequest)(nil), // 111: daemon.DownAsyncRequest + (*DownAsyncResponse)(nil), // 112: daemon.DownAsyncResponse + nil, // 113: daemon.Network.ResolvedIPsEntry + (*PortInfo_Range)(nil), // 114: daemon.PortInfo.Range + nil, // 115: daemon.SystemEvent.MetadataEntry + (*durationpb.Duration)(nil), // 116: google.protobuf.Duration + (*timestamppb.Timestamp)(nil), // 117: google.protobuf.Timestamp } var file_daemon_proto_depIdxs = []int32{ - 114, // 0: daemon.LoginRequest.dnsRouteInterval:type_name -> google.protobuf.Duration + 116, // 0: daemon.LoginRequest.dnsRouteInterval:type_name -> google.protobuf.Duration 25, // 1: daemon.StatusResponse.fullStatus:type_name -> daemon.FullStatus - 115, // 2: daemon.StatusResponse.sessionExpiresAt:type_name -> google.protobuf.Timestamp - 115, // 3: daemon.PeerState.connStatusUpdate:type_name -> google.protobuf.Timestamp - 115, // 4: daemon.PeerState.lastWireguardHandshake:type_name -> google.protobuf.Timestamp - 114, // 5: daemon.PeerState.latency:type_name -> google.protobuf.Duration + 117, // 2: daemon.StatusResponse.sessionExpiresAt:type_name -> google.protobuf.Timestamp + 117, // 3: daemon.PeerState.connStatusUpdate:type_name -> google.protobuf.Timestamp + 117, // 4: daemon.PeerState.lastWireguardHandshake:type_name -> google.protobuf.Timestamp + 116, // 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 @@ -7784,8 +7861,8 @@ var file_daemon_proto_depIdxs = []int32{ 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 - 111, // 16: daemon.Network.resolvedIPs:type_name -> daemon.Network.ResolvedIPsEntry - 112, // 17: daemon.PortInfo.range:type_name -> daemon.PortInfo.Range + 113, // 16: daemon.Network.resolvedIPs:type_name -> daemon.Network.ResolvedIPsEntry + 114, // 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 @@ -7796,16 +7873,16 @@ var file_daemon_proto_depIdxs = []int32{ 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 - 115, // 28: daemon.SystemEvent.timestamp:type_name -> google.protobuf.Timestamp - 113, // 29: daemon.SystemEvent.metadata:type_name -> daemon.SystemEvent.MetadataEntry + 117, // 28: daemon.SystemEvent.timestamp:type_name -> google.protobuf.Timestamp + 115, // 29: daemon.SystemEvent.metadata:type_name -> daemon.SystemEvent.MetadataEntry 57, // 30: daemon.GetEventsResponse.events:type_name -> daemon.SystemEvent - 114, // 31: daemon.SetConfigRequest.dnsRouteInterval:type_name -> google.protobuf.Duration + 116, // 31: daemon.SetConfigRequest.dnsRouteInterval:type_name -> google.protobuf.Duration 72, // 32: daemon.ListProfilesResponse.profiles:type_name -> daemon.Profile - 115, // 33: daemon.WaitExtendAuthSessionResponse.sessionExpiresAt:type_name -> google.protobuf.Timestamp + 117, // 33: daemon.WaitExtendAuthSessionResponse.sessionExpiresAt:type_name -> google.protobuf.Timestamp 1, // 34: daemon.ExposeServiceRequest.protocol:type_name -> daemon.ExposeProtocol 104, // 35: daemon.ExposeServiceEvent.ready:type_name -> daemon.ExposeServiceReady - 114, // 36: daemon.StartCaptureRequest.duration:type_name -> google.protobuf.Duration - 114, // 37: daemon.StartBundleCaptureRequest.timeout:type_name -> google.protobuf.Duration + 116, // 36: daemon.StartCaptureRequest.duration:type_name -> google.protobuf.Duration + 116, // 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 @@ -7813,94 +7890,96 @@ var file_daemon_proto_depIdxs = []int32{ 11, // 42: daemon.DaemonService.Status:input_type -> daemon.StatusRequest 11, // 43: daemon.DaemonService.SubscribeStatus:input_type -> daemon.StatusRequest 13, // 44: daemon.DaemonService.Down:input_type -> daemon.DownRequest - 15, // 45: daemon.DaemonService.GetConfig:input_type -> daemon.GetConfigRequest - 26, // 46: daemon.DaemonService.ListNetworks:input_type -> daemon.ListNetworksRequest - 28, // 47: daemon.DaemonService.SelectNetworks:input_type -> daemon.SelectNetworksRequest - 28, // 48: daemon.DaemonService.DeselectNetworks:input_type -> daemon.SelectNetworksRequest - 4, // 49: daemon.DaemonService.ForwardingRules:input_type -> daemon.EmptyRequest - 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 - 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 - 105, // 58: daemon.DaemonService.StartCapture:input_type -> daemon.StartCaptureRequest - 107, // 59: daemon.DaemonService.StartBundleCapture:input_type -> daemon.StartBundleCaptureRequest - 109, // 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.RenameProfile:input_type -> daemon.RenameProfileRequest - 68, // 68: daemon.DaemonService.RemoveProfile:input_type -> daemon.RemoveProfileRequest - 70, // 69: daemon.DaemonService.ListProfiles:input_type -> daemon.ListProfilesRequest - 73, // 70: daemon.DaemonService.GetActiveProfile:input_type -> daemon.GetActiveProfileRequest - 75, // 71: daemon.DaemonService.Logout:input_type -> daemon.LogoutRequest - 79, // 72: daemon.DaemonService.GetFeatures:input_type -> daemon.GetFeaturesRequest - 82, // 73: daemon.DaemonService.TriggerUpdate:input_type -> daemon.TriggerUpdateRequest - 84, // 74: daemon.DaemonService.GetPeerSSHHostKey:input_type -> daemon.GetPeerSSHHostKeyRequest - 86, // 75: daemon.DaemonService.RequestJWTAuth:input_type -> daemon.RequestJWTAuthRequest - 88, // 76: daemon.DaemonService.WaitJWTToken:input_type -> daemon.WaitJWTTokenRequest - 90, // 77: daemon.DaemonService.RequestExtendAuthSession:input_type -> daemon.RequestExtendAuthSessionRequest - 92, // 78: daemon.DaemonService.WaitExtendAuthSession:input_type -> daemon.WaitExtendAuthSessionRequest - 94, // 79: daemon.DaemonService.DismissSessionWarning:input_type -> daemon.DismissSessionWarningRequest - 96, // 80: daemon.DaemonService.StartCPUProfile:input_type -> daemon.StartCPUProfileRequest - 98, // 81: daemon.DaemonService.StopCPUProfile:input_type -> daemon.StopCPUProfileRequest - 100, // 82: daemon.DaemonService.GetInstallerResult:input_type -> daemon.InstallerResultRequest - 102, // 83: daemon.DaemonService.ExposeService:input_type -> daemon.ExposeServiceRequest - 77, // 84: daemon.DaemonService.WailsUIReady:input_type -> daemon.WailsUIReadyRequest - 6, // 85: daemon.DaemonService.Login:output_type -> daemon.LoginResponse - 8, // 86: daemon.DaemonService.WaitSSOLogin:output_type -> daemon.WaitSSOLoginResponse - 10, // 87: daemon.DaemonService.Up:output_type -> daemon.UpResponse - 12, // 88: daemon.DaemonService.Status:output_type -> daemon.StatusResponse - 12, // 89: daemon.DaemonService.SubscribeStatus:output_type -> daemon.StatusResponse - 14, // 90: daemon.DaemonService.Down:output_type -> daemon.DownResponse - 16, // 91: daemon.DaemonService.GetConfig:output_type -> daemon.GetConfigResponse - 27, // 92: daemon.DaemonService.ListNetworks:output_type -> daemon.ListNetworksResponse - 29, // 93: daemon.DaemonService.SelectNetworks:output_type -> daemon.SelectNetworksResponse - 29, // 94: daemon.DaemonService.DeselectNetworks:output_type -> daemon.SelectNetworksResponse - 34, // 95: daemon.DaemonService.ForwardingRules:output_type -> daemon.ForwardingRulesResponse - 36, // 96: daemon.DaemonService.DebugBundle:output_type -> daemon.DebugBundleResponse - 38, // 97: daemon.DaemonService.GetLogLevel:output_type -> daemon.GetLogLevelResponse - 40, // 98: daemon.DaemonService.SetLogLevel:output_type -> daemon.SetLogLevelResponse - 45, // 99: daemon.DaemonService.ListStates:output_type -> daemon.ListStatesResponse - 47, // 100: daemon.DaemonService.CleanState:output_type -> daemon.CleanStateResponse - 49, // 101: daemon.DaemonService.DeleteState:output_type -> daemon.DeleteStateResponse - 51, // 102: daemon.DaemonService.SetSyncResponsePersistence:output_type -> daemon.SetSyncResponsePersistenceResponse - 55, // 103: daemon.DaemonService.TracePacket:output_type -> daemon.TracePacketResponse - 106, // 104: daemon.DaemonService.StartCapture:output_type -> daemon.CapturePacket - 108, // 105: daemon.DaemonService.StartBundleCapture:output_type -> daemon.StartBundleCaptureResponse - 110, // 106: daemon.DaemonService.StopBundleCapture:output_type -> daemon.StopBundleCaptureResponse - 57, // 107: daemon.DaemonService.SubscribeEvents:output_type -> daemon.SystemEvent - 59, // 108: daemon.DaemonService.GetEvents:output_type -> daemon.GetEventsResponse - 42, // 109: daemon.DaemonService.RegisterUILog:output_type -> daemon.RegisterUILogResponse - 61, // 110: daemon.DaemonService.SwitchProfile:output_type -> daemon.SwitchProfileResponse - 63, // 111: daemon.DaemonService.SetConfig:output_type -> daemon.SetConfigResponse - 65, // 112: daemon.DaemonService.AddProfile:output_type -> daemon.AddProfileResponse - 67, // 113: daemon.DaemonService.RenameProfile:output_type -> daemon.RenameProfileResponse - 69, // 114: daemon.DaemonService.RemoveProfile:output_type -> daemon.RemoveProfileResponse - 71, // 115: daemon.DaemonService.ListProfiles:output_type -> daemon.ListProfilesResponse - 74, // 116: daemon.DaemonService.GetActiveProfile:output_type -> daemon.GetActiveProfileResponse - 76, // 117: daemon.DaemonService.Logout:output_type -> daemon.LogoutResponse - 80, // 118: daemon.DaemonService.GetFeatures:output_type -> daemon.GetFeaturesResponse - 83, // 119: daemon.DaemonService.TriggerUpdate:output_type -> daemon.TriggerUpdateResponse - 85, // 120: daemon.DaemonService.GetPeerSSHHostKey:output_type -> daemon.GetPeerSSHHostKeyResponse - 87, // 121: daemon.DaemonService.RequestJWTAuth:output_type -> daemon.RequestJWTAuthResponse - 89, // 122: daemon.DaemonService.WaitJWTToken:output_type -> daemon.WaitJWTTokenResponse - 91, // 123: daemon.DaemonService.RequestExtendAuthSession:output_type -> daemon.RequestExtendAuthSessionResponse - 93, // 124: daemon.DaemonService.WaitExtendAuthSession:output_type -> daemon.WaitExtendAuthSessionResponse - 95, // 125: daemon.DaemonService.DismissSessionWarning:output_type -> daemon.DismissSessionWarningResponse - 97, // 126: daemon.DaemonService.StartCPUProfile:output_type -> daemon.StartCPUProfileResponse - 99, // 127: daemon.DaemonService.StopCPUProfile:output_type -> daemon.StopCPUProfileResponse - 101, // 128: daemon.DaemonService.GetInstallerResult:output_type -> daemon.InstallerResultResponse - 103, // 129: daemon.DaemonService.ExposeService:output_type -> daemon.ExposeServiceEvent - 78, // 130: daemon.DaemonService.WailsUIReady:output_type -> daemon.WailsUIReadyResponse - 85, // [85:131] is the sub-list for method output_type - 39, // [39:85] is the sub-list for method input_type + 111, // 45: daemon.DaemonService.DownAsync:input_type -> daemon.DownAsyncRequest + 15, // 46: daemon.DaemonService.GetConfig:input_type -> daemon.GetConfigRequest + 26, // 47: daemon.DaemonService.ListNetworks:input_type -> daemon.ListNetworksRequest + 28, // 48: daemon.DaemonService.SelectNetworks:input_type -> daemon.SelectNetworksRequest + 28, // 49: daemon.DaemonService.DeselectNetworks:input_type -> daemon.SelectNetworksRequest + 4, // 50: daemon.DaemonService.ForwardingRules:input_type -> daemon.EmptyRequest + 35, // 51: daemon.DaemonService.DebugBundle:input_type -> daemon.DebugBundleRequest + 37, // 52: daemon.DaemonService.GetLogLevel:input_type -> daemon.GetLogLevelRequest + 39, // 53: daemon.DaemonService.SetLogLevel:input_type -> daemon.SetLogLevelRequest + 44, // 54: daemon.DaemonService.ListStates:input_type -> daemon.ListStatesRequest + 46, // 55: daemon.DaemonService.CleanState:input_type -> daemon.CleanStateRequest + 48, // 56: daemon.DaemonService.DeleteState:input_type -> daemon.DeleteStateRequest + 50, // 57: daemon.DaemonService.SetSyncResponsePersistence:input_type -> daemon.SetSyncResponsePersistenceRequest + 53, // 58: daemon.DaemonService.TracePacket:input_type -> daemon.TracePacketRequest + 105, // 59: daemon.DaemonService.StartCapture:input_type -> daemon.StartCaptureRequest + 107, // 60: daemon.DaemonService.StartBundleCapture:input_type -> daemon.StartBundleCaptureRequest + 109, // 61: daemon.DaemonService.StopBundleCapture:input_type -> daemon.StopBundleCaptureRequest + 56, // 62: daemon.DaemonService.SubscribeEvents:input_type -> daemon.SubscribeRequest + 58, // 63: daemon.DaemonService.GetEvents:input_type -> daemon.GetEventsRequest + 41, // 64: daemon.DaemonService.RegisterUILog:input_type -> daemon.RegisterUILogRequest + 60, // 65: daemon.DaemonService.SwitchProfile:input_type -> daemon.SwitchProfileRequest + 62, // 66: daemon.DaemonService.SetConfig:input_type -> daemon.SetConfigRequest + 64, // 67: daemon.DaemonService.AddProfile:input_type -> daemon.AddProfileRequest + 66, // 68: daemon.DaemonService.RenameProfile:input_type -> daemon.RenameProfileRequest + 68, // 69: daemon.DaemonService.RemoveProfile:input_type -> daemon.RemoveProfileRequest + 70, // 70: daemon.DaemonService.ListProfiles:input_type -> daemon.ListProfilesRequest + 73, // 71: daemon.DaemonService.GetActiveProfile:input_type -> daemon.GetActiveProfileRequest + 75, // 72: daemon.DaemonService.Logout:input_type -> daemon.LogoutRequest + 79, // 73: daemon.DaemonService.GetFeatures:input_type -> daemon.GetFeaturesRequest + 82, // 74: daemon.DaemonService.TriggerUpdate:input_type -> daemon.TriggerUpdateRequest + 84, // 75: daemon.DaemonService.GetPeerSSHHostKey:input_type -> daemon.GetPeerSSHHostKeyRequest + 86, // 76: daemon.DaemonService.RequestJWTAuth:input_type -> daemon.RequestJWTAuthRequest + 88, // 77: daemon.DaemonService.WaitJWTToken:input_type -> daemon.WaitJWTTokenRequest + 90, // 78: daemon.DaemonService.RequestExtendAuthSession:input_type -> daemon.RequestExtendAuthSessionRequest + 92, // 79: daemon.DaemonService.WaitExtendAuthSession:input_type -> daemon.WaitExtendAuthSessionRequest + 94, // 80: daemon.DaemonService.DismissSessionWarning:input_type -> daemon.DismissSessionWarningRequest + 96, // 81: daemon.DaemonService.StartCPUProfile:input_type -> daemon.StartCPUProfileRequest + 98, // 82: daemon.DaemonService.StopCPUProfile:input_type -> daemon.StopCPUProfileRequest + 100, // 83: daemon.DaemonService.GetInstallerResult:input_type -> daemon.InstallerResultRequest + 102, // 84: daemon.DaemonService.ExposeService:input_type -> daemon.ExposeServiceRequest + 77, // 85: daemon.DaemonService.WailsUIReady:input_type -> daemon.WailsUIReadyRequest + 6, // 86: daemon.DaemonService.Login:output_type -> daemon.LoginResponse + 8, // 87: daemon.DaemonService.WaitSSOLogin:output_type -> daemon.WaitSSOLoginResponse + 10, // 88: daemon.DaemonService.Up:output_type -> daemon.UpResponse + 12, // 89: daemon.DaemonService.Status:output_type -> daemon.StatusResponse + 12, // 90: daemon.DaemonService.SubscribeStatus:output_type -> daemon.StatusResponse + 14, // 91: daemon.DaemonService.Down:output_type -> daemon.DownResponse + 112, // 92: daemon.DaemonService.DownAsync:output_type -> daemon.DownAsyncResponse + 16, // 93: daemon.DaemonService.GetConfig:output_type -> daemon.GetConfigResponse + 27, // 94: daemon.DaemonService.ListNetworks:output_type -> daemon.ListNetworksResponse + 29, // 95: daemon.DaemonService.SelectNetworks:output_type -> daemon.SelectNetworksResponse + 29, // 96: daemon.DaemonService.DeselectNetworks:output_type -> daemon.SelectNetworksResponse + 34, // 97: daemon.DaemonService.ForwardingRules:output_type -> daemon.ForwardingRulesResponse + 36, // 98: daemon.DaemonService.DebugBundle:output_type -> daemon.DebugBundleResponse + 38, // 99: daemon.DaemonService.GetLogLevel:output_type -> daemon.GetLogLevelResponse + 40, // 100: daemon.DaemonService.SetLogLevel:output_type -> daemon.SetLogLevelResponse + 45, // 101: daemon.DaemonService.ListStates:output_type -> daemon.ListStatesResponse + 47, // 102: daemon.DaemonService.CleanState:output_type -> daemon.CleanStateResponse + 49, // 103: daemon.DaemonService.DeleteState:output_type -> daemon.DeleteStateResponse + 51, // 104: daemon.DaemonService.SetSyncResponsePersistence:output_type -> daemon.SetSyncResponsePersistenceResponse + 55, // 105: daemon.DaemonService.TracePacket:output_type -> daemon.TracePacketResponse + 106, // 106: daemon.DaemonService.StartCapture:output_type -> daemon.CapturePacket + 108, // 107: daemon.DaemonService.StartBundleCapture:output_type -> daemon.StartBundleCaptureResponse + 110, // 108: daemon.DaemonService.StopBundleCapture:output_type -> daemon.StopBundleCaptureResponse + 57, // 109: daemon.DaemonService.SubscribeEvents:output_type -> daemon.SystemEvent + 59, // 110: daemon.DaemonService.GetEvents:output_type -> daemon.GetEventsResponse + 42, // 111: daemon.DaemonService.RegisterUILog:output_type -> daemon.RegisterUILogResponse + 61, // 112: daemon.DaemonService.SwitchProfile:output_type -> daemon.SwitchProfileResponse + 63, // 113: daemon.DaemonService.SetConfig:output_type -> daemon.SetConfigResponse + 65, // 114: daemon.DaemonService.AddProfile:output_type -> daemon.AddProfileResponse + 67, // 115: daemon.DaemonService.RenameProfile:output_type -> daemon.RenameProfileResponse + 69, // 116: daemon.DaemonService.RemoveProfile:output_type -> daemon.RemoveProfileResponse + 71, // 117: daemon.DaemonService.ListProfiles:output_type -> daemon.ListProfilesResponse + 74, // 118: daemon.DaemonService.GetActiveProfile:output_type -> daemon.GetActiveProfileResponse + 76, // 119: daemon.DaemonService.Logout:output_type -> daemon.LogoutResponse + 80, // 120: daemon.DaemonService.GetFeatures:output_type -> daemon.GetFeaturesResponse + 83, // 121: daemon.DaemonService.TriggerUpdate:output_type -> daemon.TriggerUpdateResponse + 85, // 122: daemon.DaemonService.GetPeerSSHHostKey:output_type -> daemon.GetPeerSSHHostKeyResponse + 87, // 123: daemon.DaemonService.RequestJWTAuth:output_type -> daemon.RequestJWTAuthResponse + 89, // 124: daemon.DaemonService.WaitJWTToken:output_type -> daemon.WaitJWTTokenResponse + 91, // 125: daemon.DaemonService.RequestExtendAuthSession:output_type -> daemon.RequestExtendAuthSessionResponse + 93, // 126: daemon.DaemonService.WaitExtendAuthSession:output_type -> daemon.WaitExtendAuthSessionResponse + 95, // 127: daemon.DaemonService.DismissSessionWarning:output_type -> daemon.DismissSessionWarningResponse + 97, // 128: daemon.DaemonService.StartCPUProfile:output_type -> daemon.StartCPUProfileResponse + 99, // 129: daemon.DaemonService.StopCPUProfile:output_type -> daemon.StopCPUProfileResponse + 101, // 130: daemon.DaemonService.GetInstallerResult:output_type -> daemon.InstallerResultResponse + 103, // 131: daemon.DaemonService.ExposeService:output_type -> daemon.ExposeServiceEvent + 78, // 132: daemon.DaemonService.WailsUIReady:output_type -> daemon.WailsUIReadyResponse + 86, // [86:133] is the sub-list for method output_type + 39, // [39:86] 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 @@ -7935,7 +8014,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: 110, + NumMessages: 112, NumExtensions: 0, NumServices: 1, }, diff --git a/client/proto/daemon.pb.gw.go b/client/proto/daemon.pb.gw.go index b64dfeea1..dcf8a5f40 100644 --- a/client/proto/daemon.pb.gw.go +++ b/client/proto/daemon.pb.gw.go @@ -175,6 +175,30 @@ func local_request_DaemonService_Down_0(ctx context.Context, marshaler runtime.M return msg, metadata, err } +func request_DaemonService_DownAsync_0(ctx context.Context, marshaler runtime.Marshaler, client DaemonServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq DownAsyncRequest + metadata runtime.ServerMetadata + ) + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + msg, err := client.DownAsync(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err +} + +func local_request_DaemonService_DownAsync_0(ctx context.Context, marshaler runtime.Marshaler, server DaemonServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq DownAsyncRequest + metadata runtime.ServerMetadata + ) + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + msg, err := server.DownAsync(ctx, &protoReq) + return msg, metadata, err +} + func request_DaemonService_GetConfig_0(ctx context.Context, marshaler runtime.Marshaler, client DaemonServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var ( protoReq GetConfigRequest @@ -1236,6 +1260,26 @@ func RegisterDaemonServiceHandlerServer(ctx context.Context, mux *runtime.ServeM } forward_DaemonService_Down_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) + mux.Handle(http.MethodPost, pattern_DaemonService_DownAsync_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/daemon.DaemonService/DownAsync", runtime.WithHTTPPathPattern("/daemon.DaemonService/DownAsync")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_DaemonService_DownAsync_0(annotatedContext, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_DaemonService_DownAsync_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) mux.Handle(http.MethodPost, pattern_DaemonService_GetConfig_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -2139,6 +2183,23 @@ func RegisterDaemonServiceHandlerClient(ctx context.Context, mux *runtime.ServeM } forward_DaemonService_Down_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) + mux.Handle(http.MethodPost, pattern_DaemonService_DownAsync_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/daemon.DaemonService/DownAsync", runtime.WithHTTPPathPattern("/daemon.DaemonService/DownAsync")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_DaemonService_DownAsync_0(annotatedContext, inboundMarshaler, client, req, pathParams) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_DaemonService_DownAsync_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) mux.Handle(http.MethodPost, pattern_DaemonService_GetConfig_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -2829,6 +2890,7 @@ var ( pattern_DaemonService_Status_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"daemon.DaemonService", "Status"}, "")) pattern_DaemonService_SubscribeStatus_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"daemon.DaemonService", "SubscribeStatus"}, "")) pattern_DaemonService_Down_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"daemon.DaemonService", "Down"}, "")) + pattern_DaemonService_DownAsync_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"daemon.DaemonService", "DownAsync"}, "")) pattern_DaemonService_GetConfig_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"daemon.DaemonService", "GetConfig"}, "")) pattern_DaemonService_ListNetworks_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"daemon.DaemonService", "ListNetworks"}, "")) pattern_DaemonService_SelectNetworks_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"daemon.DaemonService", "SelectNetworks"}, "")) @@ -2878,6 +2940,7 @@ var ( forward_DaemonService_Status_0 = runtime.ForwardResponseMessage forward_DaemonService_SubscribeStatus_0 = runtime.ForwardResponseStream forward_DaemonService_Down_0 = runtime.ForwardResponseMessage + forward_DaemonService_DownAsync_0 = runtime.ForwardResponseMessage forward_DaemonService_GetConfig_0 = runtime.ForwardResponseMessage forward_DaemonService_ListNetworks_0 = runtime.ForwardResponseMessage forward_DaemonService_SelectNetworks_0 = runtime.ForwardResponseMessage diff --git a/client/proto/daemon.proto b/client/proto/daemon.proto index 8d5294eb7..25abf2f1f 100644 --- a/client/proto/daemon.proto +++ b/client/proto/daemon.proto @@ -33,6 +33,10 @@ service DaemonService { // Down stops engine work in the daemon. rpc Down(DownRequest) returns (DownResponse) {} + // DownAsync starts stopping engine work in the daemon and returns + // immediately without waiting for the teardown to complete. + rpc DownAsync(DownAsyncRequest) returns (DownAsyncResponse) {} + // GetConfig of the daemon. rpc GetConfig(GetConfigRequest) returns (GetConfigResponse) {} @@ -1046,3 +1050,7 @@ message StartBundleCaptureRequest { message StartBundleCaptureResponse {} message StopBundleCaptureRequest {} message StopBundleCaptureResponse {} + +message DownAsyncRequest {} + +message DownAsyncResponse {} diff --git a/client/proto/daemon_grpc.pb.go b/client/proto/daemon_grpc.pb.go index 2d01d474d..a5741fc12 100644 --- a/client/proto/daemon_grpc.pb.go +++ b/client/proto/daemon_grpc.pb.go @@ -25,6 +25,7 @@ const ( DaemonService_Status_FullMethodName = "/daemon.DaemonService/Status" DaemonService_SubscribeStatus_FullMethodName = "/daemon.DaemonService/SubscribeStatus" DaemonService_Down_FullMethodName = "/daemon.DaemonService/Down" + DaemonService_DownAsync_FullMethodName = "/daemon.DaemonService/DownAsync" DaemonService_GetConfig_FullMethodName = "/daemon.DaemonService/GetConfig" DaemonService_ListNetworks_FullMethodName = "/daemon.DaemonService/ListNetworks" DaemonService_SelectNetworks_FullMethodName = "/daemon.DaemonService/SelectNetworks" @@ -87,6 +88,9 @@ type DaemonServiceClient interface { SubscribeStatus(ctx context.Context, in *StatusRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[StatusResponse], error) // Down stops engine work in the daemon. Down(ctx context.Context, in *DownRequest, opts ...grpc.CallOption) (*DownResponse, error) + // DownAsync starts stopping engine work in the daemon and returns + // immediately without waiting for the teardown to complete. + DownAsync(ctx context.Context, in *DownAsyncRequest, opts ...grpc.CallOption) (*DownAsyncResponse, error) // GetConfig of the daemon. GetConfig(ctx context.Context, in *GetConfigRequest, opts ...grpc.CallOption) (*GetConfigResponse, error) // List available networks @@ -250,6 +254,16 @@ func (c *daemonServiceClient) Down(ctx context.Context, in *DownRequest, opts .. return out, nil } +func (c *daemonServiceClient) DownAsync(ctx context.Context, in *DownAsyncRequest, opts ...grpc.CallOption) (*DownAsyncResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(DownAsyncResponse) + err := c.cc.Invoke(ctx, DaemonService_DownAsync_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *daemonServiceClient) GetConfig(ctx context.Context, in *GetConfigRequest, opts ...grpc.CallOption) (*GetConfigResponse, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(GetConfigResponse) @@ -697,6 +711,9 @@ type DaemonServiceServer interface { SubscribeStatus(*StatusRequest, grpc.ServerStreamingServer[StatusResponse]) error // Down stops engine work in the daemon. Down(context.Context, *DownRequest) (*DownResponse, error) + // DownAsync starts stopping engine work in the daemon and returns + // immediately without waiting for the teardown to complete. + DownAsync(context.Context, *DownAsyncRequest) (*DownAsyncResponse, error) // GetConfig of the daemon. GetConfig(context.Context, *GetConfigRequest) (*GetConfigResponse, error) // List available networks @@ -809,6 +826,9 @@ func (UnimplementedDaemonServiceServer) SubscribeStatus(*StatusRequest, grpc.Ser func (UnimplementedDaemonServiceServer) Down(context.Context, *DownRequest) (*DownResponse, error) { return nil, status.Error(codes.Unimplemented, "method Down not implemented") } +func (UnimplementedDaemonServiceServer) DownAsync(context.Context, *DownAsyncRequest) (*DownAsyncResponse, error) { + return nil, status.Error(codes.Unimplemented, "method DownAsync not implemented") +} func (UnimplementedDaemonServiceServer) GetConfig(context.Context, *GetConfigRequest) (*GetConfigResponse, error) { return nil, status.Error(codes.Unimplemented, "method GetConfig not implemented") } @@ -1051,6 +1071,24 @@ func _DaemonService_Down_Handler(srv interface{}, ctx context.Context, dec func( return interceptor(ctx, in, info, handler) } +func _DaemonService_DownAsync_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DownAsyncRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(DaemonServiceServer).DownAsync(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: DaemonService_DownAsync_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(DaemonServiceServer).DownAsync(ctx, req.(*DownAsyncRequest)) + } + return interceptor(ctx, in, info, handler) +} + func _DaemonService_GetConfig_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(GetConfigRequest) if err := dec(in); err != nil { @@ -1777,6 +1815,10 @@ var DaemonService_ServiceDesc = grpc.ServiceDesc{ MethodName: "Down", Handler: _DaemonService_Down_Handler, }, + { + MethodName: "DownAsync", + Handler: _DaemonService_DownAsync_Handler, + }, { MethodName: "GetConfig", Handler: _DaemonService_GetConfig_Handler, diff --git a/client/server/server.go b/client/server/server.go index 2b919d58d..591bd735a 100644 --- a/client/server/server.go +++ b/client/server/server.go @@ -1074,20 +1074,40 @@ func (s *Server) SwitchProfile(callerCtx context.Context, msg *proto.SwitchProfi } // Down engine work in the daemon. -func (s *Server) Down(ctx context.Context, _ *proto.DownRequest) (*proto.DownResponse, error) { +func (s *Server) Down(_ context.Context, _ *proto.DownRequest) (*proto.DownResponse, error) { + giveUpChan, err := s.beginDown() + if err != nil { + return nil, err + } + s.finishDown(giveUpChan) + return &proto.DownResponse{}, nil +} + +func (s *Server) DownAsync(_ context.Context, _ *proto.DownAsyncRequest) (*proto.DownAsyncResponse, error) { + giveUpChan, err := s.beginDown() + if err != nil { + return nil, err + } + go s.finishDown(giveUpChan) + return &proto.DownAsyncResponse{}, nil +} + +func (s *Server) beginDown() (chan struct{}, error) { s.mutex.Lock() + defer s.mutex.Unlock() giveUpChan := s.clientGiveUpChan if err := s.cleanupConnection(); err != nil { - s.mutex.Unlock() // todo review to update the status in case any type of error log.Errorf("failed to shut down properly: %v", err) return nil, err } - s.mutex.Unlock() + return giveUpChan, nil +} +func (s *Server) finishDown(giveUpChan chan struct{}) { // Wait for the connectWithRetryRuns goroutine to finish with a short timeout. // This prevents the goroutine from setting ErrResetConnection after Down() returns. // The giveUpChan is closed by the goroutine's deferred cleanup (see @@ -1116,8 +1136,6 @@ func (s *Server) Down(ctx context.Context, _ *proto.DownRequest) (*proto.DownRes // failed to log in. s.statusRecorder.MarkManagementDisconnected(nil) s.statusRecorder.MarkSignalDisconnected(nil) - - return &proto.DownResponse{}, nil } func (s *Server) cleanupConnection() error { diff --git a/client/ui/services/connection.go b/client/ui/services/connection.go index fae7ddd23..5d3660878 100644 --- a/client/ui/services/connection.go +++ b/client/ui/services/connection.go @@ -177,6 +177,17 @@ func (s *Connection) Down(ctx context.Context) error { return nil } +func (s *Connection) DownAsync(ctx context.Context) error { + cli, err := s.conn.Client() + if err != nil { + return err + } + if _, err = cli.DownAsync(ctx, &proto.DownAsyncRequest{}); err != nil { + return s.classifyDaemonError(err) + } + return nil +} + // OpenURL opens url in an external browser; the embedded webview blocks // window.open, so the SSO verification page can't pop inline. Honors $BROWSER // before the platform default. diff --git a/client/ui/tray.go b/client/ui/tray.go index 700d94098..a6d3d9d92 100644 --- a/client/ui/tray.go +++ b/client/ui/tray.go @@ -30,6 +30,8 @@ const ( statusError = "Error" + quitDownTimeout = 5 * time.Second + urlGitHubRepo = "https://github.com/netbirdio/netbird" urlGitHubReleases = "https://github.com/netbirdio/netbird/releases/latest" urlDocs = "https://docs.netbird.io" @@ -446,11 +448,28 @@ func (t *Tray) buildMenu() *application.Menu { menu.AddSeparator() menu.Add(t.loc.T("tray.menu.quit")). SetAccelerator("CmdOrCtrl+Q"). - OnClick(func(*application.Context) { t.app.Quit() }) + OnClick(func(*application.Context) { t.handleQuit() }) return menu } +func (t *Tray) handleQuit() { + t.profileMu.Lock() + if t.switchCancel != nil { + t.switchCancel() + t.switchCancel = nil + } + t.profileMu.Unlock() + t.svc.DaemonFeed.CancelProfileSwitch() + + ctx, cancel := context.WithTimeout(context.Background(), quitDownTimeout) + defer cancel() + if err := t.svc.Connection.DownAsync(ctx); err != nil { + log.Errorf("disconnect on quit: %v", err) + } + t.app.Quit() +} + // handleConnect receives the clicked item from the buildMenu closure — // t.upItem is menuMu-guarded and must not be read here. func (t *Tray) handleConnect(upItem *application.MenuItem) {