diff --git a/go.mod b/go.mod index eef195a06..375696497 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( buf.build/go/protoyaml v0.3.1 github.com/benbjohnson/clock v1.3.5 github.com/dennwc/iters v1.0.1 - github.com/frostbyte73/core v0.1.0 + github.com/frostbyte73/core v0.1.1 github.com/fsnotify/fsnotify v1.8.0 github.com/gammazero/deque v1.0.0 github.com/go-jose/go-jose/v3 v3.0.3 diff --git a/go.sum b/go.sum index fcfbc4476..268ae83a8 100644 --- a/go.sum +++ b/go.sum @@ -49,8 +49,8 @@ github.com/envoyproxy/protoc-gen-validate v1.1.0 h1:tntQDh69XqOCOZsDz0lVJQez/2L6 github.com/envoyproxy/protoc-gen-validate v1.1.0/go.mod h1:sXRDRVmzEbkM7CVcM06s9shE/m23dg3wzjl0UWqJ2q4= github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= -github.com/frostbyte73/core v0.1.0 h1:KA4klxRjLbEHLv+judmlRtweyjcj1NWOJ+BQHQgNxfw= -github.com/frostbyte73/core v0.1.0/go.mod h1:mhfOtR+xWAvwXiwor7jnqPMnu4fxbv1F2MwZ0BEpzZo= +github.com/frostbyte73/core v0.1.1 h1:ChhJOR7bAKOCPbA+lqDLE2cGKlCG5JXsDvvQr4YaJIA= +github.com/frostbyte73/core v0.1.1/go.mod h1:mhfOtR+xWAvwXiwor7jnqPMnu4fxbv1F2MwZ0BEpzZo= github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M= github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/gammazero/deque v1.0.0 h1:LTmimT8H7bXkkCy6gZX7zNLtkbz4NdS2z8LZuor3j34= diff --git a/livekit/livekit_analytics.pb.go b/livekit/livekit_analytics.pb.go index ad196bb60..2833083e0 100644 --- a/livekit/livekit_analytics.pb.go +++ b/livekit/livekit_analytics.pb.go @@ -125,6 +125,7 @@ const ( AnalyticsEventType_SIP_CALL_ENDED AnalyticsEventType = 39 AnalyticsEventType_REPORT AnalyticsEventType = 40 AnalyticsEventType_API_CALL AnalyticsEventType = 41 + AnalyticsEventType_WEBHOOK AnalyticsEventType = 42 ) // Enum value maps for AnalyticsEventType. @@ -170,6 +171,7 @@ var ( 39: "SIP_CALL_ENDED", 40: "REPORT", 41: "API_CALL", + 42: "WEBHOOK", } AnalyticsEventType_value = map[string]int32{ "ROOM_CREATED": 0, @@ -212,6 +214,7 @@ var ( "SIP_CALL_ENDED": 39, "REPORT": 40, "API_CALL": 41, + "WEBHOOK": 42, } ) @@ -873,6 +876,7 @@ type AnalyticsEvent struct { SipDispatchRule *SIPDispatchRuleInfo `protobuf:"bytes,32,opt,name=sip_dispatch_rule,json=sipDispatchRule,proto3" json:"sip_dispatch_rule,omitempty"` Report *ReportInfo `protobuf:"bytes,33,opt,name=report,proto3" json:"report,omitempty"` ApiCall *APICallInfo `protobuf:"bytes,34,opt,name=api_call,json=apiCall,proto3" json:"api_call,omitempty"` + Webhook *WebhookInfo `protobuf:"bytes,35,opt,name=webhook,proto3" json:"webhook,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -1131,6 +1135,13 @@ func (x *AnalyticsEvent) GetApiCall() *APICallInfo { return nil } +func (x *AnalyticsEvent) GetWebhook() *WebhookInfo { + if x != nil { + return x.Webhook + } + return nil +} + type AnalyticsEvents struct { state protoimpl.MessageState `protogen:"open.v1"` Events []*AnalyticsEvent `protobuf:"bytes,1,rep,name=events,proto3" json:"events,omitempty"` @@ -1982,6 +1993,218 @@ func (x *APICallInfo) GetDurationNs() int64 { return 0 } +type WebhookInfo struct { + state protoimpl.MessageState `protogen:"open.v1"` + EventId string `protobuf:"bytes,1,opt,name=event_id,json=eventId,proto3" json:"event_id,omitempty"` + Event string `protobuf:"bytes,2,opt,name=event,proto3" json:"event,omitempty"` + ProjectId string `protobuf:"bytes,3,opt,name=project_id,json=projectId,proto3" json:"project_id,omitempty"` + RoomName string `protobuf:"bytes,4,opt,name=room_name,json=roomName,proto3" json:"room_name,omitempty"` + RoomId string `protobuf:"bytes,5,opt,name=room_id,json=roomId,proto3" json:"room_id,omitempty"` + ParticipantIdentity string `protobuf:"bytes,6,opt,name=participant_identity,json=participantIdentity,proto3" json:"participant_identity,omitempty"` + ParticipantId string `protobuf:"bytes,7,opt,name=participant_id,json=participantId,proto3" json:"participant_id,omitempty"` + TrackId string `protobuf:"bytes,8,opt,name=track_id,json=trackId,proto3" json:"track_id,omitempty"` + EgressId string `protobuf:"bytes,9,opt,name=egress_id,json=egressId,proto3" json:"egress_id,omitempty"` + IngressId string `protobuf:"bytes,10,opt,name=ingress_id,json=ingressId,proto3" json:"ingress_id,omitempty"` + CreatedAt *timestamppb.Timestamp `protobuf:"bytes,11,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` + QueuedAt *timestamppb.Timestamp `protobuf:"bytes,12,opt,name=queued_at,json=queuedAt,proto3" json:"queued_at,omitempty"` + QueueDurationNs int64 `protobuf:"varint,13,opt,name=queue_duration_ns,json=queueDurationNs,proto3" json:"queue_duration_ns,omitempty"` + SentAt *timestamppb.Timestamp `protobuf:"bytes,14,opt,name=sent_at,json=sentAt,proto3" json:"sent_at,omitempty"` + SendDurationNs int64 `protobuf:"varint,15,opt,name=send_duration_ns,json=sendDurationNs,proto3" json:"send_duration_ns,omitempty"` + Url string `protobuf:"bytes,16,opt,name=url,proto3" json:"url,omitempty"` + NumDropped int32 `protobuf:"varint,17,opt,name=num_dropped,json=numDropped,proto3" json:"num_dropped,omitempty"` + IsDropped bool `protobuf:"varint,18,opt,name=is_dropped,json=isDropped,proto3" json:"is_dropped,omitempty"` + ServiceStatus string `protobuf:"bytes,19,opt,name=service_status,json=serviceStatus,proto3" json:"service_status,omitempty"` + ServiceErrorCode int32 `protobuf:"varint,20,opt,name=service_error_code,json=serviceErrorCode,proto3" json:"service_error_code,omitempty"` + ServiceError string `protobuf:"bytes,21,opt,name=service_error,json=serviceError,proto3" json:"service_error,omitempty"` + SendError string `protobuf:"bytes,22,opt,name=send_error,json=sendError,proto3" json:"send_error,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *WebhookInfo) Reset() { + *x = WebhookInfo{} + mi := &file_livekit_analytics_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *WebhookInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*WebhookInfo) ProtoMessage() {} + +func (x *WebhookInfo) ProtoReflect() protoreflect.Message { + mi := &file_livekit_analytics_proto_msgTypes[15] + 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 WebhookInfo.ProtoReflect.Descriptor instead. +func (*WebhookInfo) Descriptor() ([]byte, []int) { + return file_livekit_analytics_proto_rawDescGZIP(), []int{15} +} + +func (x *WebhookInfo) GetEventId() string { + if x != nil { + return x.EventId + } + return "" +} + +func (x *WebhookInfo) GetEvent() string { + if x != nil { + return x.Event + } + return "" +} + +func (x *WebhookInfo) GetProjectId() string { + if x != nil { + return x.ProjectId + } + return "" +} + +func (x *WebhookInfo) GetRoomName() string { + if x != nil { + return x.RoomName + } + return "" +} + +func (x *WebhookInfo) GetRoomId() string { + if x != nil { + return x.RoomId + } + return "" +} + +func (x *WebhookInfo) GetParticipantIdentity() string { + if x != nil { + return x.ParticipantIdentity + } + return "" +} + +func (x *WebhookInfo) GetParticipantId() string { + if x != nil { + return x.ParticipantId + } + return "" +} + +func (x *WebhookInfo) GetTrackId() string { + if x != nil { + return x.TrackId + } + return "" +} + +func (x *WebhookInfo) GetEgressId() string { + if x != nil { + return x.EgressId + } + return "" +} + +func (x *WebhookInfo) GetIngressId() string { + if x != nil { + return x.IngressId + } + return "" +} + +func (x *WebhookInfo) GetCreatedAt() *timestamppb.Timestamp { + if x != nil { + return x.CreatedAt + } + return nil +} + +func (x *WebhookInfo) GetQueuedAt() *timestamppb.Timestamp { + if x != nil { + return x.QueuedAt + } + return nil +} + +func (x *WebhookInfo) GetQueueDurationNs() int64 { + if x != nil { + return x.QueueDurationNs + } + return 0 +} + +func (x *WebhookInfo) GetSentAt() *timestamppb.Timestamp { + if x != nil { + return x.SentAt + } + return nil +} + +func (x *WebhookInfo) GetSendDurationNs() int64 { + if x != nil { + return x.SendDurationNs + } + return 0 +} + +func (x *WebhookInfo) GetUrl() string { + if x != nil { + return x.Url + } + return "" +} + +func (x *WebhookInfo) GetNumDropped() int32 { + if x != nil { + return x.NumDropped + } + return 0 +} + +func (x *WebhookInfo) GetIsDropped() bool { + if x != nil { + return x.IsDropped + } + return false +} + +func (x *WebhookInfo) GetServiceStatus() string { + if x != nil { + return x.ServiceStatus + } + return "" +} + +func (x *WebhookInfo) GetServiceErrorCode() int32 { + if x != nil { + return x.ServiceErrorCode + } + return 0 +} + +func (x *WebhookInfo) GetServiceError() string { + if x != nil { + return x.ServiceError + } + return "" +} + +func (x *WebhookInfo) GetSendError() string { + if x != nil { + return x.SendError + } + return "" +} + var File_livekit_analytics_proto protoreflect.FileDescriptor var file_livekit_analytics_proto_rawDesc = string([]byte{ @@ -2103,7 +2326,7 @@ var file_livekit_analytics_proto_rawDesc = string([]byte{ 0x02, 0x52, 0x06, 0x69, 0x73, 0x70, 0x41, 0x73, 0x6e, 0x88, 0x01, 0x01, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x67, 0x65, 0x6f, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x69, 0x73, 0x70, 0x5f, 0x61, 0x73, - 0x6e, 0x22, 0xa9, 0x0b, 0x0a, 0x0e, 0x41, 0x6e, 0x61, 0x6c, 0x79, 0x74, 0x69, 0x63, 0x73, 0x45, + 0x6e, 0x22, 0xd9, 0x0b, 0x0a, 0x0e, 0x41, 0x6e, 0x61, 0x6c, 0x79, 0x74, 0x69, 0x63, 0x73, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x19, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x2f, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x2e, 0x41, 0x6e, 0x61, @@ -2193,7 +2416,10 @@ var file_livekit_analytics_proto_rawDesc = string([]byte{ 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x06, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x2f, 0x0a, 0x08, 0x61, 0x70, 0x69, 0x5f, 0x63, 0x61, 0x6c, 0x6c, 0x18, 0x22, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x2e, 0x41, 0x50, 0x49, 0x43, 0x61, 0x6c, 0x6c, - 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x07, 0x61, 0x70, 0x69, 0x43, 0x61, 0x6c, 0x6c, 0x22, 0x42, 0x0a, + 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x07, 0x61, 0x70, 0x69, 0x43, 0x61, 0x6c, 0x6c, 0x12, 0x2e, 0x0a, + 0x07, 0x77, 0x65, 0x62, 0x68, 0x6f, 0x6f, 0x6b, 0x18, 0x23, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, + 0x2e, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x2e, 0x57, 0x65, 0x62, 0x68, 0x6f, 0x6f, 0x6b, + 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x07, 0x77, 0x65, 0x62, 0x68, 0x6f, 0x6f, 0x6b, 0x22, 0x42, 0x0a, 0x0f, 0x41, 0x6e, 0x61, 0x6c, 0x79, 0x74, 0x69, 0x63, 0x73, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x2f, 0x0a, 0x06, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x2e, 0x41, 0x6e, 0x61, 0x6c, 0x79, @@ -2368,75 +2594,127 @@ var file_livekit_analytics_proto_rawDesc = string([]byte{ 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x73, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x73, - 0x2a, 0x2a, 0x0a, 0x0a, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0c, - 0x0a, 0x08, 0x55, 0x50, 0x53, 0x54, 0x52, 0x45, 0x41, 0x4d, 0x10, 0x00, 0x12, 0x0e, 0x0a, 0x0a, - 0x44, 0x4f, 0x57, 0x4e, 0x53, 0x54, 0x52, 0x45, 0x41, 0x4d, 0x10, 0x01, 0x2a, 0xc9, 0x07, 0x0a, - 0x12, 0x41, 0x6e, 0x61, 0x6c, 0x79, 0x74, 0x69, 0x63, 0x73, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x54, - 0x79, 0x70, 0x65, 0x12, 0x10, 0x0a, 0x0c, 0x52, 0x4f, 0x4f, 0x4d, 0x5f, 0x43, 0x52, 0x45, 0x41, - 0x54, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0e, 0x0a, 0x0a, 0x52, 0x4f, 0x4f, 0x4d, 0x5f, 0x45, 0x4e, - 0x44, 0x45, 0x44, 0x10, 0x01, 0x12, 0x16, 0x0a, 0x12, 0x50, 0x41, 0x52, 0x54, 0x49, 0x43, 0x49, - 0x50, 0x41, 0x4e, 0x54, 0x5f, 0x4a, 0x4f, 0x49, 0x4e, 0x45, 0x44, 0x10, 0x02, 0x12, 0x14, 0x0a, - 0x10, 0x50, 0x41, 0x52, 0x54, 0x49, 0x43, 0x49, 0x50, 0x41, 0x4e, 0x54, 0x5f, 0x4c, 0x45, 0x46, - 0x54, 0x10, 0x03, 0x12, 0x13, 0x0a, 0x0f, 0x54, 0x52, 0x41, 0x43, 0x4b, 0x5f, 0x50, 0x55, 0x42, - 0x4c, 0x49, 0x53, 0x48, 0x45, 0x44, 0x10, 0x04, 0x12, 0x1b, 0x0a, 0x17, 0x54, 0x52, 0x41, 0x43, - 0x4b, 0x5f, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x53, 0x48, 0x5f, 0x52, 0x45, 0x51, 0x55, 0x45, 0x53, - 0x54, 0x45, 0x44, 0x10, 0x14, 0x12, 0x15, 0x0a, 0x11, 0x54, 0x52, 0x41, 0x43, 0x4b, 0x5f, 0x55, - 0x4e, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x53, 0x48, 0x45, 0x44, 0x10, 0x05, 0x12, 0x14, 0x0a, 0x10, - 0x54, 0x52, 0x41, 0x43, 0x4b, 0x5f, 0x53, 0x55, 0x42, 0x53, 0x43, 0x52, 0x49, 0x42, 0x45, 0x44, - 0x10, 0x06, 0x12, 0x1d, 0x0a, 0x19, 0x54, 0x52, 0x41, 0x43, 0x4b, 0x5f, 0x53, 0x55, 0x42, 0x53, - 0x43, 0x52, 0x49, 0x42, 0x45, 0x5f, 0x52, 0x45, 0x51, 0x55, 0x45, 0x53, 0x54, 0x45, 0x44, 0x10, - 0x15, 0x12, 0x1a, 0x0a, 0x16, 0x54, 0x52, 0x41, 0x43, 0x4b, 0x5f, 0x53, 0x55, 0x42, 0x53, 0x43, - 0x52, 0x49, 0x42, 0x45, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x10, 0x19, 0x12, 0x16, 0x0a, - 0x12, 0x54, 0x52, 0x41, 0x43, 0x4b, 0x5f, 0x55, 0x4e, 0x53, 0x55, 0x42, 0x53, 0x43, 0x52, 0x49, - 0x42, 0x45, 0x44, 0x10, 0x07, 0x12, 0x1a, 0x0a, 0x16, 0x54, 0x52, 0x41, 0x43, 0x4b, 0x5f, 0x50, - 0x55, 0x42, 0x4c, 0x49, 0x53, 0x48, 0x45, 0x44, 0x5f, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x10, - 0x0a, 0x12, 0x0f, 0x0a, 0x0b, 0x54, 0x52, 0x41, 0x43, 0x4b, 0x5f, 0x4d, 0x55, 0x54, 0x45, 0x44, - 0x10, 0x17, 0x12, 0x11, 0x0a, 0x0d, 0x54, 0x52, 0x41, 0x43, 0x4b, 0x5f, 0x55, 0x4e, 0x4d, 0x55, - 0x54, 0x45, 0x44, 0x10, 0x18, 0x12, 0x17, 0x0a, 0x13, 0x54, 0x52, 0x41, 0x43, 0x4b, 0x5f, 0x50, - 0x55, 0x42, 0x4c, 0x49, 0x53, 0x48, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x53, 0x10, 0x1a, 0x12, 0x19, - 0x0a, 0x15, 0x54, 0x52, 0x41, 0x43, 0x4b, 0x5f, 0x53, 0x55, 0x42, 0x53, 0x43, 0x52, 0x49, 0x42, - 0x45, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x53, 0x10, 0x1b, 0x12, 0x16, 0x0a, 0x12, 0x50, 0x41, 0x52, - 0x54, 0x49, 0x43, 0x49, 0x50, 0x41, 0x4e, 0x54, 0x5f, 0x41, 0x43, 0x54, 0x49, 0x56, 0x45, 0x10, - 0x0b, 0x12, 0x17, 0x0a, 0x13, 0x50, 0x41, 0x52, 0x54, 0x49, 0x43, 0x49, 0x50, 0x41, 0x4e, 0x54, - 0x5f, 0x52, 0x45, 0x53, 0x55, 0x4d, 0x45, 0x44, 0x10, 0x16, 0x12, 0x12, 0x0a, 0x0e, 0x45, 0x47, - 0x52, 0x45, 0x53, 0x53, 0x5f, 0x53, 0x54, 0x41, 0x52, 0x54, 0x45, 0x44, 0x10, 0x0c, 0x12, 0x10, - 0x0a, 0x0c, 0x45, 0x47, 0x52, 0x45, 0x53, 0x53, 0x5f, 0x45, 0x4e, 0x44, 0x45, 0x44, 0x10, 0x0d, - 0x12, 0x12, 0x0a, 0x0e, 0x45, 0x47, 0x52, 0x45, 0x53, 0x53, 0x5f, 0x55, 0x50, 0x44, 0x41, 0x54, - 0x45, 0x44, 0x10, 0x1c, 0x12, 0x26, 0x0a, 0x22, 0x54, 0x52, 0x41, 0x43, 0x4b, 0x5f, 0x4d, 0x41, - 0x58, 0x5f, 0x53, 0x55, 0x42, 0x53, 0x43, 0x52, 0x49, 0x42, 0x45, 0x44, 0x5f, 0x56, 0x49, 0x44, - 0x45, 0x4f, 0x5f, 0x51, 0x55, 0x41, 0x4c, 0x49, 0x54, 0x59, 0x10, 0x0e, 0x12, 0x0f, 0x0a, 0x0b, - 0x52, 0x45, 0x43, 0x4f, 0x4e, 0x4e, 0x45, 0x43, 0x54, 0x45, 0x44, 0x10, 0x0f, 0x12, 0x13, 0x0a, - 0x0f, 0x49, 0x4e, 0x47, 0x52, 0x45, 0x53, 0x53, 0x5f, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x44, - 0x10, 0x12, 0x12, 0x13, 0x0a, 0x0f, 0x49, 0x4e, 0x47, 0x52, 0x45, 0x53, 0x53, 0x5f, 0x44, 0x45, - 0x4c, 0x45, 0x54, 0x45, 0x44, 0x10, 0x13, 0x12, 0x13, 0x0a, 0x0f, 0x49, 0x4e, 0x47, 0x52, 0x45, - 0x53, 0x53, 0x5f, 0x53, 0x54, 0x41, 0x52, 0x54, 0x45, 0x44, 0x10, 0x10, 0x12, 0x11, 0x0a, 0x0d, - 0x49, 0x4e, 0x47, 0x52, 0x45, 0x53, 0x53, 0x5f, 0x45, 0x4e, 0x44, 0x45, 0x44, 0x10, 0x11, 0x12, - 0x13, 0x0a, 0x0f, 0x49, 0x4e, 0x47, 0x52, 0x45, 0x53, 0x53, 0x5f, 0x55, 0x50, 0x44, 0x41, 0x54, - 0x45, 0x44, 0x10, 0x1d, 0x12, 0x1d, 0x0a, 0x19, 0x53, 0x49, 0x50, 0x5f, 0x49, 0x4e, 0x42, 0x4f, + 0x22, 0xae, 0x06, 0x0a, 0x0b, 0x57, 0x65, 0x62, 0x68, 0x6f, 0x6f, 0x6b, 0x49, 0x6e, 0x66, 0x6f, + 0x12, 0x19, 0x0a, 0x08, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x07, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x65, + 0x76, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x76, 0x65, 0x6e, + 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x69, 0x64, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x49, 0x64, + 0x12, 0x1b, 0x0a, 0x09, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x6f, 0x6f, 0x6d, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x17, 0x0a, + 0x07, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, + 0x72, 0x6f, 0x6f, 0x6d, 0x49, 0x64, 0x12, 0x31, 0x0a, 0x14, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, + 0x69, 0x70, 0x61, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x18, 0x06, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x13, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, + 0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x12, 0x25, 0x0a, 0x0e, 0x70, 0x61, 0x72, + 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0d, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, 0x49, 0x64, + 0x12, 0x19, 0x0a, 0x08, 0x74, 0x72, 0x61, 0x63, 0x6b, 0x5f, 0x69, 0x64, 0x18, 0x08, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x07, 0x74, 0x72, 0x61, 0x63, 0x6b, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x65, + 0x67, 0x72, 0x65, 0x73, 0x73, 0x5f, 0x69, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, + 0x65, 0x67, 0x72, 0x65, 0x73, 0x73, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x69, 0x6e, 0x67, 0x72, + 0x65, 0x73, 0x73, 0x5f, 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x69, 0x6e, + 0x67, 0x72, 0x65, 0x73, 0x73, 0x49, 0x64, 0x12, 0x39, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, + 0x41, 0x74, 0x12, 0x37, 0x0a, 0x09, 0x71, 0x75, 0x65, 0x75, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, + 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, + 0x70, 0x52, 0x08, 0x71, 0x75, 0x65, 0x75, 0x65, 0x64, 0x41, 0x74, 0x12, 0x2a, 0x0a, 0x11, 0x71, + 0x75, 0x65, 0x75, 0x65, 0x5f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x73, + 0x18, 0x0d, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x71, 0x75, 0x65, 0x75, 0x65, 0x44, 0x75, 0x72, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x73, 0x12, 0x33, 0x0a, 0x07, 0x73, 0x65, 0x6e, 0x74, 0x5f, + 0x61, 0x74, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, + 0x74, 0x61, 0x6d, 0x70, 0x52, 0x06, 0x73, 0x65, 0x6e, 0x74, 0x41, 0x74, 0x12, 0x28, 0x0a, 0x10, + 0x73, 0x65, 0x6e, 0x64, 0x5f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x73, + 0x18, 0x0f, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x73, 0x65, 0x6e, 0x64, 0x44, 0x75, 0x72, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x10, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, 0x1f, 0x0a, 0x0b, 0x6e, 0x75, 0x6d, 0x5f, + 0x64, 0x72, 0x6f, 0x70, 0x70, 0x65, 0x64, 0x18, 0x11, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x6e, + 0x75, 0x6d, 0x44, 0x72, 0x6f, 0x70, 0x70, 0x65, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x69, 0x73, 0x5f, + 0x64, 0x72, 0x6f, 0x70, 0x70, 0x65, 0x64, 0x18, 0x12, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x69, + 0x73, 0x44, 0x72, 0x6f, 0x70, 0x70, 0x65, 0x64, 0x12, 0x25, 0x0a, 0x0e, 0x73, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x13, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0d, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, + 0x2c, 0x0a, 0x12, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x65, 0x72, 0x72, 0x6f, 0x72, + 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x14, 0x20, 0x01, 0x28, 0x05, 0x52, 0x10, 0x73, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x23, 0x0a, + 0x0d, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x15, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x45, 0x72, 0x72, + 0x6f, 0x72, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x6e, 0x64, 0x5f, 0x65, 0x72, 0x72, 0x6f, 0x72, + 0x18, 0x16, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x6e, 0x64, 0x45, 0x72, 0x72, 0x6f, + 0x72, 0x2a, 0x2a, 0x0a, 0x0a, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x54, 0x79, 0x70, 0x65, 0x12, + 0x0c, 0x0a, 0x08, 0x55, 0x50, 0x53, 0x54, 0x52, 0x45, 0x41, 0x4d, 0x10, 0x00, 0x12, 0x0e, 0x0a, + 0x0a, 0x44, 0x4f, 0x57, 0x4e, 0x53, 0x54, 0x52, 0x45, 0x41, 0x4d, 0x10, 0x01, 0x2a, 0xd6, 0x07, + 0x0a, 0x12, 0x41, 0x6e, 0x61, 0x6c, 0x79, 0x74, 0x69, 0x63, 0x73, 0x45, 0x76, 0x65, 0x6e, 0x74, + 0x54, 0x79, 0x70, 0x65, 0x12, 0x10, 0x0a, 0x0c, 0x52, 0x4f, 0x4f, 0x4d, 0x5f, 0x43, 0x52, 0x45, + 0x41, 0x54, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0e, 0x0a, 0x0a, 0x52, 0x4f, 0x4f, 0x4d, 0x5f, 0x45, + 0x4e, 0x44, 0x45, 0x44, 0x10, 0x01, 0x12, 0x16, 0x0a, 0x12, 0x50, 0x41, 0x52, 0x54, 0x49, 0x43, + 0x49, 0x50, 0x41, 0x4e, 0x54, 0x5f, 0x4a, 0x4f, 0x49, 0x4e, 0x45, 0x44, 0x10, 0x02, 0x12, 0x14, + 0x0a, 0x10, 0x50, 0x41, 0x52, 0x54, 0x49, 0x43, 0x49, 0x50, 0x41, 0x4e, 0x54, 0x5f, 0x4c, 0x45, + 0x46, 0x54, 0x10, 0x03, 0x12, 0x13, 0x0a, 0x0f, 0x54, 0x52, 0x41, 0x43, 0x4b, 0x5f, 0x50, 0x55, + 0x42, 0x4c, 0x49, 0x53, 0x48, 0x45, 0x44, 0x10, 0x04, 0x12, 0x1b, 0x0a, 0x17, 0x54, 0x52, 0x41, + 0x43, 0x4b, 0x5f, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x53, 0x48, 0x5f, 0x52, 0x45, 0x51, 0x55, 0x45, + 0x53, 0x54, 0x45, 0x44, 0x10, 0x14, 0x12, 0x15, 0x0a, 0x11, 0x54, 0x52, 0x41, 0x43, 0x4b, 0x5f, + 0x55, 0x4e, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x53, 0x48, 0x45, 0x44, 0x10, 0x05, 0x12, 0x14, 0x0a, + 0x10, 0x54, 0x52, 0x41, 0x43, 0x4b, 0x5f, 0x53, 0x55, 0x42, 0x53, 0x43, 0x52, 0x49, 0x42, 0x45, + 0x44, 0x10, 0x06, 0x12, 0x1d, 0x0a, 0x19, 0x54, 0x52, 0x41, 0x43, 0x4b, 0x5f, 0x53, 0x55, 0x42, + 0x53, 0x43, 0x52, 0x49, 0x42, 0x45, 0x5f, 0x52, 0x45, 0x51, 0x55, 0x45, 0x53, 0x54, 0x45, 0x44, + 0x10, 0x15, 0x12, 0x1a, 0x0a, 0x16, 0x54, 0x52, 0x41, 0x43, 0x4b, 0x5f, 0x53, 0x55, 0x42, 0x53, + 0x43, 0x52, 0x49, 0x42, 0x45, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x10, 0x19, 0x12, 0x16, + 0x0a, 0x12, 0x54, 0x52, 0x41, 0x43, 0x4b, 0x5f, 0x55, 0x4e, 0x53, 0x55, 0x42, 0x53, 0x43, 0x52, + 0x49, 0x42, 0x45, 0x44, 0x10, 0x07, 0x12, 0x1a, 0x0a, 0x16, 0x54, 0x52, 0x41, 0x43, 0x4b, 0x5f, + 0x50, 0x55, 0x42, 0x4c, 0x49, 0x53, 0x48, 0x45, 0x44, 0x5f, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, + 0x10, 0x0a, 0x12, 0x0f, 0x0a, 0x0b, 0x54, 0x52, 0x41, 0x43, 0x4b, 0x5f, 0x4d, 0x55, 0x54, 0x45, + 0x44, 0x10, 0x17, 0x12, 0x11, 0x0a, 0x0d, 0x54, 0x52, 0x41, 0x43, 0x4b, 0x5f, 0x55, 0x4e, 0x4d, + 0x55, 0x54, 0x45, 0x44, 0x10, 0x18, 0x12, 0x17, 0x0a, 0x13, 0x54, 0x52, 0x41, 0x43, 0x4b, 0x5f, + 0x50, 0x55, 0x42, 0x4c, 0x49, 0x53, 0x48, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x53, 0x10, 0x1a, 0x12, + 0x19, 0x0a, 0x15, 0x54, 0x52, 0x41, 0x43, 0x4b, 0x5f, 0x53, 0x55, 0x42, 0x53, 0x43, 0x52, 0x49, + 0x42, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x53, 0x10, 0x1b, 0x12, 0x16, 0x0a, 0x12, 0x50, 0x41, + 0x52, 0x54, 0x49, 0x43, 0x49, 0x50, 0x41, 0x4e, 0x54, 0x5f, 0x41, 0x43, 0x54, 0x49, 0x56, 0x45, + 0x10, 0x0b, 0x12, 0x17, 0x0a, 0x13, 0x50, 0x41, 0x52, 0x54, 0x49, 0x43, 0x49, 0x50, 0x41, 0x4e, + 0x54, 0x5f, 0x52, 0x45, 0x53, 0x55, 0x4d, 0x45, 0x44, 0x10, 0x16, 0x12, 0x12, 0x0a, 0x0e, 0x45, + 0x47, 0x52, 0x45, 0x53, 0x53, 0x5f, 0x53, 0x54, 0x41, 0x52, 0x54, 0x45, 0x44, 0x10, 0x0c, 0x12, + 0x10, 0x0a, 0x0c, 0x45, 0x47, 0x52, 0x45, 0x53, 0x53, 0x5f, 0x45, 0x4e, 0x44, 0x45, 0x44, 0x10, + 0x0d, 0x12, 0x12, 0x0a, 0x0e, 0x45, 0x47, 0x52, 0x45, 0x53, 0x53, 0x5f, 0x55, 0x50, 0x44, 0x41, + 0x54, 0x45, 0x44, 0x10, 0x1c, 0x12, 0x26, 0x0a, 0x22, 0x54, 0x52, 0x41, 0x43, 0x4b, 0x5f, 0x4d, + 0x41, 0x58, 0x5f, 0x53, 0x55, 0x42, 0x53, 0x43, 0x52, 0x49, 0x42, 0x45, 0x44, 0x5f, 0x56, 0x49, + 0x44, 0x45, 0x4f, 0x5f, 0x51, 0x55, 0x41, 0x4c, 0x49, 0x54, 0x59, 0x10, 0x0e, 0x12, 0x0f, 0x0a, + 0x0b, 0x52, 0x45, 0x43, 0x4f, 0x4e, 0x4e, 0x45, 0x43, 0x54, 0x45, 0x44, 0x10, 0x0f, 0x12, 0x13, + 0x0a, 0x0f, 0x49, 0x4e, 0x47, 0x52, 0x45, 0x53, 0x53, 0x5f, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, + 0x44, 0x10, 0x12, 0x12, 0x13, 0x0a, 0x0f, 0x49, 0x4e, 0x47, 0x52, 0x45, 0x53, 0x53, 0x5f, 0x44, + 0x45, 0x4c, 0x45, 0x54, 0x45, 0x44, 0x10, 0x13, 0x12, 0x13, 0x0a, 0x0f, 0x49, 0x4e, 0x47, 0x52, + 0x45, 0x53, 0x53, 0x5f, 0x53, 0x54, 0x41, 0x52, 0x54, 0x45, 0x44, 0x10, 0x10, 0x12, 0x11, 0x0a, + 0x0d, 0x49, 0x4e, 0x47, 0x52, 0x45, 0x53, 0x53, 0x5f, 0x45, 0x4e, 0x44, 0x45, 0x44, 0x10, 0x11, + 0x12, 0x13, 0x0a, 0x0f, 0x49, 0x4e, 0x47, 0x52, 0x45, 0x53, 0x53, 0x5f, 0x55, 0x50, 0x44, 0x41, + 0x54, 0x45, 0x44, 0x10, 0x1d, 0x12, 0x1d, 0x0a, 0x19, 0x53, 0x49, 0x50, 0x5f, 0x49, 0x4e, 0x42, + 0x4f, 0x55, 0x4e, 0x44, 0x5f, 0x54, 0x52, 0x55, 0x4e, 0x4b, 0x5f, 0x43, 0x52, 0x45, 0x41, 0x54, + 0x45, 0x44, 0x10, 0x1e, 0x12, 0x1d, 0x0a, 0x19, 0x53, 0x49, 0x50, 0x5f, 0x49, 0x4e, 0x42, 0x4f, + 0x55, 0x4e, 0x44, 0x5f, 0x54, 0x52, 0x55, 0x4e, 0x4b, 0x5f, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, + 0x44, 0x10, 0x1f, 0x12, 0x1e, 0x0a, 0x1a, 0x53, 0x49, 0x50, 0x5f, 0x4f, 0x55, 0x54, 0x42, 0x4f, 0x55, 0x4e, 0x44, 0x5f, 0x54, 0x52, 0x55, 0x4e, 0x4b, 0x5f, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, - 0x44, 0x10, 0x1e, 0x12, 0x1d, 0x0a, 0x19, 0x53, 0x49, 0x50, 0x5f, 0x49, 0x4e, 0x42, 0x4f, 0x55, - 0x4e, 0x44, 0x5f, 0x54, 0x52, 0x55, 0x4e, 0x4b, 0x5f, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x44, - 0x10, 0x1f, 0x12, 0x1e, 0x0a, 0x1a, 0x53, 0x49, 0x50, 0x5f, 0x4f, 0x55, 0x54, 0x42, 0x4f, 0x55, - 0x4e, 0x44, 0x5f, 0x54, 0x52, 0x55, 0x4e, 0x4b, 0x5f, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x44, - 0x10, 0x20, 0x12, 0x1e, 0x0a, 0x1a, 0x53, 0x49, 0x50, 0x5f, 0x4f, 0x55, 0x54, 0x42, 0x4f, 0x55, - 0x4e, 0x44, 0x5f, 0x54, 0x52, 0x55, 0x4e, 0x4b, 0x5f, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x44, - 0x10, 0x21, 0x12, 0x1d, 0x0a, 0x19, 0x53, 0x49, 0x50, 0x5f, 0x44, 0x49, 0x53, 0x50, 0x41, 0x54, - 0x43, 0x48, 0x5f, 0x52, 0x55, 0x4c, 0x45, 0x5f, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x44, 0x10, - 0x22, 0x12, 0x1d, 0x0a, 0x19, 0x53, 0x49, 0x50, 0x5f, 0x44, 0x49, 0x53, 0x50, 0x41, 0x54, 0x43, - 0x48, 0x5f, 0x52, 0x55, 0x4c, 0x45, 0x5f, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x44, 0x10, 0x23, - 0x12, 0x1b, 0x0a, 0x17, 0x53, 0x49, 0x50, 0x5f, 0x50, 0x41, 0x52, 0x54, 0x49, 0x43, 0x49, 0x50, - 0x41, 0x4e, 0x54, 0x5f, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x44, 0x10, 0x24, 0x12, 0x15, 0x0a, - 0x11, 0x53, 0x49, 0x50, 0x5f, 0x43, 0x41, 0x4c, 0x4c, 0x5f, 0x49, 0x4e, 0x43, 0x4f, 0x4d, 0x49, - 0x4e, 0x47, 0x10, 0x25, 0x12, 0x14, 0x0a, 0x10, 0x53, 0x49, 0x50, 0x5f, 0x43, 0x41, 0x4c, 0x4c, - 0x5f, 0x53, 0x54, 0x41, 0x52, 0x54, 0x45, 0x44, 0x10, 0x26, 0x12, 0x12, 0x0a, 0x0e, 0x53, 0x49, - 0x50, 0x5f, 0x43, 0x41, 0x4c, 0x4c, 0x5f, 0x45, 0x4e, 0x44, 0x45, 0x44, 0x10, 0x27, 0x12, 0x0a, - 0x0a, 0x06, 0x52, 0x45, 0x50, 0x4f, 0x52, 0x54, 0x10, 0x28, 0x12, 0x0c, 0x0a, 0x08, 0x41, 0x50, - 0x49, 0x5f, 0x43, 0x41, 0x4c, 0x4c, 0x10, 0x29, 0x42, 0x46, 0x5a, 0x23, 0x67, 0x69, 0x74, 0x68, - 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x2f, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0xaa, - 0x02, 0x0d, 0x4c, 0x69, 0x76, 0x65, 0x4b, 0x69, 0x74, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0xea, - 0x02, 0x0e, 0x4c, 0x69, 0x76, 0x65, 0x4b, 0x69, 0x74, 0x3a, 0x3a, 0x50, 0x72, 0x6f, 0x74, 0x6f, - 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x44, 0x10, 0x20, 0x12, 0x1e, 0x0a, 0x1a, 0x53, 0x49, 0x50, 0x5f, 0x4f, 0x55, 0x54, 0x42, 0x4f, + 0x55, 0x4e, 0x44, 0x5f, 0x54, 0x52, 0x55, 0x4e, 0x4b, 0x5f, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, + 0x44, 0x10, 0x21, 0x12, 0x1d, 0x0a, 0x19, 0x53, 0x49, 0x50, 0x5f, 0x44, 0x49, 0x53, 0x50, 0x41, + 0x54, 0x43, 0x48, 0x5f, 0x52, 0x55, 0x4c, 0x45, 0x5f, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x44, + 0x10, 0x22, 0x12, 0x1d, 0x0a, 0x19, 0x53, 0x49, 0x50, 0x5f, 0x44, 0x49, 0x53, 0x50, 0x41, 0x54, + 0x43, 0x48, 0x5f, 0x52, 0x55, 0x4c, 0x45, 0x5f, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x44, 0x10, + 0x23, 0x12, 0x1b, 0x0a, 0x17, 0x53, 0x49, 0x50, 0x5f, 0x50, 0x41, 0x52, 0x54, 0x49, 0x43, 0x49, + 0x50, 0x41, 0x4e, 0x54, 0x5f, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x44, 0x10, 0x24, 0x12, 0x15, + 0x0a, 0x11, 0x53, 0x49, 0x50, 0x5f, 0x43, 0x41, 0x4c, 0x4c, 0x5f, 0x49, 0x4e, 0x43, 0x4f, 0x4d, + 0x49, 0x4e, 0x47, 0x10, 0x25, 0x12, 0x14, 0x0a, 0x10, 0x53, 0x49, 0x50, 0x5f, 0x43, 0x41, 0x4c, + 0x4c, 0x5f, 0x53, 0x54, 0x41, 0x52, 0x54, 0x45, 0x44, 0x10, 0x26, 0x12, 0x12, 0x0a, 0x0e, 0x53, + 0x49, 0x50, 0x5f, 0x43, 0x41, 0x4c, 0x4c, 0x5f, 0x45, 0x4e, 0x44, 0x45, 0x44, 0x10, 0x27, 0x12, + 0x0a, 0x0a, 0x06, 0x52, 0x45, 0x50, 0x4f, 0x52, 0x54, 0x10, 0x28, 0x12, 0x0c, 0x0a, 0x08, 0x41, + 0x50, 0x49, 0x5f, 0x43, 0x41, 0x4c, 0x4c, 0x10, 0x29, 0x12, 0x0b, 0x0a, 0x07, 0x57, 0x45, 0x42, + 0x48, 0x4f, 0x4f, 0x4b, 0x10, 0x2a, 0x42, 0x46, 0x5a, 0x23, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x2f, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0xaa, 0x02, 0x0d, + 0x4c, 0x69, 0x76, 0x65, 0x4b, 0x69, 0x74, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0xea, 0x02, 0x0e, + 0x4c, 0x69, 0x76, 0x65, 0x4b, 0x69, 0x74, 0x3a, 0x3a, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, }) var ( @@ -2452,7 +2730,7 @@ func file_livekit_analytics_proto_rawDescGZIP() []byte { } var file_livekit_analytics_proto_enumTypes = make([]protoimpl.EnumInfo, 3) -var file_livekit_analytics_proto_msgTypes = make([]protoimpl.MessageInfo, 15) +var file_livekit_analytics_proto_msgTypes = make([]protoimpl.MessageInfo, 16) var file_livekit_analytics_proto_goTypes = []any{ (StreamType)(0), // 0: livekit.StreamType (AnalyticsEventType)(0), // 1: livekit.AnalyticsEventType @@ -2472,88 +2750,93 @@ var file_livekit_analytics_proto_goTypes = []any{ (*FeatureUsageInfo)(nil), // 15: livekit.FeatureUsageInfo (*APICallRequest)(nil), // 16: livekit.APICallRequest (*APICallInfo)(nil), // 17: livekit.APICallInfo - (*timestamppb.Timestamp)(nil), // 18: google.protobuf.Timestamp - (ReconnectReason)(0), // 19: livekit.ReconnectReason - (*Room)(nil), // 20: livekit.Room - (*ParticipantInfo)(nil), // 21: livekit.ParticipantInfo - (*TrackInfo)(nil), // 22: livekit.TrackInfo - (*ClientInfo)(nil), // 23: livekit.ClientInfo - (VideoQuality)(0), // 24: livekit.VideoQuality - (*EgressInfo)(nil), // 25: livekit.EgressInfo - (*IngressInfo)(nil), // 26: livekit.IngressInfo - (*RTPStats)(nil), // 27: livekit.RTPStats - (*SIPCallInfo)(nil), // 28: livekit.SIPCallInfo - (*SIPInboundTrunkInfo)(nil), // 29: livekit.SIPInboundTrunkInfo - (*SIPOutboundTrunkInfo)(nil), // 30: livekit.SIPOutboundTrunkInfo - (*SIPDispatchRuleInfo)(nil), // 31: livekit.SIPDispatchRuleInfo - (ParticipantInfo_State)(0), // 32: livekit.ParticipantInfo.State - (*CreateRoomRequest)(nil), // 33: livekit.CreateRoomRequest - (*ListRoomsRequest)(nil), // 34: livekit.ListRoomsRequest - (*DeleteRoomRequest)(nil), // 35: livekit.DeleteRoomRequest - (*ListParticipantsRequest)(nil), // 36: livekit.ListParticipantsRequest - (*RoomParticipantIdentity)(nil), // 37: livekit.RoomParticipantIdentity - (*MuteRoomTrackRequest)(nil), // 38: livekit.MuteRoomTrackRequest - (*UpdateParticipantRequest)(nil), // 39: livekit.UpdateParticipantRequest - (*UpdateSubscriptionsRequest)(nil), // 40: livekit.UpdateSubscriptionsRequest - (*SendDataRequest)(nil), // 41: livekit.SendDataRequest - (*UpdateRoomMetadataRequest)(nil), // 42: livekit.UpdateRoomMetadataRequest + (*WebhookInfo)(nil), // 18: livekit.WebhookInfo + (*timestamppb.Timestamp)(nil), // 19: google.protobuf.Timestamp + (ReconnectReason)(0), // 20: livekit.ReconnectReason + (*Room)(nil), // 21: livekit.Room + (*ParticipantInfo)(nil), // 22: livekit.ParticipantInfo + (*TrackInfo)(nil), // 23: livekit.TrackInfo + (*ClientInfo)(nil), // 24: livekit.ClientInfo + (VideoQuality)(0), // 25: livekit.VideoQuality + (*EgressInfo)(nil), // 26: livekit.EgressInfo + (*IngressInfo)(nil), // 27: livekit.IngressInfo + (*RTPStats)(nil), // 28: livekit.RTPStats + (*SIPCallInfo)(nil), // 29: livekit.SIPCallInfo + (*SIPInboundTrunkInfo)(nil), // 30: livekit.SIPInboundTrunkInfo + (*SIPOutboundTrunkInfo)(nil), // 31: livekit.SIPOutboundTrunkInfo + (*SIPDispatchRuleInfo)(nil), // 32: livekit.SIPDispatchRuleInfo + (ParticipantInfo_State)(0), // 33: livekit.ParticipantInfo.State + (*CreateRoomRequest)(nil), // 34: livekit.CreateRoomRequest + (*ListRoomsRequest)(nil), // 35: livekit.ListRoomsRequest + (*DeleteRoomRequest)(nil), // 36: livekit.DeleteRoomRequest + (*ListParticipantsRequest)(nil), // 37: livekit.ListParticipantsRequest + (*RoomParticipantIdentity)(nil), // 38: livekit.RoomParticipantIdentity + (*MuteRoomTrackRequest)(nil), // 39: livekit.MuteRoomTrackRequest + (*UpdateParticipantRequest)(nil), // 40: livekit.UpdateParticipantRequest + (*UpdateSubscriptionsRequest)(nil), // 41: livekit.UpdateSubscriptionsRequest + (*SendDataRequest)(nil), // 42: livekit.SendDataRequest + (*UpdateRoomMetadataRequest)(nil), // 43: livekit.UpdateRoomMetadataRequest } var file_livekit_analytics_proto_depIdxs = []int32{ 3, // 0: livekit.AnalyticsStream.video_layers:type_name -> livekit.AnalyticsVideoLayer - 18, // 1: livekit.AnalyticsStream.start_time:type_name -> google.protobuf.Timestamp - 18, // 2: livekit.AnalyticsStream.end_time:type_name -> google.protobuf.Timestamp + 19, // 1: livekit.AnalyticsStream.start_time:type_name -> google.protobuf.Timestamp + 19, // 2: livekit.AnalyticsStream.end_time:type_name -> google.protobuf.Timestamp 0, // 3: livekit.AnalyticsStat.kind:type_name -> livekit.StreamType - 18, // 4: livekit.AnalyticsStat.time_stamp:type_name -> google.protobuf.Timestamp + 19, // 4: livekit.AnalyticsStat.time_stamp:type_name -> google.protobuf.Timestamp 4, // 5: livekit.AnalyticsStat.streams:type_name -> livekit.AnalyticsStream 5, // 6: livekit.AnalyticsStats.stats:type_name -> livekit.AnalyticsStat - 19, // 7: livekit.AnalyticsClientMeta.reconnect_reason:type_name -> livekit.ReconnectReason + 20, // 7: livekit.AnalyticsClientMeta.reconnect_reason:type_name -> livekit.ReconnectReason 1, // 8: livekit.AnalyticsEvent.type:type_name -> livekit.AnalyticsEventType - 18, // 9: livekit.AnalyticsEvent.timestamp:type_name -> google.protobuf.Timestamp - 20, // 10: livekit.AnalyticsEvent.room:type_name -> livekit.Room - 21, // 11: livekit.AnalyticsEvent.participant:type_name -> livekit.ParticipantInfo - 22, // 12: livekit.AnalyticsEvent.track:type_name -> livekit.TrackInfo - 23, // 13: livekit.AnalyticsEvent.client_info:type_name -> livekit.ClientInfo + 19, // 9: livekit.AnalyticsEvent.timestamp:type_name -> google.protobuf.Timestamp + 21, // 10: livekit.AnalyticsEvent.room:type_name -> livekit.Room + 22, // 11: livekit.AnalyticsEvent.participant:type_name -> livekit.ParticipantInfo + 23, // 12: livekit.AnalyticsEvent.track:type_name -> livekit.TrackInfo + 24, // 13: livekit.AnalyticsEvent.client_info:type_name -> livekit.ClientInfo 7, // 14: livekit.AnalyticsEvent.client_meta:type_name -> livekit.AnalyticsClientMeta - 24, // 15: livekit.AnalyticsEvent.max_subscribed_video_quality:type_name -> livekit.VideoQuality - 21, // 16: livekit.AnalyticsEvent.publisher:type_name -> livekit.ParticipantInfo - 25, // 17: livekit.AnalyticsEvent.egress:type_name -> livekit.EgressInfo - 26, // 18: livekit.AnalyticsEvent.ingress:type_name -> livekit.IngressInfo - 27, // 19: livekit.AnalyticsEvent.rtp_stats:type_name -> livekit.RTPStats - 28, // 20: livekit.AnalyticsEvent.sip_call:type_name -> livekit.SIPCallInfo - 29, // 21: livekit.AnalyticsEvent.sip_inbound_trunk:type_name -> livekit.SIPInboundTrunkInfo - 30, // 22: livekit.AnalyticsEvent.sip_outbound_trunk:type_name -> livekit.SIPOutboundTrunkInfo - 31, // 23: livekit.AnalyticsEvent.sip_dispatch_rule:type_name -> livekit.SIPDispatchRuleInfo + 25, // 15: livekit.AnalyticsEvent.max_subscribed_video_quality:type_name -> livekit.VideoQuality + 22, // 16: livekit.AnalyticsEvent.publisher:type_name -> livekit.ParticipantInfo + 26, // 17: livekit.AnalyticsEvent.egress:type_name -> livekit.EgressInfo + 27, // 18: livekit.AnalyticsEvent.ingress:type_name -> livekit.IngressInfo + 28, // 19: livekit.AnalyticsEvent.rtp_stats:type_name -> livekit.RTPStats + 29, // 20: livekit.AnalyticsEvent.sip_call:type_name -> livekit.SIPCallInfo + 30, // 21: livekit.AnalyticsEvent.sip_inbound_trunk:type_name -> livekit.SIPInboundTrunkInfo + 31, // 22: livekit.AnalyticsEvent.sip_outbound_trunk:type_name -> livekit.SIPOutboundTrunkInfo + 32, // 23: livekit.AnalyticsEvent.sip_dispatch_rule:type_name -> livekit.SIPDispatchRuleInfo 13, // 24: livekit.AnalyticsEvent.report:type_name -> livekit.ReportInfo 17, // 25: livekit.AnalyticsEvent.api_call:type_name -> livekit.APICallInfo - 8, // 26: livekit.AnalyticsEvents.events:type_name -> livekit.AnalyticsEvent - 32, // 27: livekit.AnalyticsRoomParticipant.state:type_name -> livekit.ParticipantInfo.State - 18, // 28: livekit.AnalyticsRoomParticipant.joined_at:type_name -> google.protobuf.Timestamp - 18, // 29: livekit.AnalyticsRoom.created_at:type_name -> google.protobuf.Timestamp - 10, // 30: livekit.AnalyticsRoom.participants:type_name -> livekit.AnalyticsRoomParticipant - 18, // 31: livekit.AnalyticsNodeRooms.timestamp:type_name -> google.protobuf.Timestamp - 11, // 32: livekit.AnalyticsNodeRooms.rooms:type_name -> livekit.AnalyticsRoom - 15, // 33: livekit.ReportInfo.feature_usage:type_name -> livekit.FeatureUsageInfo - 18, // 34: livekit.TimeRange.started_at:type_name -> google.protobuf.Timestamp - 18, // 35: livekit.TimeRange.ended_at:type_name -> google.protobuf.Timestamp - 2, // 36: livekit.FeatureUsageInfo.feature:type_name -> livekit.FeatureUsageInfo.Feature - 14, // 37: livekit.FeatureUsageInfo.time_ranges:type_name -> livekit.TimeRange - 33, // 38: livekit.APICallRequest.create_room_request:type_name -> livekit.CreateRoomRequest - 34, // 39: livekit.APICallRequest.list_rooms_request:type_name -> livekit.ListRoomsRequest - 35, // 40: livekit.APICallRequest.delete_room_request:type_name -> livekit.DeleteRoomRequest - 36, // 41: livekit.APICallRequest.list_participants_request:type_name -> livekit.ListParticipantsRequest - 37, // 42: livekit.APICallRequest.room_participant_identity:type_name -> livekit.RoomParticipantIdentity - 38, // 43: livekit.APICallRequest.mute_room_track_request:type_name -> livekit.MuteRoomTrackRequest - 39, // 44: livekit.APICallRequest.update_participant_request:type_name -> livekit.UpdateParticipantRequest - 40, // 45: livekit.APICallRequest.update_subscriptions_request:type_name -> livekit.UpdateSubscriptionsRequest - 41, // 46: livekit.APICallRequest.send_data_request:type_name -> livekit.SendDataRequest - 42, // 47: livekit.APICallRequest.update_room_metadata_request:type_name -> livekit.UpdateRoomMetadataRequest - 16, // 48: livekit.APICallInfo.request:type_name -> livekit.APICallRequest - 18, // 49: livekit.APICallInfo.started_at:type_name -> google.protobuf.Timestamp - 50, // [50:50] is the sub-list for method output_type - 50, // [50:50] is the sub-list for method input_type - 50, // [50:50] is the sub-list for extension type_name - 50, // [50:50] is the sub-list for extension extendee - 0, // [0:50] is the sub-list for field type_name + 18, // 26: livekit.AnalyticsEvent.webhook:type_name -> livekit.WebhookInfo + 8, // 27: livekit.AnalyticsEvents.events:type_name -> livekit.AnalyticsEvent + 33, // 28: livekit.AnalyticsRoomParticipant.state:type_name -> livekit.ParticipantInfo.State + 19, // 29: livekit.AnalyticsRoomParticipant.joined_at:type_name -> google.protobuf.Timestamp + 19, // 30: livekit.AnalyticsRoom.created_at:type_name -> google.protobuf.Timestamp + 10, // 31: livekit.AnalyticsRoom.participants:type_name -> livekit.AnalyticsRoomParticipant + 19, // 32: livekit.AnalyticsNodeRooms.timestamp:type_name -> google.protobuf.Timestamp + 11, // 33: livekit.AnalyticsNodeRooms.rooms:type_name -> livekit.AnalyticsRoom + 15, // 34: livekit.ReportInfo.feature_usage:type_name -> livekit.FeatureUsageInfo + 19, // 35: livekit.TimeRange.started_at:type_name -> google.protobuf.Timestamp + 19, // 36: livekit.TimeRange.ended_at:type_name -> google.protobuf.Timestamp + 2, // 37: livekit.FeatureUsageInfo.feature:type_name -> livekit.FeatureUsageInfo.Feature + 14, // 38: livekit.FeatureUsageInfo.time_ranges:type_name -> livekit.TimeRange + 34, // 39: livekit.APICallRequest.create_room_request:type_name -> livekit.CreateRoomRequest + 35, // 40: livekit.APICallRequest.list_rooms_request:type_name -> livekit.ListRoomsRequest + 36, // 41: livekit.APICallRequest.delete_room_request:type_name -> livekit.DeleteRoomRequest + 37, // 42: livekit.APICallRequest.list_participants_request:type_name -> livekit.ListParticipantsRequest + 38, // 43: livekit.APICallRequest.room_participant_identity:type_name -> livekit.RoomParticipantIdentity + 39, // 44: livekit.APICallRequest.mute_room_track_request:type_name -> livekit.MuteRoomTrackRequest + 40, // 45: livekit.APICallRequest.update_participant_request:type_name -> livekit.UpdateParticipantRequest + 41, // 46: livekit.APICallRequest.update_subscriptions_request:type_name -> livekit.UpdateSubscriptionsRequest + 42, // 47: livekit.APICallRequest.send_data_request:type_name -> livekit.SendDataRequest + 43, // 48: livekit.APICallRequest.update_room_metadata_request:type_name -> livekit.UpdateRoomMetadataRequest + 16, // 49: livekit.APICallInfo.request:type_name -> livekit.APICallRequest + 19, // 50: livekit.APICallInfo.started_at:type_name -> google.protobuf.Timestamp + 19, // 51: livekit.WebhookInfo.created_at:type_name -> google.protobuf.Timestamp + 19, // 52: livekit.WebhookInfo.queued_at:type_name -> google.protobuf.Timestamp + 19, // 53: livekit.WebhookInfo.sent_at:type_name -> google.protobuf.Timestamp + 54, // [54:54] is the sub-list for method output_type + 54, // [54:54] is the sub-list for method input_type + 54, // [54:54] is the sub-list for extension type_name + 54, // [54:54] is the sub-list for extension extendee + 0, // [0:54] is the sub-list for field type_name } func init() { file_livekit_analytics_proto_init() } @@ -2588,7 +2871,7 @@ func file_livekit_analytics_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_livekit_analytics_proto_rawDesc), len(file_livekit_analytics_proto_rawDesc)), NumEnums: 3, - NumMessages: 15, + NumMessages: 16, NumExtensions: 0, NumServices: 0, }, diff --git a/protobufs/livekit_analytics.proto b/protobufs/livekit_analytics.proto index 39d1af248..8f33a1696 100644 --- a/protobufs/livekit_analytics.proto +++ b/protobufs/livekit_analytics.proto @@ -124,8 +124,9 @@ enum AnalyticsEventType { SIP_CALL_ENDED = 39; REPORT = 40; API_CALL = 41; + WEBHOOK = 42; - // NEXT_ID: 42 + // NEXT_ID: 43 } message AnalyticsClientMeta { @@ -175,8 +176,9 @@ message AnalyticsEvent { SIPDispatchRuleInfo sip_dispatch_rule = 32; ReportInfo report = 33; APICallInfo api_call = 34; + WebhookInfo webhook = 35; - // NEXT_ID: 35 + // NEXT_ID: 36 } message AnalyticsEvents { @@ -269,3 +271,28 @@ message APICallInfo { google.protobuf.Timestamp started_at = 14; int64 duration_ns = 15; } + +message WebhookInfo { + string event_id = 1; + string event = 2; + string project_id = 3; + string room_name = 4; + string room_id = 5; + string participant_identity = 6; + string participant_id = 7; + string track_id = 8; + string egress_id = 9; + string ingress_id = 10; + google.protobuf.Timestamp created_at = 11; + google.protobuf.Timestamp queued_at = 12; + int64 queue_duration_ns = 13; + google.protobuf.Timestamp sent_at = 14; + int64 send_duration_ns = 15; + string url = 16; + int32 num_dropped = 17; + bool is_dropped = 18; + string service_status = 19; + int32 service_error_code = 20; + string service_error = 21; + string send_error = 22; +} diff --git a/replay/cloud_replay.pb.go b/replay/cloud_replay.pb.go index 668043da9..d725274ae 100644 --- a/replay/cloud_replay.pb.go +++ b/replay/cloud_replay.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.31.0 -// protoc v4.25.3 +// protoc v4.24.3 // source: cloud_replay.proto package replay diff --git a/webhook/notifier.go b/webhook/notifier.go index da1a91de4..d260e72ca 100644 --- a/webhook/notifier.go +++ b/webhook/notifier.go @@ -23,6 +23,7 @@ import ( ) type QueuedNotifier interface { + RegisterProcessedHook(f func(ctx context.Context, whi *livekit.WebhookInfo)) QueueNotify(ctx context.Context, event *livekit.WebhookEvent) error } @@ -56,11 +57,17 @@ func (n *DefaultNotifier) Stop(force bool) { wg.Wait() } -func (n *DefaultNotifier) QueueNotify(_ context.Context, event *livekit.WebhookEvent) error { +func (n *DefaultNotifier) QueueNotify(ctx context.Context, event *livekit.WebhookEvent) error { for _, u := range n.urlNotifiers { - if err := u.QueueNotify(event); err != nil { + if err := u.QueueNotify(ctx, event); err != nil { return err } } return nil } + +func (n *DefaultNotifier) RegisterProcessedHook(hook func(ctx context.Context, whi *livekit.WebhookInfo)) { + for _, u := range n.urlNotifiers { + u.RegisterProcessedHook(hook) + } +} diff --git a/webhook/url_notifier.go b/webhook/url_notifier.go index 4afc235cb..5dfebeb3c 100644 --- a/webhook/url_notifier.go +++ b/webhook/url_notifier.go @@ -16,6 +16,7 @@ package webhook import ( "bytes" + "context" "crypto/sha256" "encoding/base64" "sync" @@ -25,6 +26,7 @@ import ( "github.com/hashicorp/go-retryablehttp" "go.uber.org/atomic" "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/types/known/timestamppb" "github.com/livekit/protocol/auth" "github.com/livekit/protocol/livekit" @@ -37,11 +39,12 @@ const ( type URLNotifierParams struct { HTTPClientParams - Logger logger.Logger - QueueSize int - URL string - APIKey string - APISecret string + Logger logger.Logger + QueueSize int + URL string + APIKey string + APISecret string + FieldsHook func(whi *livekit.WebhookInfo) } type HTTPClientParams struct { @@ -56,11 +59,12 @@ const defaultQueueSize = 100 // URLNotifier is a QueuedNotifier that sends a POST request to a Webhook URL. // It will retry on failure, and will drop events if notification fall too far behind type URLNotifier struct { - mu sync.RWMutex - params URLNotifierParams - client *retryablehttp.Client - dropped atomic.Int32 - pool core.QueuePool + mu sync.RWMutex + params URLNotifierParams + client *retryablehttp.Client + dropped atomic.Int32 + pool core.QueuePool + processedHook func(ctx context.Context, whi *livekit.WebhookInfo) } func NewURLNotifier(params URLNotifierParams) *URLNotifier { @@ -93,7 +97,6 @@ func NewURLNotifier(params URLNotifierParams) *URLNotifier { n.pool = core.NewQueuePool(numWorkers, core.QueueWorkerParams{ QueueSize: params.QueueSize, DropWhenFull: true, - OnDropped: func() { n.dropped.Inc() }, }) return n } @@ -105,25 +108,76 @@ func (n *URLNotifier) SetKeys(apiKey, apiSecret string) { n.params.APISecret = apiSecret } -func (n *URLNotifier) QueueNotify(event *livekit.WebhookEvent) error { +func (n *URLNotifier) RegisterProcessedHook(hook func(ctx context.Context, whi *livekit.WebhookInfo)) { + n.mu.Lock() + defer n.mu.Unlock() + n.processedHook = hook +} + +func (n *URLNotifier) getProcessedHook() func(ctx context.Context, whi *livekit.WebhookInfo) { + n.mu.RLock() + defer n.mu.RUnlock() + return n.processedHook +} + +func (n *URLNotifier) QueueNotify(ctx context.Context, event *livekit.WebhookEvent) error { enqueuedAt := time.Now() - n.pool.Submit(n.eventKey(event), func() { - fields := logFields(event) - fields = append(fields, - "url", n.params.URL, - "queueDuration", time.Since(enqueuedAt), - ) - sentStart := time.Now() + if !n.pool.Submit(n.eventKey(event), func() { + fields := logFields(event, n.params.URL) + + queueDuration := time.Since(enqueuedAt) + fields = append(fields, "queueDuration", queueDuration) + + sendStart := time.Now() err := n.send(event) - fields = append(fields, "sendDuration", time.Since(sentStart)) + sendDuration := time.Since(sendStart) + fields = append(fields, "sendDuration", sendDuration) if err != nil { n.params.Logger.Warnw("failed to send webhook", err, fields...) n.dropped.Add(event.NumDropped + 1) } else { n.params.Logger.Infow("sent webhook", fields...) } - }) + if ph := n.getProcessedHook(); ph != nil { + whi := webhookInfo( + event, + enqueuedAt, + queueDuration, + sendStart, + sendDuration, + n.params.URL, + false, + err, + ) + if n.params.FieldsHook != nil { + n.params.FieldsHook(whi) + } + ph(ctx, whi) + } + }) { + n.dropped.Inc() + + fields := logFields(event, n.params.URL) + n.params.Logger.Infow("dropped webhook", fields...) + + if ph := n.getProcessedHook(); ph != nil { + whi := webhookInfo( + event, + time.Time{}, + 0, + time.Time{}, + 0, + n.params.URL, + true, + nil, + ) + if n.params.FieldsHook != nil { + n.params.FieldsHook(whi) + } + ph(ctx, whi) + } + } return nil } @@ -197,12 +251,13 @@ type logAdapter struct{} func (l *logAdapter) Printf(string, ...interface{}) {} -func logFields(event *livekit.WebhookEvent) []interface{} { +func logFields(event *livekit.WebhookEvent, url string) []interface{} { fields := make([]interface{}, 0, 20) fields = append(fields, "event", event.Event, "id", event.Id, "webhookTime", event.CreatedAt, + "url", url, ) if event.Room != nil { @@ -217,6 +272,11 @@ func logFields(event *livekit.WebhookEvent) []interface{} { "pID", event.Participant.Sid, ) } + if event.Track != nil { + fields = append(fields, + "trackID", event.Track.Sid, + ) + } if event.EgressInfo != nil { fields = append(fields, "egressID", event.EgressInfo.EgressId, @@ -239,3 +299,65 @@ func logFields(event *livekit.WebhookEvent) []interface{} { } return fields } + +func webhookInfo( + event *livekit.WebhookEvent, + queuedAt time.Time, + queueDuration time.Duration, + sentAt time.Time, + sendDuration time.Duration, + url string, + isDropped bool, + sendError error, +) *livekit.WebhookInfo { + whi := &livekit.WebhookInfo{ + EventId: event.Id, + Event: event.Event, + CreatedAt: timestamppb.New(time.Unix(event.CreatedAt, 0)), + QueuedAt: timestamppb.New(queuedAt), + QueueDurationNs: queueDuration.Nanoseconds(), + SentAt: timestamppb.New(sentAt), + SendDurationNs: sendDuration.Nanoseconds(), + Url: url, + NumDropped: event.NumDropped, + IsDropped: isDropped, + } + if !queuedAt.IsZero() { + whi.QueuedAt = timestamppb.New(queuedAt) + } + if !sentAt.IsZero() { + whi.SentAt = timestamppb.New(sentAt) + } + if event.Room != nil { + whi.RoomName = event.Room.Name + whi.RoomId = event.Room.Sid + } + if event.Participant != nil { + whi.ParticipantIdentity = event.Participant.Identity + whi.ParticipantId = event.Participant.Sid + } + if event.Track != nil { + whi.TrackId = event.Track.Sid + } + if event.EgressInfo != nil { + whi.EgressId = event.EgressInfo.EgressId + whi.ServiceStatus = event.EgressInfo.Status.String() + if event.EgressInfo.Error != "" { + whi.ServiceErrorCode = event.EgressInfo.ErrorCode + whi.ServiceError = event.EgressInfo.Error + } + } + if event.IngressInfo != nil { + whi.IngressId = event.IngressInfo.IngressId + if event.IngressInfo.State != nil { + whi.ServiceStatus = event.IngressInfo.State.Status.String() + if event.IngressInfo.State.Error != "" { + whi.ServiceError = event.IngressInfo.State.Error + } + } + } + if sendError != nil { + whi.SendError = sendError.Error() + } + return whi +} diff --git a/webhook/webhook_test.go b/webhook/webhook_test.go index 42cb3f4ab..472a9f6ab 100644 --- a/webhook/webhook_test.go +++ b/webhook/webhook_test.go @@ -91,9 +91,9 @@ func TestURLNotifierDropped(t *testing.T) { } // send multiple notifications for i := 0; i < 10; i++ { - _ = urlNotifier.QueueNotify(&livekit.WebhookEvent{Event: EventRoomStarted}) - _ = urlNotifier.QueueNotify(&livekit.WebhookEvent{Event: EventParticipantJoined}) - _ = urlNotifier.QueueNotify(&livekit.WebhookEvent{Event: EventRoomFinished}) + _ = urlNotifier.QueueNotify(context.Background(), &livekit.WebhookEvent{Event: EventRoomStarted}) + _ = urlNotifier.QueueNotify(context.Background(), &livekit.WebhookEvent{Event: EventParticipantJoined}) + _ = urlNotifier.QueueNotify(context.Background(), &livekit.WebhookEvent{Event: EventRoomFinished}) } time.Sleep(webhookCheckInterval) @@ -120,8 +120,8 @@ func TestURLNotifierLifecycle(t *testing.T) { numCalled.Inc() } for i := 0; i < 10; i++ { - _ = urlNotifier.QueueNotify(&livekit.WebhookEvent{Event: EventRoomStarted}) - _ = urlNotifier.QueueNotify(&livekit.WebhookEvent{Event: EventRoomFinished}) + _ = urlNotifier.QueueNotify(context.Background(), &livekit.WebhookEvent{Event: EventRoomStarted}) + _ = urlNotifier.QueueNotify(context.Background(), &livekit.WebhookEvent{Event: EventRoomFinished}) } urlNotifier.Stop(false) require.Eventually(t, func() bool { return numCalled.Load() == 20 }, 5*time.Second, webhookCheckInterval) @@ -134,8 +134,8 @@ func TestURLNotifierLifecycle(t *testing.T) { numCalled.Inc() } for i := 0; i < 10; i++ { - _ = urlNotifier.QueueNotify(&livekit.WebhookEvent{Event: EventRoomStarted}) - _ = urlNotifier.QueueNotify(&livekit.WebhookEvent{Event: EventRoomFinished}) + _ = urlNotifier.QueueNotify(context.Background(), &livekit.WebhookEvent{Event: EventRoomStarted}) + _ = urlNotifier.QueueNotify(context.Background(), &livekit.WebhookEvent{Event: EventRoomFinished}) } urlNotifier.Stop(true) time.Sleep(time.Second)