From 7baf62b9d8be8f00627431ac70b570ada57d1ae5 Mon Sep 17 00:00:00 2001 From: Anunay Maheshwari Date: Mon, 13 Oct 2025 16:00:54 +0530 Subject: [PATCH] feat(connectors): initial impl (#1221) * feat(connectors): initial impl * cleanup * cleanup * fix: remove affinity func * add license headers * split connector proto files * generated protobuf * cleanup * add sdp helper to extract IP * generated protobuf --------- Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com> --- connector/errors.go | 25 + connector/token.go | 56 + livekit/livekit_connector.pb.go | 96 ++ livekit/livekit_connector.twirp.go | 1373 ++++++++++++++++++++ livekit/livekit_connector_whatsapp.pb.go | 825 ++++++++++++ livekit/livekit_models.pb.go | 21 +- magefile.go | 4 + protobufs/livekit_connector.proto | 32 + protobufs/livekit_connector_whatsapp.proto | 121 ++ protobufs/livekit_models.proto | 5 +- protobufs/rpc/common.proto | 25 + protobufs/rpc/connector.proto | 65 + rpc/common.pb.go | 155 +++ rpc/connector.pb.go | 231 ++++ rpc/connector.psrpc.go | 337 +++++ rpc/connector_client.go | 52 + sdp/sdp.go | 13 + 17 files changed, 3426 insertions(+), 10 deletions(-) create mode 100644 connector/errors.go create mode 100644 connector/token.go create mode 100644 livekit/livekit_connector.pb.go create mode 100644 livekit/livekit_connector.twirp.go create mode 100644 livekit/livekit_connector_whatsapp.pb.go create mode 100644 protobufs/livekit_connector.proto create mode 100644 protobufs/livekit_connector_whatsapp.proto create mode 100644 protobufs/rpc/common.proto create mode 100644 protobufs/rpc/connector.proto create mode 100644 rpc/common.pb.go create mode 100644 rpc/connector.pb.go create mode 100644 rpc/connector.psrpc.go create mode 100644 rpc/connector_client.go diff --git a/connector/errors.go b/connector/errors.go new file mode 100644 index 0000000..34156e9 --- /dev/null +++ b/connector/errors.go @@ -0,0 +1,25 @@ +// Copyright 2025 LiveKit, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package connector + +import "github.com/livekit/psrpc" + +var ( + ErrMissingWhatsAppPhoneNumberId = psrpc.NewErrorf(psrpc.InvalidArgument, "whatsapp phone number id is required") + ErrMissingWhatsAppToNumber = psrpc.NewErrorf(psrpc.InvalidArgument, "whatsapp to_phone_number is required") + ErrMissingWhatsAppCallId = psrpc.NewErrorf(psrpc.InvalidArgument, "whatsapp call id is required") + ErrMissingWhatsAppApiKey = psrpc.NewErrorf(psrpc.InvalidArgument, "whatsapp api key is required") + ErrIncorrectSDPType = psrpc.NewErrorf(psrpc.InvalidArgument, "incorrect sdp type") +) diff --git a/connector/token.go b/connector/token.go new file mode 100644 index 0000000..e7aa8dc --- /dev/null +++ b/connector/token.go @@ -0,0 +1,56 @@ +// Copyright 2025 LiveKit, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package connector + +import ( + "time" + + "github.com/livekit/protocol/auth" + "github.com/livekit/protocol/livekit" +) + +type ConnectorTokenParams struct { + APIKey string + APISecret string + RoomName string + ParticipantIdentity string + ParticipantName string + ParticipantMetadata string + ParticipantAttributes map[string]string + Agents []*livekit.RoomAgentDispatch +} + +func BuildConnectorToken(params ConnectorTokenParams) (string, error) { + t := true + at := auth.NewAccessToken(params.APIKey, params.APISecret). + SetVideoGrant(&auth.VideoGrant{ + RoomJoin: true, + Room: params.RoomName, + CanSubscribe: &t, + CanPublish: &t, + CanPublishData: &t, + CanUpdateOwnMetadata: &t, + }). + SetAgents(params.Agents...). + SetIdentity(params.ParticipantIdentity). + SetName(params.ParticipantName). + SetMetadata(params.ParticipantMetadata). + SetAttributes(params.ParticipantAttributes). + SetKind(livekit.ParticipantInfo_CONNECTOR). + SetValidFor(24 * time.Hour). + SetAllowSensitiveCredentials(true) + + return at.ToJWT() +} diff --git a/livekit/livekit_connector.pb.go b/livekit/livekit_connector.pb.go new file mode 100644 index 0000000..1c326bc --- /dev/null +++ b/livekit/livekit_connector.pb.go @@ -0,0 +1,96 @@ +// Copyright 2025 LiveKit, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.10 +// protoc v4.23.4 +// source: livekit_connector.proto + +package livekit + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +var File_livekit_connector_proto protoreflect.FileDescriptor + +const file_livekit_connector_proto_rawDesc = "" + + "\n" + + "\x17livekit_connector.proto\x12\alivekit\x1a livekit_connector_whatsapp.proto2\x90\x03\n" + + "\tConnector\x12W\n" + + "\x10DialWhatsAppCall\x12 .livekit.DialWhatsAppCallRequest\x1a!.livekit.DialWhatsAppCallResponse\x12i\n" + + "\x16DisconnectWhatsAppCall\x12&.livekit.DisconnectWhatsAppCallRequest\x1a'.livekit.DisconnectWhatsAppCallResponse\x12`\n" + + "\x13ConnectWhatsAppCall\x12#.livekit.ConnectWhatsAppCallRequest\x1a$.livekit.ConnectWhatsAppCallResponse\x12]\n" + + "\x12AcceptWhatsAppCall\x12\".livekit.AcceptWhatsAppCallRequest\x1a#.livekit.AcceptWhatsAppCallResponseBFZ#github.com/livekit/protocol/livekit\xaa\x02\rLiveKit.Proto\xea\x02\x0eLiveKit::Protob\x06proto3" + +var file_livekit_connector_proto_goTypes = []any{ + (*DialWhatsAppCallRequest)(nil), // 0: livekit.DialWhatsAppCallRequest + (*DisconnectWhatsAppCallRequest)(nil), // 1: livekit.DisconnectWhatsAppCallRequest + (*ConnectWhatsAppCallRequest)(nil), // 2: livekit.ConnectWhatsAppCallRequest + (*AcceptWhatsAppCallRequest)(nil), // 3: livekit.AcceptWhatsAppCallRequest + (*DialWhatsAppCallResponse)(nil), // 4: livekit.DialWhatsAppCallResponse + (*DisconnectWhatsAppCallResponse)(nil), // 5: livekit.DisconnectWhatsAppCallResponse + (*ConnectWhatsAppCallResponse)(nil), // 6: livekit.ConnectWhatsAppCallResponse + (*AcceptWhatsAppCallResponse)(nil), // 7: livekit.AcceptWhatsAppCallResponse +} +var file_livekit_connector_proto_depIdxs = []int32{ + 0, // 0: livekit.Connector.DialWhatsAppCall:input_type -> livekit.DialWhatsAppCallRequest + 1, // 1: livekit.Connector.DisconnectWhatsAppCall:input_type -> livekit.DisconnectWhatsAppCallRequest + 2, // 2: livekit.Connector.ConnectWhatsAppCall:input_type -> livekit.ConnectWhatsAppCallRequest + 3, // 3: livekit.Connector.AcceptWhatsAppCall:input_type -> livekit.AcceptWhatsAppCallRequest + 4, // 4: livekit.Connector.DialWhatsAppCall:output_type -> livekit.DialWhatsAppCallResponse + 5, // 5: livekit.Connector.DisconnectWhatsAppCall:output_type -> livekit.DisconnectWhatsAppCallResponse + 6, // 6: livekit.Connector.ConnectWhatsAppCall:output_type -> livekit.ConnectWhatsAppCallResponse + 7, // 7: livekit.Connector.AcceptWhatsAppCall:output_type -> livekit.AcceptWhatsAppCallResponse + 4, // [4:8] is the sub-list for method output_type + 0, // [0:4] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name +} + +func init() { file_livekit_connector_proto_init() } +func file_livekit_connector_proto_init() { + if File_livekit_connector_proto != nil { + return + } + file_livekit_connector_whatsapp_proto_init() + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_livekit_connector_proto_rawDesc), len(file_livekit_connector_proto_rawDesc)), + NumEnums: 0, + NumMessages: 0, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_livekit_connector_proto_goTypes, + DependencyIndexes: file_livekit_connector_proto_depIdxs, + }.Build() + File_livekit_connector_proto = out.File + file_livekit_connector_proto_goTypes = nil + file_livekit_connector_proto_depIdxs = nil +} diff --git a/livekit/livekit_connector.twirp.go b/livekit/livekit_connector.twirp.go new file mode 100644 index 0000000..37276ff --- /dev/null +++ b/livekit/livekit_connector.twirp.go @@ -0,0 +1,1373 @@ +// Code generated by protoc-gen-twirp v8.1.3, DO NOT EDIT. +// source: livekit_connector.proto + +package livekit + +import context "context" +import fmt "fmt" +import http "net/http" +import io "io" +import json "encoding/json" +import strconv "strconv" +import strings "strings" + +import protojson "google.golang.org/protobuf/encoding/protojson" +import proto "google.golang.org/protobuf/proto" +import twirp "github.com/twitchtv/twirp" +import ctxsetters "github.com/twitchtv/twirp/ctxsetters" + +// Version compatibility assertion. +// If the constant is not defined in the package, that likely means +// the package needs to be updated to work with this generated code. +// See https://twitchtv.github.io/twirp/docs/version_matrix.html +const _ = twirp.TwirpPackageMinVersion_8_1_0 + +// =================== +// Connector Interface +// =================== + +type Connector interface { + DialWhatsAppCall(context.Context, *DialWhatsAppCallRequest) (*DialWhatsAppCallResponse, error) + + DisconnectWhatsAppCall(context.Context, *DisconnectWhatsAppCallRequest) (*DisconnectWhatsAppCallResponse, error) + + ConnectWhatsAppCall(context.Context, *ConnectWhatsAppCallRequest) (*ConnectWhatsAppCallResponse, error) + + AcceptWhatsAppCall(context.Context, *AcceptWhatsAppCallRequest) (*AcceptWhatsAppCallResponse, error) +} + +// ========================= +// Connector Protobuf Client +// ========================= + +type connectorProtobufClient struct { + client HTTPClient + urls [4]string + interceptor twirp.Interceptor + opts twirp.ClientOptions +} + +// NewConnectorProtobufClient creates a Protobuf client that implements the Connector interface. +// It communicates using Protobuf and can be configured with a custom HTTPClient. +func NewConnectorProtobufClient(baseURL string, client HTTPClient, opts ...twirp.ClientOption) Connector { + if c, ok := client.(*http.Client); ok { + client = withoutRedirects(c) + } + + clientOpts := twirp.ClientOptions{} + for _, o := range opts { + o(&clientOpts) + } + + // Using ReadOpt allows backwards and forwards compatibility with new options in the future + literalURLs := false + _ = clientOpts.ReadOpt("literalURLs", &literalURLs) + var pathPrefix string + if ok := clientOpts.ReadOpt("pathPrefix", &pathPrefix); !ok { + pathPrefix = "/twirp" // default prefix + } + + // Build method URLs: []/./ + serviceURL := sanitizeBaseURL(baseURL) + serviceURL += baseServicePath(pathPrefix, "livekit", "Connector") + urls := [4]string{ + serviceURL + "DialWhatsAppCall", + serviceURL + "DisconnectWhatsAppCall", + serviceURL + "ConnectWhatsAppCall", + serviceURL + "AcceptWhatsAppCall", + } + + return &connectorProtobufClient{ + client: client, + urls: urls, + interceptor: twirp.ChainInterceptors(clientOpts.Interceptors...), + opts: clientOpts, + } +} + +func (c *connectorProtobufClient) DialWhatsAppCall(ctx context.Context, in *DialWhatsAppCallRequest) (*DialWhatsAppCallResponse, error) { + ctx = ctxsetters.WithPackageName(ctx, "livekit") + ctx = ctxsetters.WithServiceName(ctx, "Connector") + ctx = ctxsetters.WithMethodName(ctx, "DialWhatsAppCall") + caller := c.callDialWhatsAppCall + if c.interceptor != nil { + caller = func(ctx context.Context, req *DialWhatsAppCallRequest) (*DialWhatsAppCallResponse, error) { + resp, err := c.interceptor( + func(ctx context.Context, req interface{}) (interface{}, error) { + typedReq, ok := req.(*DialWhatsAppCallRequest) + if !ok { + return nil, twirp.InternalError("failed type assertion req.(*DialWhatsAppCallRequest) when calling interceptor") + } + return c.callDialWhatsAppCall(ctx, typedReq) + }, + )(ctx, req) + if resp != nil { + typedResp, ok := resp.(*DialWhatsAppCallResponse) + if !ok { + return nil, twirp.InternalError("failed type assertion resp.(*DialWhatsAppCallResponse) when calling interceptor") + } + return typedResp, err + } + return nil, err + } + } + return caller(ctx, in) +} + +func (c *connectorProtobufClient) callDialWhatsAppCall(ctx context.Context, in *DialWhatsAppCallRequest) (*DialWhatsAppCallResponse, error) { + out := new(DialWhatsAppCallResponse) + ctx, err := doProtobufRequest(ctx, c.client, c.opts.Hooks, c.urls[0], in, out) + if err != nil { + twerr, ok := err.(twirp.Error) + if !ok { + twerr = twirp.InternalErrorWith(err) + } + callClientError(ctx, c.opts.Hooks, twerr) + return nil, err + } + + callClientResponseReceived(ctx, c.opts.Hooks) + + return out, nil +} + +func (c *connectorProtobufClient) DisconnectWhatsAppCall(ctx context.Context, in *DisconnectWhatsAppCallRequest) (*DisconnectWhatsAppCallResponse, error) { + ctx = ctxsetters.WithPackageName(ctx, "livekit") + ctx = ctxsetters.WithServiceName(ctx, "Connector") + ctx = ctxsetters.WithMethodName(ctx, "DisconnectWhatsAppCall") + caller := c.callDisconnectWhatsAppCall + if c.interceptor != nil { + caller = func(ctx context.Context, req *DisconnectWhatsAppCallRequest) (*DisconnectWhatsAppCallResponse, error) { + resp, err := c.interceptor( + func(ctx context.Context, req interface{}) (interface{}, error) { + typedReq, ok := req.(*DisconnectWhatsAppCallRequest) + if !ok { + return nil, twirp.InternalError("failed type assertion req.(*DisconnectWhatsAppCallRequest) when calling interceptor") + } + return c.callDisconnectWhatsAppCall(ctx, typedReq) + }, + )(ctx, req) + if resp != nil { + typedResp, ok := resp.(*DisconnectWhatsAppCallResponse) + if !ok { + return nil, twirp.InternalError("failed type assertion resp.(*DisconnectWhatsAppCallResponse) when calling interceptor") + } + return typedResp, err + } + return nil, err + } + } + return caller(ctx, in) +} + +func (c *connectorProtobufClient) callDisconnectWhatsAppCall(ctx context.Context, in *DisconnectWhatsAppCallRequest) (*DisconnectWhatsAppCallResponse, error) { + out := new(DisconnectWhatsAppCallResponse) + ctx, err := doProtobufRequest(ctx, c.client, c.opts.Hooks, c.urls[1], in, out) + if err != nil { + twerr, ok := err.(twirp.Error) + if !ok { + twerr = twirp.InternalErrorWith(err) + } + callClientError(ctx, c.opts.Hooks, twerr) + return nil, err + } + + callClientResponseReceived(ctx, c.opts.Hooks) + + return out, nil +} + +func (c *connectorProtobufClient) ConnectWhatsAppCall(ctx context.Context, in *ConnectWhatsAppCallRequest) (*ConnectWhatsAppCallResponse, error) { + ctx = ctxsetters.WithPackageName(ctx, "livekit") + ctx = ctxsetters.WithServiceName(ctx, "Connector") + ctx = ctxsetters.WithMethodName(ctx, "ConnectWhatsAppCall") + caller := c.callConnectWhatsAppCall + if c.interceptor != nil { + caller = func(ctx context.Context, req *ConnectWhatsAppCallRequest) (*ConnectWhatsAppCallResponse, error) { + resp, err := c.interceptor( + func(ctx context.Context, req interface{}) (interface{}, error) { + typedReq, ok := req.(*ConnectWhatsAppCallRequest) + if !ok { + return nil, twirp.InternalError("failed type assertion req.(*ConnectWhatsAppCallRequest) when calling interceptor") + } + return c.callConnectWhatsAppCall(ctx, typedReq) + }, + )(ctx, req) + if resp != nil { + typedResp, ok := resp.(*ConnectWhatsAppCallResponse) + if !ok { + return nil, twirp.InternalError("failed type assertion resp.(*ConnectWhatsAppCallResponse) when calling interceptor") + } + return typedResp, err + } + return nil, err + } + } + return caller(ctx, in) +} + +func (c *connectorProtobufClient) callConnectWhatsAppCall(ctx context.Context, in *ConnectWhatsAppCallRequest) (*ConnectWhatsAppCallResponse, error) { + out := new(ConnectWhatsAppCallResponse) + ctx, err := doProtobufRequest(ctx, c.client, c.opts.Hooks, c.urls[2], in, out) + if err != nil { + twerr, ok := err.(twirp.Error) + if !ok { + twerr = twirp.InternalErrorWith(err) + } + callClientError(ctx, c.opts.Hooks, twerr) + return nil, err + } + + callClientResponseReceived(ctx, c.opts.Hooks) + + return out, nil +} + +func (c *connectorProtobufClient) AcceptWhatsAppCall(ctx context.Context, in *AcceptWhatsAppCallRequest) (*AcceptWhatsAppCallResponse, error) { + ctx = ctxsetters.WithPackageName(ctx, "livekit") + ctx = ctxsetters.WithServiceName(ctx, "Connector") + ctx = ctxsetters.WithMethodName(ctx, "AcceptWhatsAppCall") + caller := c.callAcceptWhatsAppCall + if c.interceptor != nil { + caller = func(ctx context.Context, req *AcceptWhatsAppCallRequest) (*AcceptWhatsAppCallResponse, error) { + resp, err := c.interceptor( + func(ctx context.Context, req interface{}) (interface{}, error) { + typedReq, ok := req.(*AcceptWhatsAppCallRequest) + if !ok { + return nil, twirp.InternalError("failed type assertion req.(*AcceptWhatsAppCallRequest) when calling interceptor") + } + return c.callAcceptWhatsAppCall(ctx, typedReq) + }, + )(ctx, req) + if resp != nil { + typedResp, ok := resp.(*AcceptWhatsAppCallResponse) + if !ok { + return nil, twirp.InternalError("failed type assertion resp.(*AcceptWhatsAppCallResponse) when calling interceptor") + } + return typedResp, err + } + return nil, err + } + } + return caller(ctx, in) +} + +func (c *connectorProtobufClient) callAcceptWhatsAppCall(ctx context.Context, in *AcceptWhatsAppCallRequest) (*AcceptWhatsAppCallResponse, error) { + out := new(AcceptWhatsAppCallResponse) + ctx, err := doProtobufRequest(ctx, c.client, c.opts.Hooks, c.urls[3], in, out) + if err != nil { + twerr, ok := err.(twirp.Error) + if !ok { + twerr = twirp.InternalErrorWith(err) + } + callClientError(ctx, c.opts.Hooks, twerr) + return nil, err + } + + callClientResponseReceived(ctx, c.opts.Hooks) + + return out, nil +} + +// ===================== +// Connector JSON Client +// ===================== + +type connectorJSONClient struct { + client HTTPClient + urls [4]string + interceptor twirp.Interceptor + opts twirp.ClientOptions +} + +// NewConnectorJSONClient creates a JSON client that implements the Connector interface. +// It communicates using JSON and can be configured with a custom HTTPClient. +func NewConnectorJSONClient(baseURL string, client HTTPClient, opts ...twirp.ClientOption) Connector { + if c, ok := client.(*http.Client); ok { + client = withoutRedirects(c) + } + + clientOpts := twirp.ClientOptions{} + for _, o := range opts { + o(&clientOpts) + } + + // Using ReadOpt allows backwards and forwards compatibility with new options in the future + literalURLs := false + _ = clientOpts.ReadOpt("literalURLs", &literalURLs) + var pathPrefix string + if ok := clientOpts.ReadOpt("pathPrefix", &pathPrefix); !ok { + pathPrefix = "/twirp" // default prefix + } + + // Build method URLs: []/./ + serviceURL := sanitizeBaseURL(baseURL) + serviceURL += baseServicePath(pathPrefix, "livekit", "Connector") + urls := [4]string{ + serviceURL + "DialWhatsAppCall", + serviceURL + "DisconnectWhatsAppCall", + serviceURL + "ConnectWhatsAppCall", + serviceURL + "AcceptWhatsAppCall", + } + + return &connectorJSONClient{ + client: client, + urls: urls, + interceptor: twirp.ChainInterceptors(clientOpts.Interceptors...), + opts: clientOpts, + } +} + +func (c *connectorJSONClient) DialWhatsAppCall(ctx context.Context, in *DialWhatsAppCallRequest) (*DialWhatsAppCallResponse, error) { + ctx = ctxsetters.WithPackageName(ctx, "livekit") + ctx = ctxsetters.WithServiceName(ctx, "Connector") + ctx = ctxsetters.WithMethodName(ctx, "DialWhatsAppCall") + caller := c.callDialWhatsAppCall + if c.interceptor != nil { + caller = func(ctx context.Context, req *DialWhatsAppCallRequest) (*DialWhatsAppCallResponse, error) { + resp, err := c.interceptor( + func(ctx context.Context, req interface{}) (interface{}, error) { + typedReq, ok := req.(*DialWhatsAppCallRequest) + if !ok { + return nil, twirp.InternalError("failed type assertion req.(*DialWhatsAppCallRequest) when calling interceptor") + } + return c.callDialWhatsAppCall(ctx, typedReq) + }, + )(ctx, req) + if resp != nil { + typedResp, ok := resp.(*DialWhatsAppCallResponse) + if !ok { + return nil, twirp.InternalError("failed type assertion resp.(*DialWhatsAppCallResponse) when calling interceptor") + } + return typedResp, err + } + return nil, err + } + } + return caller(ctx, in) +} + +func (c *connectorJSONClient) callDialWhatsAppCall(ctx context.Context, in *DialWhatsAppCallRequest) (*DialWhatsAppCallResponse, error) { + out := new(DialWhatsAppCallResponse) + ctx, err := doJSONRequest(ctx, c.client, c.opts.Hooks, c.urls[0], in, out) + if err != nil { + twerr, ok := err.(twirp.Error) + if !ok { + twerr = twirp.InternalErrorWith(err) + } + callClientError(ctx, c.opts.Hooks, twerr) + return nil, err + } + + callClientResponseReceived(ctx, c.opts.Hooks) + + return out, nil +} + +func (c *connectorJSONClient) DisconnectWhatsAppCall(ctx context.Context, in *DisconnectWhatsAppCallRequest) (*DisconnectWhatsAppCallResponse, error) { + ctx = ctxsetters.WithPackageName(ctx, "livekit") + ctx = ctxsetters.WithServiceName(ctx, "Connector") + ctx = ctxsetters.WithMethodName(ctx, "DisconnectWhatsAppCall") + caller := c.callDisconnectWhatsAppCall + if c.interceptor != nil { + caller = func(ctx context.Context, req *DisconnectWhatsAppCallRequest) (*DisconnectWhatsAppCallResponse, error) { + resp, err := c.interceptor( + func(ctx context.Context, req interface{}) (interface{}, error) { + typedReq, ok := req.(*DisconnectWhatsAppCallRequest) + if !ok { + return nil, twirp.InternalError("failed type assertion req.(*DisconnectWhatsAppCallRequest) when calling interceptor") + } + return c.callDisconnectWhatsAppCall(ctx, typedReq) + }, + )(ctx, req) + if resp != nil { + typedResp, ok := resp.(*DisconnectWhatsAppCallResponse) + if !ok { + return nil, twirp.InternalError("failed type assertion resp.(*DisconnectWhatsAppCallResponse) when calling interceptor") + } + return typedResp, err + } + return nil, err + } + } + return caller(ctx, in) +} + +func (c *connectorJSONClient) callDisconnectWhatsAppCall(ctx context.Context, in *DisconnectWhatsAppCallRequest) (*DisconnectWhatsAppCallResponse, error) { + out := new(DisconnectWhatsAppCallResponse) + ctx, err := doJSONRequest(ctx, c.client, c.opts.Hooks, c.urls[1], in, out) + if err != nil { + twerr, ok := err.(twirp.Error) + if !ok { + twerr = twirp.InternalErrorWith(err) + } + callClientError(ctx, c.opts.Hooks, twerr) + return nil, err + } + + callClientResponseReceived(ctx, c.opts.Hooks) + + return out, nil +} + +func (c *connectorJSONClient) ConnectWhatsAppCall(ctx context.Context, in *ConnectWhatsAppCallRequest) (*ConnectWhatsAppCallResponse, error) { + ctx = ctxsetters.WithPackageName(ctx, "livekit") + ctx = ctxsetters.WithServiceName(ctx, "Connector") + ctx = ctxsetters.WithMethodName(ctx, "ConnectWhatsAppCall") + caller := c.callConnectWhatsAppCall + if c.interceptor != nil { + caller = func(ctx context.Context, req *ConnectWhatsAppCallRequest) (*ConnectWhatsAppCallResponse, error) { + resp, err := c.interceptor( + func(ctx context.Context, req interface{}) (interface{}, error) { + typedReq, ok := req.(*ConnectWhatsAppCallRequest) + if !ok { + return nil, twirp.InternalError("failed type assertion req.(*ConnectWhatsAppCallRequest) when calling interceptor") + } + return c.callConnectWhatsAppCall(ctx, typedReq) + }, + )(ctx, req) + if resp != nil { + typedResp, ok := resp.(*ConnectWhatsAppCallResponse) + if !ok { + return nil, twirp.InternalError("failed type assertion resp.(*ConnectWhatsAppCallResponse) when calling interceptor") + } + return typedResp, err + } + return nil, err + } + } + return caller(ctx, in) +} + +func (c *connectorJSONClient) callConnectWhatsAppCall(ctx context.Context, in *ConnectWhatsAppCallRequest) (*ConnectWhatsAppCallResponse, error) { + out := new(ConnectWhatsAppCallResponse) + ctx, err := doJSONRequest(ctx, c.client, c.opts.Hooks, c.urls[2], in, out) + if err != nil { + twerr, ok := err.(twirp.Error) + if !ok { + twerr = twirp.InternalErrorWith(err) + } + callClientError(ctx, c.opts.Hooks, twerr) + return nil, err + } + + callClientResponseReceived(ctx, c.opts.Hooks) + + return out, nil +} + +func (c *connectorJSONClient) AcceptWhatsAppCall(ctx context.Context, in *AcceptWhatsAppCallRequest) (*AcceptWhatsAppCallResponse, error) { + ctx = ctxsetters.WithPackageName(ctx, "livekit") + ctx = ctxsetters.WithServiceName(ctx, "Connector") + ctx = ctxsetters.WithMethodName(ctx, "AcceptWhatsAppCall") + caller := c.callAcceptWhatsAppCall + if c.interceptor != nil { + caller = func(ctx context.Context, req *AcceptWhatsAppCallRequest) (*AcceptWhatsAppCallResponse, error) { + resp, err := c.interceptor( + func(ctx context.Context, req interface{}) (interface{}, error) { + typedReq, ok := req.(*AcceptWhatsAppCallRequest) + if !ok { + return nil, twirp.InternalError("failed type assertion req.(*AcceptWhatsAppCallRequest) when calling interceptor") + } + return c.callAcceptWhatsAppCall(ctx, typedReq) + }, + )(ctx, req) + if resp != nil { + typedResp, ok := resp.(*AcceptWhatsAppCallResponse) + if !ok { + return nil, twirp.InternalError("failed type assertion resp.(*AcceptWhatsAppCallResponse) when calling interceptor") + } + return typedResp, err + } + return nil, err + } + } + return caller(ctx, in) +} + +func (c *connectorJSONClient) callAcceptWhatsAppCall(ctx context.Context, in *AcceptWhatsAppCallRequest) (*AcceptWhatsAppCallResponse, error) { + out := new(AcceptWhatsAppCallResponse) + ctx, err := doJSONRequest(ctx, c.client, c.opts.Hooks, c.urls[3], in, out) + if err != nil { + twerr, ok := err.(twirp.Error) + if !ok { + twerr = twirp.InternalErrorWith(err) + } + callClientError(ctx, c.opts.Hooks, twerr) + return nil, err + } + + callClientResponseReceived(ctx, c.opts.Hooks) + + return out, nil +} + +// ======================== +// Connector Server Handler +// ======================== + +type connectorServer struct { + Connector + interceptor twirp.Interceptor + hooks *twirp.ServerHooks + pathPrefix string // prefix for routing + jsonSkipDefaults bool // do not include unpopulated fields (default values) in the response + jsonCamelCase bool // JSON fields are serialized as lowerCamelCase rather than keeping the original proto names +} + +// NewConnectorServer builds a TwirpServer that can be used as an http.Handler to handle +// HTTP requests that are routed to the right method in the provided svc implementation. +// The opts are twirp.ServerOption modifiers, for example twirp.WithServerHooks(hooks). +func NewConnectorServer(svc Connector, opts ...interface{}) TwirpServer { + serverOpts := newServerOpts(opts) + + // Using ReadOpt allows backwards and forwards compatibility with new options in the future + jsonSkipDefaults := false + _ = serverOpts.ReadOpt("jsonSkipDefaults", &jsonSkipDefaults) + jsonCamelCase := false + _ = serverOpts.ReadOpt("jsonCamelCase", &jsonCamelCase) + var pathPrefix string + if ok := serverOpts.ReadOpt("pathPrefix", &pathPrefix); !ok { + pathPrefix = "/twirp" // default prefix + } + + return &connectorServer{ + Connector: svc, + hooks: serverOpts.Hooks, + interceptor: twirp.ChainInterceptors(serverOpts.Interceptors...), + pathPrefix: pathPrefix, + jsonSkipDefaults: jsonSkipDefaults, + jsonCamelCase: jsonCamelCase, + } +} + +// writeError writes an HTTP response with a valid Twirp error format, and triggers hooks. +// If err is not a twirp.Error, it will get wrapped with twirp.InternalErrorWith(err) +func (s *connectorServer) writeError(ctx context.Context, resp http.ResponseWriter, err error) { + writeError(ctx, resp, err, s.hooks) +} + +// handleRequestBodyError is used to handle error when the twirp server cannot read request +func (s *connectorServer) handleRequestBodyError(ctx context.Context, resp http.ResponseWriter, msg string, err error) { + if context.Canceled == ctx.Err() { + s.writeError(ctx, resp, twirp.NewError(twirp.Canceled, "failed to read request: context canceled")) + return + } + if context.DeadlineExceeded == ctx.Err() { + s.writeError(ctx, resp, twirp.NewError(twirp.DeadlineExceeded, "failed to read request: deadline exceeded")) + return + } + s.writeError(ctx, resp, twirp.WrapError(malformedRequestError(msg), err)) +} + +// ConnectorPathPrefix is a convenience constant that may identify URL paths. +// Should be used with caution, it only matches routes generated by Twirp Go clients, +// with the default "/twirp" prefix and default CamelCase service and method names. +// More info: https://twitchtv.github.io/twirp/docs/routing.html +const ConnectorPathPrefix = "/twirp/livekit.Connector/" + +func (s *connectorServer) ServeHTTP(resp http.ResponseWriter, req *http.Request) { + ctx := req.Context() + ctx = ctxsetters.WithPackageName(ctx, "livekit") + ctx = ctxsetters.WithServiceName(ctx, "Connector") + ctx = ctxsetters.WithResponseWriter(ctx, resp) + + var err error + ctx, err = callRequestReceived(ctx, s.hooks) + if err != nil { + s.writeError(ctx, resp, err) + return + } + + if req.Method != "POST" { + msg := fmt.Sprintf("unsupported method %q (only POST is allowed)", req.Method) + s.writeError(ctx, resp, badRouteError(msg, req.Method, req.URL.Path)) + return + } + + // Verify path format: []/./ + prefix, pkgService, method := parseTwirpPath(req.URL.Path) + if pkgService != "livekit.Connector" { + msg := fmt.Sprintf("no handler for path %q", req.URL.Path) + s.writeError(ctx, resp, badRouteError(msg, req.Method, req.URL.Path)) + return + } + if prefix != s.pathPrefix { + msg := fmt.Sprintf("invalid path prefix %q, expected %q, on path %q", prefix, s.pathPrefix, req.URL.Path) + s.writeError(ctx, resp, badRouteError(msg, req.Method, req.URL.Path)) + return + } + + switch method { + case "DialWhatsAppCall": + s.serveDialWhatsAppCall(ctx, resp, req) + return + case "DisconnectWhatsAppCall": + s.serveDisconnectWhatsAppCall(ctx, resp, req) + return + case "ConnectWhatsAppCall": + s.serveConnectWhatsAppCall(ctx, resp, req) + return + case "AcceptWhatsAppCall": + s.serveAcceptWhatsAppCall(ctx, resp, req) + return + default: + msg := fmt.Sprintf("no handler for path %q", req.URL.Path) + s.writeError(ctx, resp, badRouteError(msg, req.Method, req.URL.Path)) + return + } +} + +func (s *connectorServer) serveDialWhatsAppCall(ctx context.Context, resp http.ResponseWriter, req *http.Request) { + header := req.Header.Get("Content-Type") + i := strings.Index(header, ";") + if i == -1 { + i = len(header) + } + switch strings.TrimSpace(strings.ToLower(header[:i])) { + case "application/json": + s.serveDialWhatsAppCallJSON(ctx, resp, req) + case "application/protobuf": + s.serveDialWhatsAppCallProtobuf(ctx, resp, req) + default: + msg := fmt.Sprintf("unexpected Content-Type: %q", req.Header.Get("Content-Type")) + twerr := badRouteError(msg, req.Method, req.URL.Path) + s.writeError(ctx, resp, twerr) + } +} + +func (s *connectorServer) serveDialWhatsAppCallJSON(ctx context.Context, resp http.ResponseWriter, req *http.Request) { + var err error + ctx = ctxsetters.WithMethodName(ctx, "DialWhatsAppCall") + ctx, err = callRequestRouted(ctx, s.hooks) + if err != nil { + s.writeError(ctx, resp, err) + return + } + + d := json.NewDecoder(req.Body) + rawReqBody := json.RawMessage{} + if err := d.Decode(&rawReqBody); err != nil { + s.handleRequestBodyError(ctx, resp, "the json request could not be decoded", err) + return + } + reqContent := new(DialWhatsAppCallRequest) + unmarshaler := protojson.UnmarshalOptions{DiscardUnknown: true} + if err = unmarshaler.Unmarshal(rawReqBody, reqContent); err != nil { + s.handleRequestBodyError(ctx, resp, "the json request could not be decoded", err) + return + } + + handler := s.Connector.DialWhatsAppCall + if s.interceptor != nil { + handler = func(ctx context.Context, req *DialWhatsAppCallRequest) (*DialWhatsAppCallResponse, error) { + resp, err := s.interceptor( + func(ctx context.Context, req interface{}) (interface{}, error) { + typedReq, ok := req.(*DialWhatsAppCallRequest) + if !ok { + return nil, twirp.InternalError("failed type assertion req.(*DialWhatsAppCallRequest) when calling interceptor") + } + return s.Connector.DialWhatsAppCall(ctx, typedReq) + }, + )(ctx, req) + if resp != nil { + typedResp, ok := resp.(*DialWhatsAppCallResponse) + if !ok { + return nil, twirp.InternalError("failed type assertion resp.(*DialWhatsAppCallResponse) when calling interceptor") + } + return typedResp, err + } + return nil, err + } + } + + // Call service method + var respContent *DialWhatsAppCallResponse + func() { + defer ensurePanicResponses(ctx, resp, s.hooks) + respContent, err = handler(ctx, reqContent) + }() + + if err != nil { + s.writeError(ctx, resp, err) + return + } + if respContent == nil { + s.writeError(ctx, resp, twirp.InternalError("received a nil *DialWhatsAppCallResponse and nil error while calling DialWhatsAppCall. nil responses are not supported")) + return + } + + ctx = callResponsePrepared(ctx, s.hooks) + + marshaler := &protojson.MarshalOptions{UseProtoNames: !s.jsonCamelCase, EmitUnpopulated: !s.jsonSkipDefaults} + respBytes, err := marshaler.Marshal(respContent) + if err != nil { + s.writeError(ctx, resp, wrapInternal(err, "failed to marshal json response")) + return + } + + ctx = ctxsetters.WithStatusCode(ctx, http.StatusOK) + resp.Header().Set("Content-Type", "application/json") + resp.Header().Set("Content-Length", strconv.Itoa(len(respBytes))) + resp.WriteHeader(http.StatusOK) + + if n, err := resp.Write(respBytes); err != nil { + msg := fmt.Sprintf("failed to write response, %d of %d bytes written: %s", n, len(respBytes), err.Error()) + twerr := twirp.NewError(twirp.Unknown, msg) + ctx = callError(ctx, s.hooks, twerr) + } + callResponseSent(ctx, s.hooks) +} + +func (s *connectorServer) serveDialWhatsAppCallProtobuf(ctx context.Context, resp http.ResponseWriter, req *http.Request) { + var err error + ctx = ctxsetters.WithMethodName(ctx, "DialWhatsAppCall") + ctx, err = callRequestRouted(ctx, s.hooks) + if err != nil { + s.writeError(ctx, resp, err) + return + } + + buf, err := io.ReadAll(req.Body) + if err != nil { + s.handleRequestBodyError(ctx, resp, "failed to read request body", err) + return + } + reqContent := new(DialWhatsAppCallRequest) + if err = proto.Unmarshal(buf, reqContent); err != nil { + s.writeError(ctx, resp, malformedRequestError("the protobuf request could not be decoded")) + return + } + + handler := s.Connector.DialWhatsAppCall + if s.interceptor != nil { + handler = func(ctx context.Context, req *DialWhatsAppCallRequest) (*DialWhatsAppCallResponse, error) { + resp, err := s.interceptor( + func(ctx context.Context, req interface{}) (interface{}, error) { + typedReq, ok := req.(*DialWhatsAppCallRequest) + if !ok { + return nil, twirp.InternalError("failed type assertion req.(*DialWhatsAppCallRequest) when calling interceptor") + } + return s.Connector.DialWhatsAppCall(ctx, typedReq) + }, + )(ctx, req) + if resp != nil { + typedResp, ok := resp.(*DialWhatsAppCallResponse) + if !ok { + return nil, twirp.InternalError("failed type assertion resp.(*DialWhatsAppCallResponse) when calling interceptor") + } + return typedResp, err + } + return nil, err + } + } + + // Call service method + var respContent *DialWhatsAppCallResponse + func() { + defer ensurePanicResponses(ctx, resp, s.hooks) + respContent, err = handler(ctx, reqContent) + }() + + if err != nil { + s.writeError(ctx, resp, err) + return + } + if respContent == nil { + s.writeError(ctx, resp, twirp.InternalError("received a nil *DialWhatsAppCallResponse and nil error while calling DialWhatsAppCall. nil responses are not supported")) + return + } + + ctx = callResponsePrepared(ctx, s.hooks) + + respBytes, err := proto.Marshal(respContent) + if err != nil { + s.writeError(ctx, resp, wrapInternal(err, "failed to marshal proto response")) + return + } + + ctx = ctxsetters.WithStatusCode(ctx, http.StatusOK) + resp.Header().Set("Content-Type", "application/protobuf") + resp.Header().Set("Content-Length", strconv.Itoa(len(respBytes))) + resp.WriteHeader(http.StatusOK) + if n, err := resp.Write(respBytes); err != nil { + msg := fmt.Sprintf("failed to write response, %d of %d bytes written: %s", n, len(respBytes), err.Error()) + twerr := twirp.NewError(twirp.Unknown, msg) + ctx = callError(ctx, s.hooks, twerr) + } + callResponseSent(ctx, s.hooks) +} + +func (s *connectorServer) serveDisconnectWhatsAppCall(ctx context.Context, resp http.ResponseWriter, req *http.Request) { + header := req.Header.Get("Content-Type") + i := strings.Index(header, ";") + if i == -1 { + i = len(header) + } + switch strings.TrimSpace(strings.ToLower(header[:i])) { + case "application/json": + s.serveDisconnectWhatsAppCallJSON(ctx, resp, req) + case "application/protobuf": + s.serveDisconnectWhatsAppCallProtobuf(ctx, resp, req) + default: + msg := fmt.Sprintf("unexpected Content-Type: %q", req.Header.Get("Content-Type")) + twerr := badRouteError(msg, req.Method, req.URL.Path) + s.writeError(ctx, resp, twerr) + } +} + +func (s *connectorServer) serveDisconnectWhatsAppCallJSON(ctx context.Context, resp http.ResponseWriter, req *http.Request) { + var err error + ctx = ctxsetters.WithMethodName(ctx, "DisconnectWhatsAppCall") + ctx, err = callRequestRouted(ctx, s.hooks) + if err != nil { + s.writeError(ctx, resp, err) + return + } + + d := json.NewDecoder(req.Body) + rawReqBody := json.RawMessage{} + if err := d.Decode(&rawReqBody); err != nil { + s.handleRequestBodyError(ctx, resp, "the json request could not be decoded", err) + return + } + reqContent := new(DisconnectWhatsAppCallRequest) + unmarshaler := protojson.UnmarshalOptions{DiscardUnknown: true} + if err = unmarshaler.Unmarshal(rawReqBody, reqContent); err != nil { + s.handleRequestBodyError(ctx, resp, "the json request could not be decoded", err) + return + } + + handler := s.Connector.DisconnectWhatsAppCall + if s.interceptor != nil { + handler = func(ctx context.Context, req *DisconnectWhatsAppCallRequest) (*DisconnectWhatsAppCallResponse, error) { + resp, err := s.interceptor( + func(ctx context.Context, req interface{}) (interface{}, error) { + typedReq, ok := req.(*DisconnectWhatsAppCallRequest) + if !ok { + return nil, twirp.InternalError("failed type assertion req.(*DisconnectWhatsAppCallRequest) when calling interceptor") + } + return s.Connector.DisconnectWhatsAppCall(ctx, typedReq) + }, + )(ctx, req) + if resp != nil { + typedResp, ok := resp.(*DisconnectWhatsAppCallResponse) + if !ok { + return nil, twirp.InternalError("failed type assertion resp.(*DisconnectWhatsAppCallResponse) when calling interceptor") + } + return typedResp, err + } + return nil, err + } + } + + // Call service method + var respContent *DisconnectWhatsAppCallResponse + func() { + defer ensurePanicResponses(ctx, resp, s.hooks) + respContent, err = handler(ctx, reqContent) + }() + + if err != nil { + s.writeError(ctx, resp, err) + return + } + if respContent == nil { + s.writeError(ctx, resp, twirp.InternalError("received a nil *DisconnectWhatsAppCallResponse and nil error while calling DisconnectWhatsAppCall. nil responses are not supported")) + return + } + + ctx = callResponsePrepared(ctx, s.hooks) + + marshaler := &protojson.MarshalOptions{UseProtoNames: !s.jsonCamelCase, EmitUnpopulated: !s.jsonSkipDefaults} + respBytes, err := marshaler.Marshal(respContent) + if err != nil { + s.writeError(ctx, resp, wrapInternal(err, "failed to marshal json response")) + return + } + + ctx = ctxsetters.WithStatusCode(ctx, http.StatusOK) + resp.Header().Set("Content-Type", "application/json") + resp.Header().Set("Content-Length", strconv.Itoa(len(respBytes))) + resp.WriteHeader(http.StatusOK) + + if n, err := resp.Write(respBytes); err != nil { + msg := fmt.Sprintf("failed to write response, %d of %d bytes written: %s", n, len(respBytes), err.Error()) + twerr := twirp.NewError(twirp.Unknown, msg) + ctx = callError(ctx, s.hooks, twerr) + } + callResponseSent(ctx, s.hooks) +} + +func (s *connectorServer) serveDisconnectWhatsAppCallProtobuf(ctx context.Context, resp http.ResponseWriter, req *http.Request) { + var err error + ctx = ctxsetters.WithMethodName(ctx, "DisconnectWhatsAppCall") + ctx, err = callRequestRouted(ctx, s.hooks) + if err != nil { + s.writeError(ctx, resp, err) + return + } + + buf, err := io.ReadAll(req.Body) + if err != nil { + s.handleRequestBodyError(ctx, resp, "failed to read request body", err) + return + } + reqContent := new(DisconnectWhatsAppCallRequest) + if err = proto.Unmarshal(buf, reqContent); err != nil { + s.writeError(ctx, resp, malformedRequestError("the protobuf request could not be decoded")) + return + } + + handler := s.Connector.DisconnectWhatsAppCall + if s.interceptor != nil { + handler = func(ctx context.Context, req *DisconnectWhatsAppCallRequest) (*DisconnectWhatsAppCallResponse, error) { + resp, err := s.interceptor( + func(ctx context.Context, req interface{}) (interface{}, error) { + typedReq, ok := req.(*DisconnectWhatsAppCallRequest) + if !ok { + return nil, twirp.InternalError("failed type assertion req.(*DisconnectWhatsAppCallRequest) when calling interceptor") + } + return s.Connector.DisconnectWhatsAppCall(ctx, typedReq) + }, + )(ctx, req) + if resp != nil { + typedResp, ok := resp.(*DisconnectWhatsAppCallResponse) + if !ok { + return nil, twirp.InternalError("failed type assertion resp.(*DisconnectWhatsAppCallResponse) when calling interceptor") + } + return typedResp, err + } + return nil, err + } + } + + // Call service method + var respContent *DisconnectWhatsAppCallResponse + func() { + defer ensurePanicResponses(ctx, resp, s.hooks) + respContent, err = handler(ctx, reqContent) + }() + + if err != nil { + s.writeError(ctx, resp, err) + return + } + if respContent == nil { + s.writeError(ctx, resp, twirp.InternalError("received a nil *DisconnectWhatsAppCallResponse and nil error while calling DisconnectWhatsAppCall. nil responses are not supported")) + return + } + + ctx = callResponsePrepared(ctx, s.hooks) + + respBytes, err := proto.Marshal(respContent) + if err != nil { + s.writeError(ctx, resp, wrapInternal(err, "failed to marshal proto response")) + return + } + + ctx = ctxsetters.WithStatusCode(ctx, http.StatusOK) + resp.Header().Set("Content-Type", "application/protobuf") + resp.Header().Set("Content-Length", strconv.Itoa(len(respBytes))) + resp.WriteHeader(http.StatusOK) + if n, err := resp.Write(respBytes); err != nil { + msg := fmt.Sprintf("failed to write response, %d of %d bytes written: %s", n, len(respBytes), err.Error()) + twerr := twirp.NewError(twirp.Unknown, msg) + ctx = callError(ctx, s.hooks, twerr) + } + callResponseSent(ctx, s.hooks) +} + +func (s *connectorServer) serveConnectWhatsAppCall(ctx context.Context, resp http.ResponseWriter, req *http.Request) { + header := req.Header.Get("Content-Type") + i := strings.Index(header, ";") + if i == -1 { + i = len(header) + } + switch strings.TrimSpace(strings.ToLower(header[:i])) { + case "application/json": + s.serveConnectWhatsAppCallJSON(ctx, resp, req) + case "application/protobuf": + s.serveConnectWhatsAppCallProtobuf(ctx, resp, req) + default: + msg := fmt.Sprintf("unexpected Content-Type: %q", req.Header.Get("Content-Type")) + twerr := badRouteError(msg, req.Method, req.URL.Path) + s.writeError(ctx, resp, twerr) + } +} + +func (s *connectorServer) serveConnectWhatsAppCallJSON(ctx context.Context, resp http.ResponseWriter, req *http.Request) { + var err error + ctx = ctxsetters.WithMethodName(ctx, "ConnectWhatsAppCall") + ctx, err = callRequestRouted(ctx, s.hooks) + if err != nil { + s.writeError(ctx, resp, err) + return + } + + d := json.NewDecoder(req.Body) + rawReqBody := json.RawMessage{} + if err := d.Decode(&rawReqBody); err != nil { + s.handleRequestBodyError(ctx, resp, "the json request could not be decoded", err) + return + } + reqContent := new(ConnectWhatsAppCallRequest) + unmarshaler := protojson.UnmarshalOptions{DiscardUnknown: true} + if err = unmarshaler.Unmarshal(rawReqBody, reqContent); err != nil { + s.handleRequestBodyError(ctx, resp, "the json request could not be decoded", err) + return + } + + handler := s.Connector.ConnectWhatsAppCall + if s.interceptor != nil { + handler = func(ctx context.Context, req *ConnectWhatsAppCallRequest) (*ConnectWhatsAppCallResponse, error) { + resp, err := s.interceptor( + func(ctx context.Context, req interface{}) (interface{}, error) { + typedReq, ok := req.(*ConnectWhatsAppCallRequest) + if !ok { + return nil, twirp.InternalError("failed type assertion req.(*ConnectWhatsAppCallRequest) when calling interceptor") + } + return s.Connector.ConnectWhatsAppCall(ctx, typedReq) + }, + )(ctx, req) + if resp != nil { + typedResp, ok := resp.(*ConnectWhatsAppCallResponse) + if !ok { + return nil, twirp.InternalError("failed type assertion resp.(*ConnectWhatsAppCallResponse) when calling interceptor") + } + return typedResp, err + } + return nil, err + } + } + + // Call service method + var respContent *ConnectWhatsAppCallResponse + func() { + defer ensurePanicResponses(ctx, resp, s.hooks) + respContent, err = handler(ctx, reqContent) + }() + + if err != nil { + s.writeError(ctx, resp, err) + return + } + if respContent == nil { + s.writeError(ctx, resp, twirp.InternalError("received a nil *ConnectWhatsAppCallResponse and nil error while calling ConnectWhatsAppCall. nil responses are not supported")) + return + } + + ctx = callResponsePrepared(ctx, s.hooks) + + marshaler := &protojson.MarshalOptions{UseProtoNames: !s.jsonCamelCase, EmitUnpopulated: !s.jsonSkipDefaults} + respBytes, err := marshaler.Marshal(respContent) + if err != nil { + s.writeError(ctx, resp, wrapInternal(err, "failed to marshal json response")) + return + } + + ctx = ctxsetters.WithStatusCode(ctx, http.StatusOK) + resp.Header().Set("Content-Type", "application/json") + resp.Header().Set("Content-Length", strconv.Itoa(len(respBytes))) + resp.WriteHeader(http.StatusOK) + + if n, err := resp.Write(respBytes); err != nil { + msg := fmt.Sprintf("failed to write response, %d of %d bytes written: %s", n, len(respBytes), err.Error()) + twerr := twirp.NewError(twirp.Unknown, msg) + ctx = callError(ctx, s.hooks, twerr) + } + callResponseSent(ctx, s.hooks) +} + +func (s *connectorServer) serveConnectWhatsAppCallProtobuf(ctx context.Context, resp http.ResponseWriter, req *http.Request) { + var err error + ctx = ctxsetters.WithMethodName(ctx, "ConnectWhatsAppCall") + ctx, err = callRequestRouted(ctx, s.hooks) + if err != nil { + s.writeError(ctx, resp, err) + return + } + + buf, err := io.ReadAll(req.Body) + if err != nil { + s.handleRequestBodyError(ctx, resp, "failed to read request body", err) + return + } + reqContent := new(ConnectWhatsAppCallRequest) + if err = proto.Unmarshal(buf, reqContent); err != nil { + s.writeError(ctx, resp, malformedRequestError("the protobuf request could not be decoded")) + return + } + + handler := s.Connector.ConnectWhatsAppCall + if s.interceptor != nil { + handler = func(ctx context.Context, req *ConnectWhatsAppCallRequest) (*ConnectWhatsAppCallResponse, error) { + resp, err := s.interceptor( + func(ctx context.Context, req interface{}) (interface{}, error) { + typedReq, ok := req.(*ConnectWhatsAppCallRequest) + if !ok { + return nil, twirp.InternalError("failed type assertion req.(*ConnectWhatsAppCallRequest) when calling interceptor") + } + return s.Connector.ConnectWhatsAppCall(ctx, typedReq) + }, + )(ctx, req) + if resp != nil { + typedResp, ok := resp.(*ConnectWhatsAppCallResponse) + if !ok { + return nil, twirp.InternalError("failed type assertion resp.(*ConnectWhatsAppCallResponse) when calling interceptor") + } + return typedResp, err + } + return nil, err + } + } + + // Call service method + var respContent *ConnectWhatsAppCallResponse + func() { + defer ensurePanicResponses(ctx, resp, s.hooks) + respContent, err = handler(ctx, reqContent) + }() + + if err != nil { + s.writeError(ctx, resp, err) + return + } + if respContent == nil { + s.writeError(ctx, resp, twirp.InternalError("received a nil *ConnectWhatsAppCallResponse and nil error while calling ConnectWhatsAppCall. nil responses are not supported")) + return + } + + ctx = callResponsePrepared(ctx, s.hooks) + + respBytes, err := proto.Marshal(respContent) + if err != nil { + s.writeError(ctx, resp, wrapInternal(err, "failed to marshal proto response")) + return + } + + ctx = ctxsetters.WithStatusCode(ctx, http.StatusOK) + resp.Header().Set("Content-Type", "application/protobuf") + resp.Header().Set("Content-Length", strconv.Itoa(len(respBytes))) + resp.WriteHeader(http.StatusOK) + if n, err := resp.Write(respBytes); err != nil { + msg := fmt.Sprintf("failed to write response, %d of %d bytes written: %s", n, len(respBytes), err.Error()) + twerr := twirp.NewError(twirp.Unknown, msg) + ctx = callError(ctx, s.hooks, twerr) + } + callResponseSent(ctx, s.hooks) +} + +func (s *connectorServer) serveAcceptWhatsAppCall(ctx context.Context, resp http.ResponseWriter, req *http.Request) { + header := req.Header.Get("Content-Type") + i := strings.Index(header, ";") + if i == -1 { + i = len(header) + } + switch strings.TrimSpace(strings.ToLower(header[:i])) { + case "application/json": + s.serveAcceptWhatsAppCallJSON(ctx, resp, req) + case "application/protobuf": + s.serveAcceptWhatsAppCallProtobuf(ctx, resp, req) + default: + msg := fmt.Sprintf("unexpected Content-Type: %q", req.Header.Get("Content-Type")) + twerr := badRouteError(msg, req.Method, req.URL.Path) + s.writeError(ctx, resp, twerr) + } +} + +func (s *connectorServer) serveAcceptWhatsAppCallJSON(ctx context.Context, resp http.ResponseWriter, req *http.Request) { + var err error + ctx = ctxsetters.WithMethodName(ctx, "AcceptWhatsAppCall") + ctx, err = callRequestRouted(ctx, s.hooks) + if err != nil { + s.writeError(ctx, resp, err) + return + } + + d := json.NewDecoder(req.Body) + rawReqBody := json.RawMessage{} + if err := d.Decode(&rawReqBody); err != nil { + s.handleRequestBodyError(ctx, resp, "the json request could not be decoded", err) + return + } + reqContent := new(AcceptWhatsAppCallRequest) + unmarshaler := protojson.UnmarshalOptions{DiscardUnknown: true} + if err = unmarshaler.Unmarshal(rawReqBody, reqContent); err != nil { + s.handleRequestBodyError(ctx, resp, "the json request could not be decoded", err) + return + } + + handler := s.Connector.AcceptWhatsAppCall + if s.interceptor != nil { + handler = func(ctx context.Context, req *AcceptWhatsAppCallRequest) (*AcceptWhatsAppCallResponse, error) { + resp, err := s.interceptor( + func(ctx context.Context, req interface{}) (interface{}, error) { + typedReq, ok := req.(*AcceptWhatsAppCallRequest) + if !ok { + return nil, twirp.InternalError("failed type assertion req.(*AcceptWhatsAppCallRequest) when calling interceptor") + } + return s.Connector.AcceptWhatsAppCall(ctx, typedReq) + }, + )(ctx, req) + if resp != nil { + typedResp, ok := resp.(*AcceptWhatsAppCallResponse) + if !ok { + return nil, twirp.InternalError("failed type assertion resp.(*AcceptWhatsAppCallResponse) when calling interceptor") + } + return typedResp, err + } + return nil, err + } + } + + // Call service method + var respContent *AcceptWhatsAppCallResponse + func() { + defer ensurePanicResponses(ctx, resp, s.hooks) + respContent, err = handler(ctx, reqContent) + }() + + if err != nil { + s.writeError(ctx, resp, err) + return + } + if respContent == nil { + s.writeError(ctx, resp, twirp.InternalError("received a nil *AcceptWhatsAppCallResponse and nil error while calling AcceptWhatsAppCall. nil responses are not supported")) + return + } + + ctx = callResponsePrepared(ctx, s.hooks) + + marshaler := &protojson.MarshalOptions{UseProtoNames: !s.jsonCamelCase, EmitUnpopulated: !s.jsonSkipDefaults} + respBytes, err := marshaler.Marshal(respContent) + if err != nil { + s.writeError(ctx, resp, wrapInternal(err, "failed to marshal json response")) + return + } + + ctx = ctxsetters.WithStatusCode(ctx, http.StatusOK) + resp.Header().Set("Content-Type", "application/json") + resp.Header().Set("Content-Length", strconv.Itoa(len(respBytes))) + resp.WriteHeader(http.StatusOK) + + if n, err := resp.Write(respBytes); err != nil { + msg := fmt.Sprintf("failed to write response, %d of %d bytes written: %s", n, len(respBytes), err.Error()) + twerr := twirp.NewError(twirp.Unknown, msg) + ctx = callError(ctx, s.hooks, twerr) + } + callResponseSent(ctx, s.hooks) +} + +func (s *connectorServer) serveAcceptWhatsAppCallProtobuf(ctx context.Context, resp http.ResponseWriter, req *http.Request) { + var err error + ctx = ctxsetters.WithMethodName(ctx, "AcceptWhatsAppCall") + ctx, err = callRequestRouted(ctx, s.hooks) + if err != nil { + s.writeError(ctx, resp, err) + return + } + + buf, err := io.ReadAll(req.Body) + if err != nil { + s.handleRequestBodyError(ctx, resp, "failed to read request body", err) + return + } + reqContent := new(AcceptWhatsAppCallRequest) + if err = proto.Unmarshal(buf, reqContent); err != nil { + s.writeError(ctx, resp, malformedRequestError("the protobuf request could not be decoded")) + return + } + + handler := s.Connector.AcceptWhatsAppCall + if s.interceptor != nil { + handler = func(ctx context.Context, req *AcceptWhatsAppCallRequest) (*AcceptWhatsAppCallResponse, error) { + resp, err := s.interceptor( + func(ctx context.Context, req interface{}) (interface{}, error) { + typedReq, ok := req.(*AcceptWhatsAppCallRequest) + if !ok { + return nil, twirp.InternalError("failed type assertion req.(*AcceptWhatsAppCallRequest) when calling interceptor") + } + return s.Connector.AcceptWhatsAppCall(ctx, typedReq) + }, + )(ctx, req) + if resp != nil { + typedResp, ok := resp.(*AcceptWhatsAppCallResponse) + if !ok { + return nil, twirp.InternalError("failed type assertion resp.(*AcceptWhatsAppCallResponse) when calling interceptor") + } + return typedResp, err + } + return nil, err + } + } + + // Call service method + var respContent *AcceptWhatsAppCallResponse + func() { + defer ensurePanicResponses(ctx, resp, s.hooks) + respContent, err = handler(ctx, reqContent) + }() + + if err != nil { + s.writeError(ctx, resp, err) + return + } + if respContent == nil { + s.writeError(ctx, resp, twirp.InternalError("received a nil *AcceptWhatsAppCallResponse and nil error while calling AcceptWhatsAppCall. nil responses are not supported")) + return + } + + ctx = callResponsePrepared(ctx, s.hooks) + + respBytes, err := proto.Marshal(respContent) + if err != nil { + s.writeError(ctx, resp, wrapInternal(err, "failed to marshal proto response")) + return + } + + ctx = ctxsetters.WithStatusCode(ctx, http.StatusOK) + resp.Header().Set("Content-Type", "application/protobuf") + resp.Header().Set("Content-Length", strconv.Itoa(len(respBytes))) + resp.WriteHeader(http.StatusOK) + if n, err := resp.Write(respBytes); err != nil { + msg := fmt.Sprintf("failed to write response, %d of %d bytes written: %s", n, len(respBytes), err.Error()) + twerr := twirp.NewError(twirp.Unknown, msg) + ctx = callError(ctx, s.hooks, twerr) + } + callResponseSent(ctx, s.hooks) +} + +func (s *connectorServer) ServiceDescriptor() ([]byte, int) { + return twirpFileDescriptor7, 0 +} + +func (s *connectorServer) ProtocGenTwirpVersion() string { + return "v8.1.3" +} + +// PathPrefix returns the base service path, in the form: "//./" +// that is everything in a Twirp route except for the . This can be used for routing, +// for example to identify the requests that are targeted to this service in a mux. +func (s *connectorServer) PathPrefix() string { + return baseServicePath(s.pathPrefix, "livekit", "Connector") +} + +var twirpFileDescriptor7 = []byte{ + // 238 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0xcf, 0xc9, 0x2c, 0x4b, + 0xcd, 0xce, 0x2c, 0x89, 0x4f, 0xce, 0xcf, 0xcb, 0x4b, 0x4d, 0x2e, 0xc9, 0x2f, 0xd2, 0x2b, 0x28, + 0xca, 0x2f, 0xc9, 0x17, 0x62, 0x87, 0x4a, 0x48, 0x29, 0x60, 0xa8, 0x88, 0x2f, 0xcf, 0x48, 0x2c, + 0x29, 0x4e, 0x2c, 0x28, 0x80, 0x28, 0x35, 0x9a, 0xc0, 0xcc, 0xc5, 0xe9, 0x0c, 0x93, 0x14, 0x0a, + 0xe7, 0x12, 0x70, 0xc9, 0x4c, 0xcc, 0x09, 0x07, 0xa9, 0x71, 0x2c, 0x28, 0x70, 0x4e, 0xcc, 0xc9, + 0x11, 0x52, 0xd0, 0x83, 0x1a, 0xa2, 0x87, 0x2e, 0x15, 0x94, 0x5a, 0x58, 0x9a, 0x5a, 0x5c, 0x22, + 0xa5, 0x88, 0x47, 0x45, 0x71, 0x41, 0x7e, 0x5e, 0x71, 0xaa, 0x50, 0x26, 0x97, 0x98, 0x4b, 0x66, + 0x31, 0xd4, 0x15, 0x28, 0xc6, 0xab, 0x21, 0x69, 0xc6, 0xa6, 0x00, 0x66, 0x89, 0x3a, 0x41, 0x75, + 0x50, 0xab, 0x12, 0xb8, 0x84, 0x9d, 0xb1, 0xd8, 0xa3, 0x0c, 0xd7, 0xef, 0x8c, 0xdb, 0x12, 0x15, + 0xfc, 0x8a, 0xa0, 0x36, 0xc4, 0x72, 0x09, 0x39, 0x26, 0x27, 0xa7, 0x16, 0xa0, 0x5a, 0xa0, 0x04, + 0xd7, 0x8b, 0x29, 0x09, 0x33, 0x5f, 0x19, 0xaf, 0x1a, 0x88, 0xf1, 0x4e, 0x6e, 0x51, 0xca, 0xe9, + 0x99, 0x25, 0x19, 0xa5, 0x49, 0x7a, 0xc9, 0xf9, 0xb9, 0xfa, 0x50, 0x0d, 0xfa, 0xe0, 0xe8, 0x4a, + 0xce, 0xcf, 0x81, 0x09, 0xac, 0x62, 0xe2, 0xf5, 0xc9, 0x2c, 0x4b, 0xf5, 0xce, 0x2c, 0xd1, 0x0b, + 0x00, 0x49, 0xbd, 0x62, 0xe2, 0x83, 0xf2, 0xad, 0xac, 0xc0, 0x02, 0x49, 0x6c, 0x60, 0x2d, 0xc6, + 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0x7a, 0x7c, 0x2f, 0xe1, 0x27, 0x02, 0x00, 0x00, +} diff --git a/livekit/livekit_connector_whatsapp.pb.go b/livekit/livekit_connector_whatsapp.pb.go new file mode 100644 index 0000000..6f6a7cd --- /dev/null +++ b/livekit/livekit_connector_whatsapp.pb.go @@ -0,0 +1,825 @@ +// Copyright 2025 LiveKit, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.10 +// protoc v4.23.4 +// source: livekit_connector_whatsapp.proto + +package livekit + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type WhatsAppCallDirection int32 + +const ( + WhatsAppCallDirection_WHATSAPP_CALL_DIRECTION_INBOUND WhatsAppCallDirection = 0 + WhatsAppCallDirection_WHATSAPP_CALL_DIRECTION_OUTBOUND WhatsAppCallDirection = 2 +) + +// Enum value maps for WhatsAppCallDirection. +var ( + WhatsAppCallDirection_name = map[int32]string{ + 0: "WHATSAPP_CALL_DIRECTION_INBOUND", + 2: "WHATSAPP_CALL_DIRECTION_OUTBOUND", + } + WhatsAppCallDirection_value = map[string]int32{ + "WHATSAPP_CALL_DIRECTION_INBOUND": 0, + "WHATSAPP_CALL_DIRECTION_OUTBOUND": 2, + } +) + +func (x WhatsAppCallDirection) Enum() *WhatsAppCallDirection { + p := new(WhatsAppCallDirection) + *p = x + return p +} + +func (x WhatsAppCallDirection) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (WhatsAppCallDirection) Descriptor() protoreflect.EnumDescriptor { + return file_livekit_connector_whatsapp_proto_enumTypes[0].Descriptor() +} + +func (WhatsAppCallDirection) Type() protoreflect.EnumType { + return &file_livekit_connector_whatsapp_proto_enumTypes[0] +} + +func (x WhatsAppCallDirection) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use WhatsAppCallDirection.Descriptor instead. +func (WhatsAppCallDirection) EnumDescriptor() ([]byte, []int) { + return file_livekit_connector_whatsapp_proto_rawDescGZIP(), []int{0} +} + +type DialWhatsAppCallRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The number of the business that is initiating the call + WhatsappPhoneNumberId string `protobuf:"bytes,1,opt,name=whatsapp_phone_number_id,json=whatsappPhoneNumberId,proto3" json:"whatsapp_phone_number_id,omitempty"` + // The number of the user that is supossed to receive the call + WhatsappToPhoneNumber string `protobuf:"bytes,2,opt,name=whatsapp_to_phone_number,json=whatsappToPhoneNumber,proto3" json:"whatsapp_to_phone_number,omitempty"` + // The API key of the business that is initiating the call + WhatsappApiKey string `protobuf:"bytes,3,opt,name=whatsapp_api_key,json=whatsappApiKey,proto3" json:"whatsapp_api_key,omitempty"` + // An arbitrary string you can pass in that is useful for tracking and logging purposes. + WhatsappBizOpaqueCallbackData string `protobuf:"bytes,4,opt,name=whatsapp_biz_opaque_callback_data,json=whatsappBizOpaqueCallbackData,proto3" json:"whatsapp_biz_opaque_callback_data,omitempty"` + // What LiveKit room should this participant be connected too + RoomName string `protobuf:"bytes,5,opt,name=room_name,json=roomName,proto3" json:"room_name,omitempty"` + // Optional agents to dispatch the call to + Agents []*RoomAgentDispatch `protobuf:"bytes,6,rep,name=agents,proto3" json:"agents,omitempty"` + // Optional identity of the participant in LiveKit room + ParticipantIdentity string `protobuf:"bytes,7,opt,name=participant_identity,json=participantIdentity,proto3" json:"participant_identity,omitempty"` + // Optional name of the participant in LiveKit room + ParticipantName string `protobuf:"bytes,8,opt,name=participant_name,json=participantName,proto3" json:"participant_name,omitempty"` + // Optional user-defined metadata. Will be attached to a created Participant in the room. + ParticipantMetadata string `protobuf:"bytes,9,opt,name=participant_metadata,json=participantMetadata,proto3" json:"participant_metadata,omitempty"` + // Optional user-defined attributes. Will be attached to a created Participant in the room. + ParticipantAttributes map[string]string `protobuf:"bytes,10,rep,name=participant_attributes,json=participantAttributes,proto3" json:"participant_attributes,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + // Country where the call terminates as ISO 3166-1 alpha-2 (https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2). This will be used by the livekit infrastructure to route calls. + DestinationCountry string `protobuf:"bytes,11,opt,name=destination_country,json=destinationCountry,proto3" json:"destination_country,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DialWhatsAppCallRequest) Reset() { + *x = DialWhatsAppCallRequest{} + mi := &file_livekit_connector_whatsapp_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DialWhatsAppCallRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DialWhatsAppCallRequest) ProtoMessage() {} + +func (x *DialWhatsAppCallRequest) ProtoReflect() protoreflect.Message { + mi := &file_livekit_connector_whatsapp_proto_msgTypes[0] + 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 DialWhatsAppCallRequest.ProtoReflect.Descriptor instead. +func (*DialWhatsAppCallRequest) Descriptor() ([]byte, []int) { + return file_livekit_connector_whatsapp_proto_rawDescGZIP(), []int{0} +} + +func (x *DialWhatsAppCallRequest) GetWhatsappPhoneNumberId() string { + if x != nil { + return x.WhatsappPhoneNumberId + } + return "" +} + +func (x *DialWhatsAppCallRequest) GetWhatsappToPhoneNumber() string { + if x != nil { + return x.WhatsappToPhoneNumber + } + return "" +} + +func (x *DialWhatsAppCallRequest) GetWhatsappApiKey() string { + if x != nil { + return x.WhatsappApiKey + } + return "" +} + +func (x *DialWhatsAppCallRequest) GetWhatsappBizOpaqueCallbackData() string { + if x != nil { + return x.WhatsappBizOpaqueCallbackData + } + return "" +} + +func (x *DialWhatsAppCallRequest) GetRoomName() string { + if x != nil { + return x.RoomName + } + return "" +} + +func (x *DialWhatsAppCallRequest) GetAgents() []*RoomAgentDispatch { + if x != nil { + return x.Agents + } + return nil +} + +func (x *DialWhatsAppCallRequest) GetParticipantIdentity() string { + if x != nil { + return x.ParticipantIdentity + } + return "" +} + +func (x *DialWhatsAppCallRequest) GetParticipantName() string { + if x != nil { + return x.ParticipantName + } + return "" +} + +func (x *DialWhatsAppCallRequest) GetParticipantMetadata() string { + if x != nil { + return x.ParticipantMetadata + } + return "" +} + +func (x *DialWhatsAppCallRequest) GetParticipantAttributes() map[string]string { + if x != nil { + return x.ParticipantAttributes + } + return nil +} + +func (x *DialWhatsAppCallRequest) GetDestinationCountry() string { + if x != nil { + return x.DestinationCountry + } + return "" +} + +type DialWhatsAppCallResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Call ID sent by Meta + WhatsappCallId string `protobuf:"bytes,1,opt,name=whatsapp_call_id,json=whatsappCallId,proto3" json:"whatsapp_call_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DialWhatsAppCallResponse) Reset() { + *x = DialWhatsAppCallResponse{} + mi := &file_livekit_connector_whatsapp_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DialWhatsAppCallResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DialWhatsAppCallResponse) ProtoMessage() {} + +func (x *DialWhatsAppCallResponse) ProtoReflect() protoreflect.Message { + mi := &file_livekit_connector_whatsapp_proto_msgTypes[1] + 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 DialWhatsAppCallResponse.ProtoReflect.Descriptor instead. +func (*DialWhatsAppCallResponse) Descriptor() ([]byte, []int) { + return file_livekit_connector_whatsapp_proto_rawDescGZIP(), []int{1} +} + +func (x *DialWhatsAppCallResponse) GetWhatsappCallId() string { + if x != nil { + return x.WhatsappCallId + } + return "" +} + +type DisconnectWhatsAppCallRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Call ID sent by Meta + WhatsappCallId string `protobuf:"bytes,1,opt,name=whatsapp_call_id,json=whatsappCallId,proto3" json:"whatsapp_call_id,omitempty"` + WhatsappApiKey string `protobuf:"bytes,2,opt,name=whatsapp_api_key,json=whatsappApiKey,proto3" json:"whatsapp_api_key,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DisconnectWhatsAppCallRequest) Reset() { + *x = DisconnectWhatsAppCallRequest{} + mi := &file_livekit_connector_whatsapp_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DisconnectWhatsAppCallRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DisconnectWhatsAppCallRequest) ProtoMessage() {} + +func (x *DisconnectWhatsAppCallRequest) ProtoReflect() protoreflect.Message { + mi := &file_livekit_connector_whatsapp_proto_msgTypes[2] + 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 DisconnectWhatsAppCallRequest.ProtoReflect.Descriptor instead. +func (*DisconnectWhatsAppCallRequest) Descriptor() ([]byte, []int) { + return file_livekit_connector_whatsapp_proto_rawDescGZIP(), []int{2} +} + +func (x *DisconnectWhatsAppCallRequest) GetWhatsappCallId() string { + if x != nil { + return x.WhatsappCallId + } + return "" +} + +func (x *DisconnectWhatsAppCallRequest) GetWhatsappApiKey() string { + if x != nil { + return x.WhatsappApiKey + } + return "" +} + +type DisconnectWhatsAppCallResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DisconnectWhatsAppCallResponse) Reset() { + *x = DisconnectWhatsAppCallResponse{} + mi := &file_livekit_connector_whatsapp_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DisconnectWhatsAppCallResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DisconnectWhatsAppCallResponse) ProtoMessage() {} + +func (x *DisconnectWhatsAppCallResponse) ProtoReflect() protoreflect.Message { + mi := &file_livekit_connector_whatsapp_proto_msgTypes[3] + 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 DisconnectWhatsAppCallResponse.ProtoReflect.Descriptor instead. +func (*DisconnectWhatsAppCallResponse) Descriptor() ([]byte, []int) { + return file_livekit_connector_whatsapp_proto_rawDescGZIP(), []int{3} +} + +type ConnectWhatsAppCallRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The number of the business that is conencting the call + WhatsappPhoneNumberId string `protobuf:"bytes,1,opt,name=whatsapp_phone_number_id,json=whatsappPhoneNumberId,proto3" json:"whatsapp_phone_number_id,omitempty"` + // The API key of the business that is connecting the call + WhatsappApiKey string `protobuf:"bytes,2,opt,name=whatsapp_api_key,json=whatsappApiKey,proto3" json:"whatsapp_api_key,omitempty"` + // Call ID sent by Meta + WhatsappCallId string `protobuf:"bytes,3,opt,name=whatsapp_call_id,json=whatsappCallId,proto3" json:"whatsapp_call_id,omitempty"` + // The call connect webhook comes with SDP from Meta + // It is the answer SDP for a business initiated call + Sdp *SessionDescription `protobuf:"bytes,4,opt,name=sdp,proto3" json:"sdp,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ConnectWhatsAppCallRequest) Reset() { + *x = ConnectWhatsAppCallRequest{} + mi := &file_livekit_connector_whatsapp_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ConnectWhatsAppCallRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ConnectWhatsAppCallRequest) ProtoMessage() {} + +func (x *ConnectWhatsAppCallRequest) ProtoReflect() protoreflect.Message { + mi := &file_livekit_connector_whatsapp_proto_msgTypes[4] + 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 ConnectWhatsAppCallRequest.ProtoReflect.Descriptor instead. +func (*ConnectWhatsAppCallRequest) Descriptor() ([]byte, []int) { + return file_livekit_connector_whatsapp_proto_rawDescGZIP(), []int{4} +} + +func (x *ConnectWhatsAppCallRequest) GetWhatsappPhoneNumberId() string { + if x != nil { + return x.WhatsappPhoneNumberId + } + return "" +} + +func (x *ConnectWhatsAppCallRequest) GetWhatsappApiKey() string { + if x != nil { + return x.WhatsappApiKey + } + return "" +} + +func (x *ConnectWhatsAppCallRequest) GetWhatsappCallId() string { + if x != nil { + return x.WhatsappCallId + } + return "" +} + +func (x *ConnectWhatsAppCallRequest) GetSdp() *SessionDescription { + if x != nil { + return x.Sdp + } + return nil +} + +type ConnectWhatsAppCallResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ConnectWhatsAppCallResponse) Reset() { + *x = ConnectWhatsAppCallResponse{} + mi := &file_livekit_connector_whatsapp_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ConnectWhatsAppCallResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ConnectWhatsAppCallResponse) ProtoMessage() {} + +func (x *ConnectWhatsAppCallResponse) ProtoReflect() protoreflect.Message { + mi := &file_livekit_connector_whatsapp_proto_msgTypes[5] + 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 ConnectWhatsAppCallResponse.ProtoReflect.Descriptor instead. +func (*ConnectWhatsAppCallResponse) Descriptor() ([]byte, []int) { + return file_livekit_connector_whatsapp_proto_rawDescGZIP(), []int{5} +} + +type AcceptWhatsAppCallRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The number of the business that is conencting the call + WhatsappPhoneNumberId string `protobuf:"bytes,1,opt,name=whatsapp_phone_number_id,json=whatsappPhoneNumberId,proto3" json:"whatsapp_phone_number_id,omitempty"` + // The API key of the business that is connecting the call + WhatsappApiKey string `protobuf:"bytes,2,opt,name=whatsapp_api_key,json=whatsappApiKey,proto3" json:"whatsapp_api_key,omitempty"` + // Call ID sent by Meta + WhatsappCallId string `protobuf:"bytes,3,opt,name=whatsapp_call_id,json=whatsappCallId,proto3" json:"whatsapp_call_id,omitempty"` + // An arbitrary string you can pass in that is useful for tracking and logging purposes. + WhatsappBizOpaqueCallbackData string `protobuf:"bytes,4,opt,name=whatsapp_biz_opaque_callback_data,json=whatsappBizOpaqueCallbackData,proto3" json:"whatsapp_biz_opaque_callback_data,omitempty"` + // The call accept webhook comes with SDP from Meta + // It is the for a user initiated call + Sdp *SessionDescription `protobuf:"bytes,5,opt,name=sdp,proto3" json:"sdp,omitempty"` + // What LiveKit room should this participant be connected too + RoomName string `protobuf:"bytes,6,opt,name=room_name,json=roomName,proto3" json:"room_name,omitempty"` + // Optional agents to dispatch the call to + Agents []*RoomAgentDispatch `protobuf:"bytes,7,rep,name=agents,proto3" json:"agents,omitempty"` + // Optional identity of the participant in LiveKit room + ParticipantIdentity string `protobuf:"bytes,8,opt,name=participant_identity,json=participantIdentity,proto3" json:"participant_identity,omitempty"` + // Optional name of the participant in LiveKit room + ParticipantName string `protobuf:"bytes,9,opt,name=participant_name,json=participantName,proto3" json:"participant_name,omitempty"` + // Optional user-defined metadata. Will be attached to a created Participant in the room. + ParticipantMetadata string `protobuf:"bytes,10,opt,name=participant_metadata,json=participantMetadata,proto3" json:"participant_metadata,omitempty"` + // Optional user-defined attributes. Will be attached to a created Participant in the room. + ParticipantAttributes map[string]string `protobuf:"bytes,11,rep,name=participant_attributes,json=participantAttributes,proto3" json:"participant_attributes,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + // Country where the call terminates as ISO 3166-1 alpha-2 (https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2). This will be used by the livekit infrastructure to route calls. + DestinationCountry string `protobuf:"bytes,12,opt,name=destination_country,json=destinationCountry,proto3" json:"destination_country,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *AcceptWhatsAppCallRequest) Reset() { + *x = AcceptWhatsAppCallRequest{} + mi := &file_livekit_connector_whatsapp_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *AcceptWhatsAppCallRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AcceptWhatsAppCallRequest) ProtoMessage() {} + +func (x *AcceptWhatsAppCallRequest) ProtoReflect() protoreflect.Message { + mi := &file_livekit_connector_whatsapp_proto_msgTypes[6] + 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 AcceptWhatsAppCallRequest.ProtoReflect.Descriptor instead. +func (*AcceptWhatsAppCallRequest) Descriptor() ([]byte, []int) { + return file_livekit_connector_whatsapp_proto_rawDescGZIP(), []int{6} +} + +func (x *AcceptWhatsAppCallRequest) GetWhatsappPhoneNumberId() string { + if x != nil { + return x.WhatsappPhoneNumberId + } + return "" +} + +func (x *AcceptWhatsAppCallRequest) GetWhatsappApiKey() string { + if x != nil { + return x.WhatsappApiKey + } + return "" +} + +func (x *AcceptWhatsAppCallRequest) GetWhatsappCallId() string { + if x != nil { + return x.WhatsappCallId + } + return "" +} + +func (x *AcceptWhatsAppCallRequest) GetWhatsappBizOpaqueCallbackData() string { + if x != nil { + return x.WhatsappBizOpaqueCallbackData + } + return "" +} + +func (x *AcceptWhatsAppCallRequest) GetSdp() *SessionDescription { + if x != nil { + return x.Sdp + } + return nil +} + +func (x *AcceptWhatsAppCallRequest) GetRoomName() string { + if x != nil { + return x.RoomName + } + return "" +} + +func (x *AcceptWhatsAppCallRequest) GetAgents() []*RoomAgentDispatch { + if x != nil { + return x.Agents + } + return nil +} + +func (x *AcceptWhatsAppCallRequest) GetParticipantIdentity() string { + if x != nil { + return x.ParticipantIdentity + } + return "" +} + +func (x *AcceptWhatsAppCallRequest) GetParticipantName() string { + if x != nil { + return x.ParticipantName + } + return "" +} + +func (x *AcceptWhatsAppCallRequest) GetParticipantMetadata() string { + if x != nil { + return x.ParticipantMetadata + } + return "" +} + +func (x *AcceptWhatsAppCallRequest) GetParticipantAttributes() map[string]string { + if x != nil { + return x.ParticipantAttributes + } + return nil +} + +func (x *AcceptWhatsAppCallRequest) GetDestinationCountry() string { + if x != nil { + return x.DestinationCountry + } + return "" +} + +type AcceptWhatsAppCallResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *AcceptWhatsAppCallResponse) Reset() { + *x = AcceptWhatsAppCallResponse{} + mi := &file_livekit_connector_whatsapp_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *AcceptWhatsAppCallResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AcceptWhatsAppCallResponse) ProtoMessage() {} + +func (x *AcceptWhatsAppCallResponse) ProtoReflect() protoreflect.Message { + mi := &file_livekit_connector_whatsapp_proto_msgTypes[7] + 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 AcceptWhatsAppCallResponse.ProtoReflect.Descriptor instead. +func (*AcceptWhatsAppCallResponse) Descriptor() ([]byte, []int) { + return file_livekit_connector_whatsapp_proto_rawDescGZIP(), []int{7} +} + +type WhatsAppCall struct { + state protoimpl.MessageState `protogen:"open.v1"` + // list of call ids that are currently active + WhatsappCallId string `protobuf:"bytes,1,opt,name=whatsapp_call_id,json=whatsappCallId,proto3" json:"whatsapp_call_id,omitempty"` + // Direction of the call + Direction WhatsAppCallDirection `protobuf:"varint,2,opt,name=direction,proto3,enum=livekit.WhatsAppCallDirection" json:"direction,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *WhatsAppCall) Reset() { + *x = WhatsAppCall{} + mi := &file_livekit_connector_whatsapp_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *WhatsAppCall) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*WhatsAppCall) ProtoMessage() {} + +func (x *WhatsAppCall) ProtoReflect() protoreflect.Message { + mi := &file_livekit_connector_whatsapp_proto_msgTypes[8] + 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 WhatsAppCall.ProtoReflect.Descriptor instead. +func (*WhatsAppCall) Descriptor() ([]byte, []int) { + return file_livekit_connector_whatsapp_proto_rawDescGZIP(), []int{8} +} + +func (x *WhatsAppCall) GetWhatsappCallId() string { + if x != nil { + return x.WhatsappCallId + } + return "" +} + +func (x *WhatsAppCall) GetDirection() WhatsAppCallDirection { + if x != nil { + return x.Direction + } + return WhatsAppCallDirection_WHATSAPP_CALL_DIRECTION_INBOUND +} + +var File_livekit_connector_whatsapp_proto protoreflect.FileDescriptor + +const file_livekit_connector_whatsapp_proto_rawDesc = "" + + "\n" + + " livekit_connector_whatsapp.proto\x12\alivekit\x1a\x1clivekit_agent_dispatch.proto\x1a\x11livekit_rtc.proto\"\xd0\x05\n" + + "\x17DialWhatsAppCallRequest\x127\n" + + "\x18whatsapp_phone_number_id\x18\x01 \x01(\tR\x15whatsappPhoneNumberId\x127\n" + + "\x18whatsapp_to_phone_number\x18\x02 \x01(\tR\x15whatsappToPhoneNumber\x12(\n" + + "\x10whatsapp_api_key\x18\x03 \x01(\tR\x0ewhatsappApiKey\x12H\n" + + "!whatsapp_biz_opaque_callback_data\x18\x04 \x01(\tR\x1dwhatsappBizOpaqueCallbackData\x12\x1b\n" + + "\troom_name\x18\x05 \x01(\tR\broomName\x122\n" + + "\x06agents\x18\x06 \x03(\v2\x1a.livekit.RoomAgentDispatchR\x06agents\x121\n" + + "\x14participant_identity\x18\a \x01(\tR\x13participantIdentity\x12)\n" + + "\x10participant_name\x18\b \x01(\tR\x0fparticipantName\x121\n" + + "\x14participant_metadata\x18\t \x01(\tR\x13participantMetadata\x12r\n" + + "\x16participant_attributes\x18\n" + + " \x03(\v2;.livekit.DialWhatsAppCallRequest.ParticipantAttributesEntryR\x15participantAttributes\x12/\n" + + "\x13destination_country\x18\v \x01(\tR\x12destinationCountry\x1aH\n" + + "\x1aParticipantAttributesEntry\x12\x10\n" + + "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + + "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"D\n" + + "\x18DialWhatsAppCallResponse\x12(\n" + + "\x10whatsapp_call_id\x18\x01 \x01(\tR\x0ewhatsappCallId\"s\n" + + "\x1dDisconnectWhatsAppCallRequest\x12(\n" + + "\x10whatsapp_call_id\x18\x01 \x01(\tR\x0ewhatsappCallId\x12(\n" + + "\x10whatsapp_api_key\x18\x02 \x01(\tR\x0ewhatsappApiKey\" \n" + + "\x1eDisconnectWhatsAppCallResponse\"\xd8\x01\n" + + "\x1aConnectWhatsAppCallRequest\x127\n" + + "\x18whatsapp_phone_number_id\x18\x01 \x01(\tR\x15whatsappPhoneNumberId\x12(\n" + + "\x10whatsapp_api_key\x18\x02 \x01(\tR\x0ewhatsappApiKey\x12(\n" + + "\x10whatsapp_call_id\x18\x03 \x01(\tR\x0ewhatsappCallId\x12-\n" + + "\x03sdp\x18\x04 \x01(\v2\x1b.livekit.SessionDescriptionR\x03sdp\"\x1d\n" + + "\x1bConnectWhatsAppCallResponse\"\xf4\x05\n" + + "\x19AcceptWhatsAppCallRequest\x127\n" + + "\x18whatsapp_phone_number_id\x18\x01 \x01(\tR\x15whatsappPhoneNumberId\x12(\n" + + "\x10whatsapp_api_key\x18\x02 \x01(\tR\x0ewhatsappApiKey\x12(\n" + + "\x10whatsapp_call_id\x18\x03 \x01(\tR\x0ewhatsappCallId\x12H\n" + + "!whatsapp_biz_opaque_callback_data\x18\x04 \x01(\tR\x1dwhatsappBizOpaqueCallbackData\x12-\n" + + "\x03sdp\x18\x05 \x01(\v2\x1b.livekit.SessionDescriptionR\x03sdp\x12\x1b\n" + + "\troom_name\x18\x06 \x01(\tR\broomName\x122\n" + + "\x06agents\x18\a \x03(\v2\x1a.livekit.RoomAgentDispatchR\x06agents\x121\n" + + "\x14participant_identity\x18\b \x01(\tR\x13participantIdentity\x12)\n" + + "\x10participant_name\x18\t \x01(\tR\x0fparticipantName\x121\n" + + "\x14participant_metadata\x18\n" + + " \x01(\tR\x13participantMetadata\x12t\n" + + "\x16participant_attributes\x18\v \x03(\v2=.livekit.AcceptWhatsAppCallRequest.ParticipantAttributesEntryR\x15participantAttributes\x12/\n" + + "\x13destination_country\x18\f \x01(\tR\x12destinationCountry\x1aH\n" + + "\x1aParticipantAttributesEntry\x12\x10\n" + + "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + + "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"\x1c\n" + + "\x1aAcceptWhatsAppCallResponse\"v\n" + + "\fWhatsAppCall\x12(\n" + + "\x10whatsapp_call_id\x18\x01 \x01(\tR\x0ewhatsappCallId\x12<\n" + + "\tdirection\x18\x02 \x01(\x0e2\x1e.livekit.WhatsAppCallDirectionR\tdirection*b\n" + + "\x15WhatsAppCallDirection\x12#\n" + + "\x1fWHATSAPP_CALL_DIRECTION_INBOUND\x10\x00\x12$\n" + + " WHATSAPP_CALL_DIRECTION_OUTBOUND\x10\x02BFZ#github.com/livekit/protocol/livekit\xaa\x02\rLiveKit.Proto\xea\x02\x0eLiveKit::Protob\x06proto3" + +var ( + file_livekit_connector_whatsapp_proto_rawDescOnce sync.Once + file_livekit_connector_whatsapp_proto_rawDescData []byte +) + +func file_livekit_connector_whatsapp_proto_rawDescGZIP() []byte { + file_livekit_connector_whatsapp_proto_rawDescOnce.Do(func() { + file_livekit_connector_whatsapp_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_livekit_connector_whatsapp_proto_rawDesc), len(file_livekit_connector_whatsapp_proto_rawDesc))) + }) + return file_livekit_connector_whatsapp_proto_rawDescData +} + +var file_livekit_connector_whatsapp_proto_enumTypes = make([]protoimpl.EnumInfo, 1) +var file_livekit_connector_whatsapp_proto_msgTypes = make([]protoimpl.MessageInfo, 11) +var file_livekit_connector_whatsapp_proto_goTypes = []any{ + (WhatsAppCallDirection)(0), // 0: livekit.WhatsAppCallDirection + (*DialWhatsAppCallRequest)(nil), // 1: livekit.DialWhatsAppCallRequest + (*DialWhatsAppCallResponse)(nil), // 2: livekit.DialWhatsAppCallResponse + (*DisconnectWhatsAppCallRequest)(nil), // 3: livekit.DisconnectWhatsAppCallRequest + (*DisconnectWhatsAppCallResponse)(nil), // 4: livekit.DisconnectWhatsAppCallResponse + (*ConnectWhatsAppCallRequest)(nil), // 5: livekit.ConnectWhatsAppCallRequest + (*ConnectWhatsAppCallResponse)(nil), // 6: livekit.ConnectWhatsAppCallResponse + (*AcceptWhatsAppCallRequest)(nil), // 7: livekit.AcceptWhatsAppCallRequest + (*AcceptWhatsAppCallResponse)(nil), // 8: livekit.AcceptWhatsAppCallResponse + (*WhatsAppCall)(nil), // 9: livekit.WhatsAppCall + nil, // 10: livekit.DialWhatsAppCallRequest.ParticipantAttributesEntry + nil, // 11: livekit.AcceptWhatsAppCallRequest.ParticipantAttributesEntry + (*RoomAgentDispatch)(nil), // 12: livekit.RoomAgentDispatch + (*SessionDescription)(nil), // 13: livekit.SessionDescription +} +var file_livekit_connector_whatsapp_proto_depIdxs = []int32{ + 12, // 0: livekit.DialWhatsAppCallRequest.agents:type_name -> livekit.RoomAgentDispatch + 10, // 1: livekit.DialWhatsAppCallRequest.participant_attributes:type_name -> livekit.DialWhatsAppCallRequest.ParticipantAttributesEntry + 13, // 2: livekit.ConnectWhatsAppCallRequest.sdp:type_name -> livekit.SessionDescription + 13, // 3: livekit.AcceptWhatsAppCallRequest.sdp:type_name -> livekit.SessionDescription + 12, // 4: livekit.AcceptWhatsAppCallRequest.agents:type_name -> livekit.RoomAgentDispatch + 11, // 5: livekit.AcceptWhatsAppCallRequest.participant_attributes:type_name -> livekit.AcceptWhatsAppCallRequest.ParticipantAttributesEntry + 0, // 6: livekit.WhatsAppCall.direction:type_name -> livekit.WhatsAppCallDirection + 7, // [7:7] is the sub-list for method output_type + 7, // [7:7] is the sub-list for method input_type + 7, // [7:7] is the sub-list for extension type_name + 7, // [7:7] is the sub-list for extension extendee + 0, // [0:7] is the sub-list for field type_name +} + +func init() { file_livekit_connector_whatsapp_proto_init() } +func file_livekit_connector_whatsapp_proto_init() { + if File_livekit_connector_whatsapp_proto != nil { + return + } + file_livekit_agent_dispatch_proto_init() + file_livekit_rtc_proto_init() + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_livekit_connector_whatsapp_proto_rawDesc), len(file_livekit_connector_whatsapp_proto_rawDesc)), + NumEnums: 1, + NumMessages: 11, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_livekit_connector_whatsapp_proto_goTypes, + DependencyIndexes: file_livekit_connector_whatsapp_proto_depIdxs, + EnumInfos: file_livekit_connector_whatsapp_proto_enumTypes, + MessageInfos: file_livekit_connector_whatsapp_proto_msgTypes, + }.Build() + File_livekit_connector_whatsapp_proto = out.File + file_livekit_connector_whatsapp_proto_goTypes = nil + file_livekit_connector_whatsapp_proto_depIdxs = nil +} diff --git a/livekit/livekit_models.pb.go b/livekit/livekit_models.pb.go index 08d7669..b8ee70f 100644 --- a/livekit/livekit_models.pb.go +++ b/livekit/livekit_models.pb.go @@ -837,6 +837,8 @@ const ( ParticipantInfo_SIP ParticipantInfo_Kind = 3 // LiveKit agents ParticipantInfo_AGENT ParticipantInfo_Kind = 4 + // Connectors participants + ParticipantInfo_CONNECTOR ParticipantInfo_Kind = 7 // NEXT_ID: 8 ) // Enum value maps for ParticipantInfo_Kind. @@ -847,13 +849,15 @@ var ( 2: "EGRESS", 3: "SIP", 4: "AGENT", + 7: "CONNECTOR", } ParticipantInfo_Kind_value = map[string]int32{ - "STANDARD": 0, - "INGRESS": 1, - "EGRESS": 2, - "SIP": 3, - "AGENT": 4, + "STANDARD": 0, + "INGRESS": 1, + "EGRESS": 2, + "SIP": 3, + "AGENT": 4, + "CONNECTOR": 7, } ) @@ -5808,7 +5812,7 @@ const file_livekit_models_proto_rawDesc = "" + "\x13can_update_metadata\x18\n" + " \x01(\bR\x11canUpdateMetadata\x12\x18\n" + "\x05agent\x18\v \x01(\bB\x02\x18\x01R\x05agent\x122\n" + - "\x15can_subscribe_metrics\x18\f \x01(\bR\x13canSubscribeMetrics\"\xa2\a\n" + + "\x15can_subscribe_metrics\x18\f \x01(\bR\x13canSubscribeMetrics\"\xb1\a\n" + "\x0fParticipantInfo\x12\x10\n" + "\x03sid\x18\x01 \x01(\tR\x03sid\x12\x1a\n" + "\bidentity\x18\x02 \x01(\tR\bidentity\x124\n" + @@ -5841,14 +5845,15 @@ const file_livekit_models_proto_rawDesc = "" + "\x06JOINED\x10\x01\x12\n" + "\n" + "\x06ACTIVE\x10\x02\x12\x10\n" + - "\fDISCONNECTED\x10\x03\"A\n" + + "\fDISCONNECTED\x10\x03\"P\n" + "\x04Kind\x12\f\n" + "\bSTANDARD\x10\x00\x12\v\n" + "\aINGRESS\x10\x01\x12\n" + "\n" + "\x06EGRESS\x10\x02\x12\a\n" + "\x03SIP\x10\x03\x12\t\n" + - "\x05AGENT\x10\x04\",\n" + + "\x05AGENT\x10\x04\x12\r\n" + + "\tCONNECTOR\x10\a\",\n" + "\n" + "KindDetail\x12\x0f\n" + "\vCLOUD_AGENT\x10\x00\x12\r\n" + diff --git a/magefile.go b/magefile.go index 54d32be..ab1eebf 100644 --- a/magefile.go +++ b/magefile.go @@ -50,6 +50,8 @@ func Proto() error { "livekit_sip.proto", "livekit_cloud_agent.proto", "livekit_phone_number.proto", + "livekit_connector.proto", + "livekit_connector_whatsapp.proto", } agentProtoFiles := []string{ @@ -83,6 +85,8 @@ func Proto() error { "rpc/signal.proto", "rpc/whip_signal.proto", "rpc/sip.proto", + "rpc/connector.proto", + "rpc/common.proto", } fmt.Println("generating protobuf") diff --git a/protobufs/livekit_connector.proto b/protobufs/livekit_connector.proto new file mode 100644 index 0000000..c537572 --- /dev/null +++ b/protobufs/livekit_connector.proto @@ -0,0 +1,32 @@ +// Copyright 2025 LiveKit, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package livekit; +option go_package = "github.com/livekit/protocol/livekit"; +option csharp_namespace = "LiveKit.Proto"; +option ruby_package = "LiveKit::Proto"; + +import "livekit_connector_whatsapp.proto"; + +service Connector { + rpc DialWhatsAppCall(DialWhatsAppCallRequest) returns (DialWhatsAppCallResponse); + + rpc DisconnectWhatsAppCall(DisconnectWhatsAppCallRequest) returns (DisconnectWhatsAppCallResponse); + + rpc ConnectWhatsAppCall(ConnectWhatsAppCallRequest) returns (ConnectWhatsAppCallResponse); + + rpc AcceptWhatsAppCall(AcceptWhatsAppCallRequest) returns (AcceptWhatsAppCallResponse); +} \ No newline at end of file diff --git a/protobufs/livekit_connector_whatsapp.proto b/protobufs/livekit_connector_whatsapp.proto new file mode 100644 index 0000000..40b8cc0 --- /dev/null +++ b/protobufs/livekit_connector_whatsapp.proto @@ -0,0 +1,121 @@ +// Copyright 2025 LiveKit, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package livekit; +option go_package = "github.com/livekit/protocol/livekit"; +option csharp_namespace = "LiveKit.Proto"; +option ruby_package = "LiveKit::Proto"; + +import "livekit_agent_dispatch.proto"; +import "livekit_rtc.proto"; + +message DialWhatsAppCallRequest { + // The number of the business that is initiating the call + string whatsapp_phone_number_id = 1; + // The number of the user that is supossed to receive the call + string whatsapp_to_phone_number = 2; + // The API key of the business that is initiating the call + string whatsapp_api_key = 3; + // An arbitrary string you can pass in that is useful for tracking and logging purposes. + string whatsapp_biz_opaque_callback_data = 4; + // What LiveKit room should this participant be connected too + string room_name = 5; + // Optional agents to dispatch the call to + repeated RoomAgentDispatch agents = 6; + // Optional identity of the participant in LiveKit room + string participant_identity= 7; + // Optional name of the participant in LiveKit room + string participant_name = 8; + // Optional user-defined metadata. Will be attached to a created Participant in the room. + string participant_metadata = 9; + // Optional user-defined attributes. Will be attached to a created Participant in the room. + map participant_attributes = 10; + // Country where the call terminates as ISO 3166-1 alpha-2 (https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2). This will be used by the livekit infrastructure to route calls. + string destination_country = 11; +} + +message DialWhatsAppCallResponse { + // Call ID sent by Meta + string whatsapp_call_id = 1; +} + +message DisconnectWhatsAppCallRequest { + // Call ID sent by Meta + string whatsapp_call_id = 1; + string whatsapp_api_key = 2; +} + +message DisconnectWhatsAppCallResponse { +} + +message ConnectWhatsAppCallRequest { + // The number of the business that is conencting the call + string whatsapp_phone_number_id = 1; + // The API key of the business that is connecting the call + string whatsapp_api_key = 2; + // Call ID sent by Meta + string whatsapp_call_id = 3; + // The call connect webhook comes with SDP from Meta + // It is the answer SDP for a business initiated call + SessionDescription sdp = 4; +} + +message ConnectWhatsAppCallResponse { +} + +message AcceptWhatsAppCallRequest { + // The number of the business that is conencting the call + string whatsapp_phone_number_id = 1; + // The API key of the business that is connecting the call + string whatsapp_api_key = 2; + // Call ID sent by Meta + string whatsapp_call_id = 3; + // An arbitrary string you can pass in that is useful for tracking and logging purposes. + string whatsapp_biz_opaque_callback_data = 4; + // The call accept webhook comes with SDP from Meta + // It is the for a user initiated call + SessionDescription sdp = 5; + // What LiveKit room should this participant be connected too + string room_name = 6; + // Optional agents to dispatch the call to + repeated RoomAgentDispatch agents = 7; + // Optional identity of the participant in LiveKit room + string participant_identity= 8; + // Optional name of the participant in LiveKit room + string participant_name = 9; + // Optional user-defined metadata. Will be attached to a created Participant in the room. + string participant_metadata = 10; + // Optional user-defined attributes. Will be attached to a created Participant in the room. + map participant_attributes = 11; + // Country where the call terminates as ISO 3166-1 alpha-2 (https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2). This will be used by the livekit infrastructure to route calls. + string destination_country = 12; + +} + +message AcceptWhatsAppCallResponse { +} + +message WhatsAppCall { + // list of call ids that are currently active + string whatsapp_call_id = 1; + // Direction of the call + WhatsAppCallDirection direction = 2; +} + +enum WhatsAppCallDirection { + WHATSAPP_CALL_DIRECTION_INBOUND = 0; + WHATSAPP_CALL_DIRECTION_OUTBOUND = 2; +} \ No newline at end of file diff --git a/protobufs/livekit_models.proto b/protobufs/livekit_models.proto index 94bf6be..05aa115 100644 --- a/protobufs/livekit_models.proto +++ b/protobufs/livekit_models.proto @@ -148,8 +148,9 @@ message ParticipantInfo { SIP = 3; // LiveKit agents AGENT = 4; - - // NEXT_ID: 7 + // Connectors participants + CONNECTOR = 7; + // NEXT_ID: 8 } enum KindDetail { CLOUD_AGENT = 0; diff --git a/protobufs/rpc/common.proto b/protobufs/rpc/common.proto new file mode 100644 index 0000000..997e020 --- /dev/null +++ b/protobufs/rpc/common.proto @@ -0,0 +1,25 @@ +// Copyright 2025 LiveKit, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package rpc; + +option go_package = "github.com/livekit/protocol/rpc"; + +message InternalRoomJoinInfo { + string ws_url = 1; + string token = 2; + string project_id = 3; +} \ No newline at end of file diff --git a/protobufs/rpc/connector.proto b/protobufs/rpc/connector.proto new file mode 100644 index 0000000..a1d78a4 --- /dev/null +++ b/protobufs/rpc/connector.proto @@ -0,0 +1,65 @@ +// Copyright 2025 LiveKit, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package rpc; + +option go_package = "github.com/livekit/protocol/rpc"; + +import "options.proto"; +import "livekit_connector_whatsapp.proto"; +import "rpc/common.proto"; + +service ConnectorInternal { + rpc DialWhatsAppCall(InternalDialWhatsAppCallRequest) returns (livekit.DialWhatsAppCallResponse) { + option (psrpc.options).topics = true; + }; + + rpc AcceptWhatsAppCall(InternalAcceptWhatsAppCallRequest) returns (livekit.AcceptWhatsAppCallResponse) { + option (psrpc.options).topics = true; + }; +} + +service ConnectorHandler { + rpc ConnectWhatsAppCall(livekit.ConnectWhatsAppCallRequest) returns (livekit.ConnectWhatsAppCallResponse) { + option (psrpc.options) = { + topics: true + topic_params: { + names: ["whatsapp_call_id"] + typed: false + } + }; + }; + + rpc DisconnectWhatsAppCall(livekit.DisconnectWhatsAppCallRequest) returns (livekit.DisconnectWhatsAppCallResponse) { + option (psrpc.options) = { + topics: true + topic_params: { + names: ["whatsapp_call_id"] + typed: false + } + }; + }; +} + +message InternalDialWhatsAppCallRequest { + livekit.DialWhatsAppCallRequest request = 1; + InternalRoomJoinInfo room_join_info = 2; +} + +message InternalAcceptWhatsAppCallRequest { + livekit.AcceptWhatsAppCallRequest request = 1; + InternalRoomJoinInfo room_join_info = 2; +} \ No newline at end of file diff --git a/rpc/common.pb.go b/rpc/common.pb.go new file mode 100644 index 0000000..2cbf629 --- /dev/null +++ b/rpc/common.pb.go @@ -0,0 +1,155 @@ +// Copyright 2025 LiveKit, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.10 +// protoc v4.23.4 +// source: rpc/common.proto + +package rpc + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type InternalRoomJoinInfo struct { + state protoimpl.MessageState `protogen:"open.v1"` + WsUrl string `protobuf:"bytes,1,opt,name=ws_url,json=wsUrl,proto3" json:"ws_url,omitempty"` + Token string `protobuf:"bytes,2,opt,name=token,proto3" json:"token,omitempty"` + ProjectId string `protobuf:"bytes,3,opt,name=project_id,json=projectId,proto3" json:"project_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *InternalRoomJoinInfo) Reset() { + *x = InternalRoomJoinInfo{} + mi := &file_rpc_common_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *InternalRoomJoinInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*InternalRoomJoinInfo) ProtoMessage() {} + +func (x *InternalRoomJoinInfo) ProtoReflect() protoreflect.Message { + mi := &file_rpc_common_proto_msgTypes[0] + 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 InternalRoomJoinInfo.ProtoReflect.Descriptor instead. +func (*InternalRoomJoinInfo) Descriptor() ([]byte, []int) { + return file_rpc_common_proto_rawDescGZIP(), []int{0} +} + +func (x *InternalRoomJoinInfo) GetWsUrl() string { + if x != nil { + return x.WsUrl + } + return "" +} + +func (x *InternalRoomJoinInfo) GetToken() string { + if x != nil { + return x.Token + } + return "" +} + +func (x *InternalRoomJoinInfo) GetProjectId() string { + if x != nil { + return x.ProjectId + } + return "" +} + +var File_rpc_common_proto protoreflect.FileDescriptor + +const file_rpc_common_proto_rawDesc = "" + + "\n" + + "\x10rpc/common.proto\x12\x03rpc\"b\n" + + "\x14InternalRoomJoinInfo\x12\x15\n" + + "\x06ws_url\x18\x01 \x01(\tR\x05wsUrl\x12\x14\n" + + "\x05token\x18\x02 \x01(\tR\x05token\x12\x1d\n" + + "\n" + + "project_id\x18\x03 \x01(\tR\tprojectIdB!Z\x1fgithub.com/livekit/protocol/rpcb\x06proto3" + +var ( + file_rpc_common_proto_rawDescOnce sync.Once + file_rpc_common_proto_rawDescData []byte +) + +func file_rpc_common_proto_rawDescGZIP() []byte { + file_rpc_common_proto_rawDescOnce.Do(func() { + file_rpc_common_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_rpc_common_proto_rawDesc), len(file_rpc_common_proto_rawDesc))) + }) + return file_rpc_common_proto_rawDescData +} + +var file_rpc_common_proto_msgTypes = make([]protoimpl.MessageInfo, 1) +var file_rpc_common_proto_goTypes = []any{ + (*InternalRoomJoinInfo)(nil), // 0: rpc.InternalRoomJoinInfo +} +var file_rpc_common_proto_depIdxs = []int32{ + 0, // [0:0] is the sub-list for method output_type + 0, // [0:0] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name +} + +func init() { file_rpc_common_proto_init() } +func file_rpc_common_proto_init() { + if File_rpc_common_proto != nil { + return + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_rpc_common_proto_rawDesc), len(file_rpc_common_proto_rawDesc)), + NumEnums: 0, + NumMessages: 1, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_rpc_common_proto_goTypes, + DependencyIndexes: file_rpc_common_proto_depIdxs, + MessageInfos: file_rpc_common_proto_msgTypes, + }.Build() + File_rpc_common_proto = out.File + file_rpc_common_proto_goTypes = nil + file_rpc_common_proto_depIdxs = nil +} diff --git a/rpc/connector.pb.go b/rpc/connector.pb.go new file mode 100644 index 0000000..0cff5ad --- /dev/null +++ b/rpc/connector.pb.go @@ -0,0 +1,231 @@ +// Copyright 2025 LiveKit, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.10 +// protoc v4.23.4 +// source: rpc/connector.proto + +package rpc + +import ( + livekit "github.com/livekit/protocol/livekit" + _ "github.com/livekit/psrpc/protoc-gen-psrpc/options" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type InternalDialWhatsAppCallRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Request *livekit.DialWhatsAppCallRequest `protobuf:"bytes,1,opt,name=request,proto3" json:"request,omitempty"` + RoomJoinInfo *InternalRoomJoinInfo `protobuf:"bytes,2,opt,name=room_join_info,json=roomJoinInfo,proto3" json:"room_join_info,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *InternalDialWhatsAppCallRequest) Reset() { + *x = InternalDialWhatsAppCallRequest{} + mi := &file_rpc_connector_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *InternalDialWhatsAppCallRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*InternalDialWhatsAppCallRequest) ProtoMessage() {} + +func (x *InternalDialWhatsAppCallRequest) ProtoReflect() protoreflect.Message { + mi := &file_rpc_connector_proto_msgTypes[0] + 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 InternalDialWhatsAppCallRequest.ProtoReflect.Descriptor instead. +func (*InternalDialWhatsAppCallRequest) Descriptor() ([]byte, []int) { + return file_rpc_connector_proto_rawDescGZIP(), []int{0} +} + +func (x *InternalDialWhatsAppCallRequest) GetRequest() *livekit.DialWhatsAppCallRequest { + if x != nil { + return x.Request + } + return nil +} + +func (x *InternalDialWhatsAppCallRequest) GetRoomJoinInfo() *InternalRoomJoinInfo { + if x != nil { + return x.RoomJoinInfo + } + return nil +} + +type InternalAcceptWhatsAppCallRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Request *livekit.AcceptWhatsAppCallRequest `protobuf:"bytes,1,opt,name=request,proto3" json:"request,omitempty"` + RoomJoinInfo *InternalRoomJoinInfo `protobuf:"bytes,2,opt,name=room_join_info,json=roomJoinInfo,proto3" json:"room_join_info,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *InternalAcceptWhatsAppCallRequest) Reset() { + *x = InternalAcceptWhatsAppCallRequest{} + mi := &file_rpc_connector_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *InternalAcceptWhatsAppCallRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*InternalAcceptWhatsAppCallRequest) ProtoMessage() {} + +func (x *InternalAcceptWhatsAppCallRequest) ProtoReflect() protoreflect.Message { + mi := &file_rpc_connector_proto_msgTypes[1] + 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 InternalAcceptWhatsAppCallRequest.ProtoReflect.Descriptor instead. +func (*InternalAcceptWhatsAppCallRequest) Descriptor() ([]byte, []int) { + return file_rpc_connector_proto_rawDescGZIP(), []int{1} +} + +func (x *InternalAcceptWhatsAppCallRequest) GetRequest() *livekit.AcceptWhatsAppCallRequest { + if x != nil { + return x.Request + } + return nil +} + +func (x *InternalAcceptWhatsAppCallRequest) GetRoomJoinInfo() *InternalRoomJoinInfo { + if x != nil { + return x.RoomJoinInfo + } + return nil +} + +var File_rpc_connector_proto protoreflect.FileDescriptor + +const file_rpc_connector_proto_rawDesc = "" + + "\n" + + "\x13rpc/connector.proto\x12\x03rpc\x1a\roptions.proto\x1a livekit_connector_whatsapp.proto\x1a\x10rpc/common.proto\"\x9e\x01\n" + + "\x1fInternalDialWhatsAppCallRequest\x12:\n" + + "\arequest\x18\x01 \x01(\v2 .livekit.DialWhatsAppCallRequestR\arequest\x12?\n" + + "\x0eroom_join_info\x18\x02 \x01(\v2\x19.rpc.InternalRoomJoinInfoR\froomJoinInfo\"\xa2\x01\n" + + "!InternalAcceptWhatsAppCallRequest\x12<\n" + + "\arequest\x18\x01 \x01(\v2\".livekit.AcceptWhatsAppCallRequestR\arequest\x12?\n" + + "\x0eroom_join_info\x18\x02 \x01(\v2\x19.rpc.InternalRoomJoinInfoR\froomJoinInfo2\xe3\x01\n" + + "\x11ConnectorInternal\x12c\n" + + "\x10DialWhatsAppCall\x12$.rpc.InternalDialWhatsAppCallRequest\x1a!.livekit.DialWhatsAppCallResponse\"\x06\xb2\x89\x01\x02\x10\x01\x12i\n" + + "\x12AcceptWhatsAppCall\x12&.rpc.InternalAcceptWhatsAppCallRequest\x1a#.livekit.AcceptWhatsAppCallResponse\"\x06\xb2\x89\x01\x02\x10\x012\x98\x02\n" + + "\x10ConnectorHandler\x12|\n" + + "\x13ConnectWhatsAppCall\x12#.livekit.ConnectWhatsAppCallRequest\x1a$.livekit.ConnectWhatsAppCallResponse\"\x1a\xb2\x89\x01\x16\x10\x01\x1a\x12\x12\x10whatsapp_call_id\x12\x85\x01\n" + + "\x16DisconnectWhatsAppCall\x12&.livekit.DisconnectWhatsAppCallRequest\x1a'.livekit.DisconnectWhatsAppCallResponse\"\x1a\xb2\x89\x01\x16\x10\x01\x1a\x12\x12\x10whatsapp_call_idB!Z\x1fgithub.com/livekit/protocol/rpcb\x06proto3" + +var ( + file_rpc_connector_proto_rawDescOnce sync.Once + file_rpc_connector_proto_rawDescData []byte +) + +func file_rpc_connector_proto_rawDescGZIP() []byte { + file_rpc_connector_proto_rawDescOnce.Do(func() { + file_rpc_connector_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_rpc_connector_proto_rawDesc), len(file_rpc_connector_proto_rawDesc))) + }) + return file_rpc_connector_proto_rawDescData +} + +var file_rpc_connector_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_rpc_connector_proto_goTypes = []any{ + (*InternalDialWhatsAppCallRequest)(nil), // 0: rpc.InternalDialWhatsAppCallRequest + (*InternalAcceptWhatsAppCallRequest)(nil), // 1: rpc.InternalAcceptWhatsAppCallRequest + (*livekit.DialWhatsAppCallRequest)(nil), // 2: livekit.DialWhatsAppCallRequest + (*InternalRoomJoinInfo)(nil), // 3: rpc.InternalRoomJoinInfo + (*livekit.AcceptWhatsAppCallRequest)(nil), // 4: livekit.AcceptWhatsAppCallRequest + (*livekit.ConnectWhatsAppCallRequest)(nil), // 5: livekit.ConnectWhatsAppCallRequest + (*livekit.DisconnectWhatsAppCallRequest)(nil), // 6: livekit.DisconnectWhatsAppCallRequest + (*livekit.DialWhatsAppCallResponse)(nil), // 7: livekit.DialWhatsAppCallResponse + (*livekit.AcceptWhatsAppCallResponse)(nil), // 8: livekit.AcceptWhatsAppCallResponse + (*livekit.ConnectWhatsAppCallResponse)(nil), // 9: livekit.ConnectWhatsAppCallResponse + (*livekit.DisconnectWhatsAppCallResponse)(nil), // 10: livekit.DisconnectWhatsAppCallResponse +} +var file_rpc_connector_proto_depIdxs = []int32{ + 2, // 0: rpc.InternalDialWhatsAppCallRequest.request:type_name -> livekit.DialWhatsAppCallRequest + 3, // 1: rpc.InternalDialWhatsAppCallRequest.room_join_info:type_name -> rpc.InternalRoomJoinInfo + 4, // 2: rpc.InternalAcceptWhatsAppCallRequest.request:type_name -> livekit.AcceptWhatsAppCallRequest + 3, // 3: rpc.InternalAcceptWhatsAppCallRequest.room_join_info:type_name -> rpc.InternalRoomJoinInfo + 0, // 4: rpc.ConnectorInternal.DialWhatsAppCall:input_type -> rpc.InternalDialWhatsAppCallRequest + 1, // 5: rpc.ConnectorInternal.AcceptWhatsAppCall:input_type -> rpc.InternalAcceptWhatsAppCallRequest + 5, // 6: rpc.ConnectorHandler.ConnectWhatsAppCall:input_type -> livekit.ConnectWhatsAppCallRequest + 6, // 7: rpc.ConnectorHandler.DisconnectWhatsAppCall:input_type -> livekit.DisconnectWhatsAppCallRequest + 7, // 8: rpc.ConnectorInternal.DialWhatsAppCall:output_type -> livekit.DialWhatsAppCallResponse + 8, // 9: rpc.ConnectorInternal.AcceptWhatsAppCall:output_type -> livekit.AcceptWhatsAppCallResponse + 9, // 10: rpc.ConnectorHandler.ConnectWhatsAppCall:output_type -> livekit.ConnectWhatsAppCallResponse + 10, // 11: rpc.ConnectorHandler.DisconnectWhatsAppCall:output_type -> livekit.DisconnectWhatsAppCallResponse + 8, // [8:12] is the sub-list for method output_type + 4, // [4:8] is the sub-list for method input_type + 4, // [4:4] is the sub-list for extension type_name + 4, // [4:4] is the sub-list for extension extendee + 0, // [0:4] is the sub-list for field type_name +} + +func init() { file_rpc_connector_proto_init() } +func file_rpc_connector_proto_init() { + if File_rpc_connector_proto != nil { + return + } + file_rpc_common_proto_init() + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_rpc_connector_proto_rawDesc), len(file_rpc_connector_proto_rawDesc)), + NumEnums: 0, + NumMessages: 2, + NumExtensions: 0, + NumServices: 2, + }, + GoTypes: file_rpc_connector_proto_goTypes, + DependencyIndexes: file_rpc_connector_proto_depIdxs, + MessageInfos: file_rpc_connector_proto_msgTypes, + }.Build() + File_rpc_connector_proto = out.File + file_rpc_connector_proto_goTypes = nil + file_rpc_connector_proto_depIdxs = nil +} diff --git a/rpc/connector.psrpc.go b/rpc/connector.psrpc.go new file mode 100644 index 0000000..dc3eb65 --- /dev/null +++ b/rpc/connector.psrpc.go @@ -0,0 +1,337 @@ +// Code generated by protoc-gen-psrpc v0.7.0, DO NOT EDIT. +// source: rpc/connector.proto + +package rpc + +import ( + "context" + + "github.com/livekit/psrpc" + "github.com/livekit/psrpc/pkg/client" + "github.com/livekit/psrpc/pkg/info" + "github.com/livekit/psrpc/pkg/rand" + "github.com/livekit/psrpc/pkg/server" + "github.com/livekit/psrpc/version" +) +import livekit10 "github.com/livekit/protocol/livekit" + +var _ = version.PsrpcVersion_0_7 + +// ================================== +// ConnectorInternal Client Interface +// ================================== + +type ConnectorInternalClient interface { + DialWhatsAppCall(ctx context.Context, topic string, req *InternalDialWhatsAppCallRequest, opts ...psrpc.RequestOption) (*livekit10.DialWhatsAppCallResponse, error) + + AcceptWhatsAppCall(ctx context.Context, topic string, req *InternalAcceptWhatsAppCallRequest, opts ...psrpc.RequestOption) (*livekit10.AcceptWhatsAppCallResponse, error) + + // Close immediately, without waiting for pending RPCs + Close() +} + +// ====================================== +// ConnectorInternal ServerImpl Interface +// ====================================== + +type ConnectorInternalServerImpl interface { + DialWhatsAppCall(context.Context, *InternalDialWhatsAppCallRequest) (*livekit10.DialWhatsAppCallResponse, error) + + AcceptWhatsAppCall(context.Context, *InternalAcceptWhatsAppCallRequest) (*livekit10.AcceptWhatsAppCallResponse, error) +} + +// ================================== +// ConnectorInternal Server Interface +// ================================== + +type ConnectorInternalServer interface { + RegisterDialWhatsAppCallTopic(topic string) error + DeregisterDialWhatsAppCallTopic(topic string) + RegisterAcceptWhatsAppCallTopic(topic string) error + DeregisterAcceptWhatsAppCallTopic(topic string) + + // Close and wait for pending RPCs to complete + Shutdown() + + // Close immediately, without waiting for pending RPCs + Kill() +} + +// ======================== +// ConnectorInternal Client +// ======================== + +type connectorInternalClient struct { + client *client.RPCClient +} + +// NewConnectorInternalClient creates a psrpc client that implements the ConnectorInternalClient interface. +func NewConnectorInternalClient(bus psrpc.MessageBus, opts ...psrpc.ClientOption) (ConnectorInternalClient, error) { + sd := &info.ServiceDefinition{ + Name: "ConnectorInternal", + ID: rand.NewClientID(), + } + + sd.RegisterMethod("DialWhatsAppCall", false, false, true, true) + sd.RegisterMethod("AcceptWhatsAppCall", false, false, true, true) + + rpcClient, err := client.NewRPCClient(sd, bus, opts...) + if err != nil { + return nil, err + } + + return &connectorInternalClient{ + client: rpcClient, + }, nil +} + +func (c *connectorInternalClient) DialWhatsAppCall(ctx context.Context, topic string, req *InternalDialWhatsAppCallRequest, opts ...psrpc.RequestOption) (*livekit10.DialWhatsAppCallResponse, error) { + return client.RequestSingle[*livekit10.DialWhatsAppCallResponse](ctx, c.client, "DialWhatsAppCall", []string{topic}, req, opts...) +} + +func (c *connectorInternalClient) AcceptWhatsAppCall(ctx context.Context, topic string, req *InternalAcceptWhatsAppCallRequest, opts ...psrpc.RequestOption) (*livekit10.AcceptWhatsAppCallResponse, error) { + return client.RequestSingle[*livekit10.AcceptWhatsAppCallResponse](ctx, c.client, "AcceptWhatsAppCall", []string{topic}, req, opts...) +} + +func (s *connectorInternalClient) Close() { + s.client.Close() +} + +// ======================== +// ConnectorInternal Server +// ======================== + +type connectorInternalServer struct { + svc ConnectorInternalServerImpl + rpc *server.RPCServer +} + +// NewConnectorInternalServer builds a RPCServer that will route requests +// to the corresponding method in the provided svc implementation. +func NewConnectorInternalServer(svc ConnectorInternalServerImpl, bus psrpc.MessageBus, opts ...psrpc.ServerOption) (ConnectorInternalServer, error) { + sd := &info.ServiceDefinition{ + Name: "ConnectorInternal", + ID: rand.NewServerID(), + } + + s := server.NewRPCServer(sd, bus, opts...) + + sd.RegisterMethod("DialWhatsAppCall", false, false, true, true) + sd.RegisterMethod("AcceptWhatsAppCall", false, false, true, true) + return &connectorInternalServer{ + svc: svc, + rpc: s, + }, nil +} + +func (s *connectorInternalServer) RegisterDialWhatsAppCallTopic(topic string) error { + return server.RegisterHandler(s.rpc, "DialWhatsAppCall", []string{topic}, s.svc.DialWhatsAppCall, nil) +} + +func (s *connectorInternalServer) DeregisterDialWhatsAppCallTopic(topic string) { + s.rpc.DeregisterHandler("DialWhatsAppCall", []string{topic}) +} + +func (s *connectorInternalServer) RegisterAcceptWhatsAppCallTopic(topic string) error { + return server.RegisterHandler(s.rpc, "AcceptWhatsAppCall", []string{topic}, s.svc.AcceptWhatsAppCall, nil) +} + +func (s *connectorInternalServer) DeregisterAcceptWhatsAppCallTopic(topic string) { + s.rpc.DeregisterHandler("AcceptWhatsAppCall", []string{topic}) +} + +func (s *connectorInternalServer) Shutdown() { + s.rpc.Close(false) +} + +func (s *connectorInternalServer) Kill() { + s.rpc.Close(true) +} + +// ====================================== +// ConnectorInternal Unimplemented Server +// ====================================== + +type UnimplementedConnectorInternalServer struct{} + +func (UnimplementedConnectorInternalServer) DialWhatsAppCall(context.Context, *InternalDialWhatsAppCallRequest) (*livekit10.DialWhatsAppCallResponse, error) { + return nil, psrpc.ErrUnimplemented +} + +func (UnimplementedConnectorInternalServer) AcceptWhatsAppCall(context.Context, *InternalAcceptWhatsAppCallRequest) (*livekit10.AcceptWhatsAppCallResponse, error) { + return nil, psrpc.ErrUnimplemented +} + +// ================================= +// ConnectorHandler Client Interface +// ================================= + +type ConnectorHandlerClient interface { + ConnectWhatsAppCall(ctx context.Context, whatsappCallId string, req *livekit10.ConnectWhatsAppCallRequest, opts ...psrpc.RequestOption) (*livekit10.ConnectWhatsAppCallResponse, error) + + DisconnectWhatsAppCall(ctx context.Context, whatsappCallId string, req *livekit10.DisconnectWhatsAppCallRequest, opts ...psrpc.RequestOption) (*livekit10.DisconnectWhatsAppCallResponse, error) + + // Close immediately, without waiting for pending RPCs + Close() +} + +// ===================================== +// ConnectorHandler ServerImpl Interface +// ===================================== + +type ConnectorHandlerServerImpl interface { + ConnectWhatsAppCall(context.Context, *livekit10.ConnectWhatsAppCallRequest) (*livekit10.ConnectWhatsAppCallResponse, error) + + DisconnectWhatsAppCall(context.Context, *livekit10.DisconnectWhatsAppCallRequest) (*livekit10.DisconnectWhatsAppCallResponse, error) +} + +// ================================= +// ConnectorHandler Server Interface +// ================================= + +type ConnectorHandlerServer interface { + RegisterConnectWhatsAppCallTopic(whatsappCallId string) error + DeregisterConnectWhatsAppCallTopic(whatsappCallId string) + RegisterDisconnectWhatsAppCallTopic(whatsappCallId string) error + DeregisterDisconnectWhatsAppCallTopic(whatsappCallId string) + + // Close and wait for pending RPCs to complete + Shutdown() + + // Close immediately, without waiting for pending RPCs + Kill() +} + +// ======================= +// ConnectorHandler Client +// ======================= + +type connectorHandlerClient struct { + client *client.RPCClient +} + +// NewConnectorHandlerClient creates a psrpc client that implements the ConnectorHandlerClient interface. +func NewConnectorHandlerClient(bus psrpc.MessageBus, opts ...psrpc.ClientOption) (ConnectorHandlerClient, error) { + sd := &info.ServiceDefinition{ + Name: "ConnectorHandler", + ID: rand.NewClientID(), + } + + sd.RegisterMethod("ConnectWhatsAppCall", false, false, true, true) + sd.RegisterMethod("DisconnectWhatsAppCall", false, false, true, true) + + rpcClient, err := client.NewRPCClient(sd, bus, opts...) + if err != nil { + return nil, err + } + + return &connectorHandlerClient{ + client: rpcClient, + }, nil +} + +func (c *connectorHandlerClient) ConnectWhatsAppCall(ctx context.Context, whatsappCallId string, req *livekit10.ConnectWhatsAppCallRequest, opts ...psrpc.RequestOption) (*livekit10.ConnectWhatsAppCallResponse, error) { + return client.RequestSingle[*livekit10.ConnectWhatsAppCallResponse](ctx, c.client, "ConnectWhatsAppCall", []string{whatsappCallId}, req, opts...) +} + +func (c *connectorHandlerClient) DisconnectWhatsAppCall(ctx context.Context, whatsappCallId string, req *livekit10.DisconnectWhatsAppCallRequest, opts ...psrpc.RequestOption) (*livekit10.DisconnectWhatsAppCallResponse, error) { + return client.RequestSingle[*livekit10.DisconnectWhatsAppCallResponse](ctx, c.client, "DisconnectWhatsAppCall", []string{whatsappCallId}, req, opts...) +} + +func (s *connectorHandlerClient) Close() { + s.client.Close() +} + +// ======================= +// ConnectorHandler Server +// ======================= + +type connectorHandlerServer struct { + svc ConnectorHandlerServerImpl + rpc *server.RPCServer +} + +// NewConnectorHandlerServer builds a RPCServer that will route requests +// to the corresponding method in the provided svc implementation. +func NewConnectorHandlerServer(svc ConnectorHandlerServerImpl, bus psrpc.MessageBus, opts ...psrpc.ServerOption) (ConnectorHandlerServer, error) { + sd := &info.ServiceDefinition{ + Name: "ConnectorHandler", + ID: rand.NewServerID(), + } + + s := server.NewRPCServer(sd, bus, opts...) + + sd.RegisterMethod("ConnectWhatsAppCall", false, false, true, true) + sd.RegisterMethod("DisconnectWhatsAppCall", false, false, true, true) + return &connectorHandlerServer{ + svc: svc, + rpc: s, + }, nil +} + +func (s *connectorHandlerServer) RegisterConnectWhatsAppCallTopic(whatsappCallId string) error { + return server.RegisterHandler(s.rpc, "ConnectWhatsAppCall", []string{whatsappCallId}, s.svc.ConnectWhatsAppCall, nil) +} + +func (s *connectorHandlerServer) DeregisterConnectWhatsAppCallTopic(whatsappCallId string) { + s.rpc.DeregisterHandler("ConnectWhatsAppCall", []string{whatsappCallId}) +} + +func (s *connectorHandlerServer) RegisterDisconnectWhatsAppCallTopic(whatsappCallId string) error { + return server.RegisterHandler(s.rpc, "DisconnectWhatsAppCall", []string{whatsappCallId}, s.svc.DisconnectWhatsAppCall, nil) +} + +func (s *connectorHandlerServer) DeregisterDisconnectWhatsAppCallTopic(whatsappCallId string) { + s.rpc.DeregisterHandler("DisconnectWhatsAppCall", []string{whatsappCallId}) +} + +func (s *connectorHandlerServer) Shutdown() { + s.rpc.Close(false) +} + +func (s *connectorHandlerServer) Kill() { + s.rpc.Close(true) +} + +// ===================================== +// ConnectorHandler Unimplemented Server +// ===================================== + +type UnimplementedConnectorHandlerServer struct{} + +func (UnimplementedConnectorHandlerServer) ConnectWhatsAppCall(context.Context, *livekit10.ConnectWhatsAppCallRequest) (*livekit10.ConnectWhatsAppCallResponse, error) { + return nil, psrpc.ErrUnimplemented +} + +func (UnimplementedConnectorHandlerServer) DisconnectWhatsAppCall(context.Context, *livekit10.DisconnectWhatsAppCallRequest) (*livekit10.DisconnectWhatsAppCallResponse, error) { + return nil, psrpc.ErrUnimplemented +} + +var psrpcFileDescriptor12 = []byte{ + // 391 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x93, 0x3f, 0x6f, 0xda, 0x40, + 0x18, 0xc6, 0x75, 0x54, 0xa2, 0xd2, 0xf5, 0x8f, 0xdc, 0x43, 0x42, 0xd4, 0x0b, 0xe0, 0x22, 0xda, + 0xc9, 0x96, 0xe8, 0x56, 0x55, 0xaa, 0x28, 0x0c, 0xa5, 0xa3, 0x97, 0x48, 0x59, 0x2c, 0x73, 0x1c, + 0xe1, 0x92, 0xf3, 0xbd, 0x97, 0xf3, 0x91, 0x2c, 0x59, 0x33, 0xf0, 0x0d, 0x32, 0x65, 0xc8, 0x47, + 0xe0, 0x2b, 0xe5, 0x8b, 0x44, 0xc1, 0x3e, 0x82, 0x89, 0x0d, 0x4b, 0x36, 0xdf, 0xeb, 0xe7, 0x7d, + 0x9e, 0xdf, 0x3d, 0xb2, 0x71, 0x43, 0x2b, 0x1a, 0x50, 0x90, 0x92, 0x51, 0x03, 0xda, 0x57, 0x1a, + 0x0c, 0x90, 0x77, 0x5a, 0x51, 0xf7, 0x13, 0x28, 0xc3, 0x41, 0xa6, 0xd9, 0xcc, 0xed, 0x08, 0x7e, + 0xc5, 0x2e, 0xb8, 0x89, 0xb6, 0xe2, 0xe8, 0x7a, 0x11, 0x9b, 0x34, 0x56, 0x2a, 0x57, 0x38, 0x99, + 0x55, 0x92, 0x80, 0xcc, 0x26, 0xde, 0x3d, 0xc2, 0xed, 0x89, 0x34, 0x4c, 0xcb, 0x58, 0x8c, 0x79, + 0x2c, 0x4e, 0x9e, 0x17, 0x86, 0x4a, 0x8d, 0x62, 0x21, 0x42, 0x76, 0xb9, 0x64, 0xa9, 0x21, 0xbf, + 0xf0, 0x7b, 0x9d, 0x3d, 0xb6, 0x50, 0x07, 0xfd, 0xf8, 0x30, 0xe8, 0xf8, 0x79, 0x92, 0x5f, 0xb1, + 0x12, 0xda, 0x05, 0xf2, 0x07, 0x7f, 0xd6, 0x00, 0x49, 0x74, 0x0e, 0x5c, 0x46, 0x5c, 0xce, 0xa1, + 0x55, 0xdb, 0x58, 0x7c, 0xf5, 0xb5, 0xa2, 0xbe, 0x4d, 0x0e, 0x01, 0x92, 0xff, 0xc0, 0xe5, 0x44, + 0xce, 0x21, 0xfc, 0xa8, 0x77, 0x4e, 0xde, 0x03, 0xc2, 0x5d, 0x2b, 0x1b, 0x52, 0xca, 0x94, 0x29, + 0x43, 0xfc, 0xbd, 0x8f, 0xe8, 0x6d, 0x11, 0x2b, 0x97, 0xde, 0x0e, 0x72, 0xf0, 0x88, 0xf0, 0x97, + 0x91, 0x2d, 0xdd, 0xea, 0x09, 0xc5, 0xce, 0x7e, 0x3f, 0xa4, 0x57, 0xb0, 0xac, 0xa8, 0xcf, 0xed, + 0x1e, 0x28, 0x38, 0x55, 0x20, 0x53, 0xe6, 0xd5, 0xd7, 0x2b, 0x54, 0x73, 0x10, 0xe1, 0x98, 0xbc, + 0xbe, 0x21, 0xe9, 0x17, 0x62, 0x2a, 0x2b, 0x70, 0xbf, 0x1d, 0xac, 0xa9, 0x18, 0x35, 0xb8, 0xab, + 0x61, 0x67, 0x7b, 0xcb, 0x7f, 0xb1, 0x9c, 0x09, 0xa6, 0xc9, 0x0d, 0x6e, 0xe4, 0xb3, 0x02, 0xc0, + 0x8b, 0x71, 0xc9, 0x5b, 0x9b, 0xde, 0x3b, 0x2c, 0xca, 0xe3, 0xdd, 0xf5, 0x0a, 0x35, 0x1d, 0xe4, + 0x12, 0xe2, 0xd8, 0xcf, 0x39, 0xa2, 0xb1, 0x10, 0x11, 0x9f, 0x91, 0x5b, 0x84, 0x9b, 0x63, 0x9e, + 0xd2, 0x12, 0x82, 0xfe, 0x4e, 0x87, 0x65, 0x02, 0x0b, 0xf1, 0xfd, 0xa8, 0xee, 0x38, 0xc7, 0xdf, + 0xee, 0x69, 0xfb, 0x8c, 0x9b, 0xc5, 0x72, 0xea, 0x53, 0x48, 0x82, 0xdc, 0x30, 0xd8, 0xfc, 0x62, + 0x14, 0x44, 0xa0, 0x15, 0x9d, 0xd6, 0x37, 0xa7, 0x9f, 0x4f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x5c, + 0xdc, 0xdc, 0x82, 0xcf, 0x03, 0x00, 0x00, +} diff --git a/rpc/connector_client.go b/rpc/connector_client.go new file mode 100644 index 0000000..af8be9f --- /dev/null +++ b/rpc/connector_client.go @@ -0,0 +1,52 @@ +// Copyright 2025 LiveKit, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package rpc + +type ConnectorClient interface { + ConnectorInternalClient + ConnectorHandlerClient +} + +type connectorClient struct { + ConnectorInternalClient + ConnectorHandlerClient +} + +func NewConnectorClient(params ClientParams) (ConnectorClient, error) { + if params.Bus == nil { + return nil, nil + } + opts := params.Options() + + internalClient, err := NewConnectorInternalClient(params.Bus, opts...) + if err != nil { + return nil, err + } + + handlerClient, err := NewConnectorHandlerClient(params.Bus, opts...) + if err != nil { + return nil, err + } + + return &connectorClient{ + internalClient, + handlerClient, + }, nil +} + +func (c *connectorClient) Close() { + c.ConnectorInternalClient.Close() + c.ConnectorHandlerClient.Close() +} diff --git a/sdp/sdp.go b/sdp/sdp.go index 2a45224..d7943d5 100644 --- a/sdp/sdp.go +++ b/sdp/sdp.go @@ -153,6 +153,19 @@ func ExtractStreamID(media *sdp.MediaDescription) (string, bool) { return streamID, true } +func GetIP(sdp *sdp.SessionDescription) string { + if sdp.ConnectionInformation != nil && sdp.ConnectionInformation.NetworkType == "IN" { + return sdp.ConnectionInformation.Address.Address + } + + for _, media := range sdp.MediaDescriptions { + if media.ConnectionInformation != nil && media.ConnectionInformation.NetworkType == "IN" { + return media.ConnectionInformation.Address.Address + } + } + return "" +} + func GetMediaStreamTrack(m *sdp.MediaDescription) string { mst := "" msid, ok := m.Attribute(sdp.AttrKeyMsid)