diff --git a/.gitattributes b/.gitattributes index adac94fa8f81d..c72d98e5c6cef 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,2 +1,3 @@ # Generated files +peerbroker/proto/*.go linguist-generated=true provisionersdk/proto/*.go linguist-generated=true diff --git a/.github/workflows/coder.yaml b/.github/workflows/coder.yaml index 38bd2e3733f6b..3c025ec2a3df4 100644 --- a/.github/workflows/coder.yaml +++ b/.github/workflows/coder.yaml @@ -113,6 +113,18 @@ jobs: with: go-version: "^1.17" + - uses: actions/cache@v2 + with: + # Go mod cache, Linux build cache, Mac build cache, Windows build cache + path: | + ~/go/pkg/mod + ~/.cache/go-build + ~/Library/Caches/go-build + %LocalAppData%\go-build + key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} + restore-keys: | + ${{ runner.os }}-go- + - run: go install gotest.tools/gotestsum@latest - run: diff --git a/Makefile b/Makefile index 98e115c15f315..8c569e933ec9d 100644 --- a/Makefile +++ b/Makefile @@ -22,9 +22,19 @@ endif fmt: fmt/prettier .PHONY: fmt -gen: database/generate provisionersdk/proto +gen: database/generate peerbroker/proto provisionersdk/proto .PHONY: gen +# Generates the protocol files. +peerbroker/proto: peerbroker/proto/peerbroker.proto + cd peerbroker/proto && protoc \ + --go_out=. \ + --go_opt=paths=source_relative \ + --go-drpc_out=. \ + --go-drpc_opt=paths=source_relative \ + ./peerbroker.proto +.PHONY: peerbroker/proto + # Generates the protocol files. provisionersdk/proto: provisionersdk/proto/provisioner.proto cd provisionersdk/proto && protoc \ diff --git a/codecov.yml b/codecov.yml index b380420fb1790..9d0d944c6835d 100644 --- a/codecov.yml +++ b/codecov.yml @@ -21,4 +21,5 @@ coverage: ignore: # This is generated code. + - peerbroker/proto - provisionersdk/proto diff --git a/peer/conn.go b/peer/conn.go index 00f340f5c44e2..e4d3fec760434 100644 --- a/peer/conn.go +++ b/peer/conn.go @@ -337,6 +337,12 @@ func (c *Conn) LocalSessionDescription() <-chan webrtc.SessionDescription { return c.localSessionDescriptionChannel } +// SetConfiguration applies options to the WebRTC connection. +// Generally used for updating transport options, like ICE servers. +func (c *Conn) SetConfiguration(configuration webrtc.Configuration) error { + return c.rtc.SetConfiguration(configuration) +} + // SetRemoteSessionDescription sets the remote description for the WebRTC connection. func (c *Conn) SetRemoteSessionDescription(s webrtc.SessionDescription) { if c.isClosed() { @@ -388,6 +394,9 @@ func (c *Conn) dialChannel(ctx context.Context, label string, opts *ChannelOpts) if opts.OpenOnDisconnect && !opts.Negotiated { return nil, xerrors.New("OpenOnDisconnect is only allowed for Negotiated channels") } + if c.isClosed() { + return nil, xerrors.Errorf("closed: %w", c.closeError) + } dc, err := c.rtc.CreateDataChannel(label, &webrtc.DataChannelInit{ ID: id, @@ -446,6 +455,11 @@ func (c *Conn) Close() error { return c.closeWithError(nil) } +// CloseWithError closes the connection; subsequent reads/writes will return the error err. +func (c *Conn) CloseWithError(err error) error { + return c.closeWithError(err) +} + func (c *Conn) isClosed() bool { select { case <-c.closed: diff --git a/peer/conn_test.go b/peer/conn_test.go index e9b8732ad42b3..c316125fe5cee 100644 --- a/peer/conn_test.go +++ b/peer/conn_test.go @@ -2,6 +2,7 @@ package peer_test import ( "context" + "errors" "io" "net" "net/http" @@ -193,6 +194,15 @@ func TestConn(t *testing.T) { require.NoError(t, err) }) + t.Run("CloseWithError", func(t *testing.T) { + conn, err := peer.Client([]webrtc.ICEServer{}, nil) + require.NoError(t, err) + expectedErr := errors.New("wow") + _ = conn.CloseWithError(expectedErr) + _, err = conn.Dial(context.Background(), "", nil) + require.ErrorIs(t, err, expectedErr) + }) + t.Run("PingConcurrent", func(t *testing.T) { t.Parallel() client, server, _ := createPair(t) diff --git a/peerbroker/dial.go b/peerbroker/dial.go new file mode 100644 index 0000000000000..9505a364ad874 --- /dev/null +++ b/peerbroker/dial.go @@ -0,0 +1,113 @@ +package peerbroker + +import ( + "reflect" + + "github.com/pion/webrtc/v3" + "golang.org/x/xerrors" + + "github.com/coder/coder/peer" + "github.com/coder/coder/peerbroker/proto" +) + +// Dial consumes the PeerBroker gRPC connection negotiation stream to produce a WebRTC peered connection. +func Dial(stream proto.DRPCPeerBroker_NegotiateConnectionClient, iceServers []webrtc.ICEServer, opts *peer.ConnOpts) (*peer.Conn, error) { + // Convert WebRTC ICE servers to the protobuf type. + protoIceServers := make([]*proto.WebRTCICEServer, 0, len(iceServers)) + for _, iceServer := range iceServers { + var credentialString string + if value, ok := iceServer.Credential.(string); ok { + credentialString = value + } + protoIceServers = append(protoIceServers, &proto.WebRTCICEServer{ + Urls: iceServer.URLs, + Username: iceServer.Username, + Credential: credentialString, + CredentialType: int32(iceServer.CredentialType), + }) + } + if len(protoIceServers) > 0 { + // Send ICE servers to connect with. + // Client sends ICE servers so clients can determine the node + // servers will meet at. eg. us-west1.coder.com could be a TURN server. + err := stream.Send(&proto.NegotiateConnection_ClientToServer{ + Message: &proto.NegotiateConnection_ClientToServer_Servers{ + Servers: &proto.WebRTCICEServers{ + Servers: protoIceServers, + }, + }, + }) + if err != nil { + return nil, xerrors.Errorf("write ice servers: %w", err) + } + } + + peerConn, err := peer.Client(iceServers, opts) + if err != nil { + return nil, xerrors.Errorf("create peer connection: %w", err) + } + go func() { + defer stream.Close() + // Exchanging messages from the peer connection to negotiate a connection. + for { + select { + case <-peerConn.Closed(): + return + case sessionDescription := <-peerConn.LocalSessionDescription(): + err = stream.Send(&proto.NegotiateConnection_ClientToServer{ + Message: &proto.NegotiateConnection_ClientToServer_Offer{ + Offer: &proto.WebRTCSessionDescription{ + SdpType: int32(sessionDescription.Type), + Sdp: sessionDescription.SDP, + }, + }, + }) + if err != nil { + _ = peerConn.CloseWithError(xerrors.Errorf("send local session description: %w", err)) + return + } + case iceCandidate := <-peerConn.LocalCandidate(): + err = stream.Send(&proto.NegotiateConnection_ClientToServer{ + Message: &proto.NegotiateConnection_ClientToServer_IceCandidate{ + IceCandidate: iceCandidate.Candidate, + }, + }) + if err != nil { + _ = peerConn.CloseWithError(xerrors.Errorf("send local candidate: %w", err)) + return + } + } + } + }() + go func() { + // Exchanging messages from the server to negotiate a connection. + for { + serverToClientMessage, err := stream.Recv() + if err != nil { + _ = peerConn.CloseWithError(err) + return + } + + switch { + case serverToClientMessage.GetAnswer() != nil: + peerConn.SetRemoteSessionDescription(webrtc.SessionDescription{ + Type: webrtc.SDPType(serverToClientMessage.GetAnswer().SdpType), + SDP: serverToClientMessage.GetAnswer().Sdp, + }) + case serverToClientMessage.GetIceCandidate() != "": + err = peerConn.AddRemoteCandidate(webrtc.ICECandidateInit{ + Candidate: serverToClientMessage.GetIceCandidate(), + }) + if err != nil { + _ = peerConn.CloseWithError(xerrors.Errorf("add remote candidate: %w", err)) + return + } + default: + _ = peerConn.CloseWithError(xerrors.Errorf("unhandled message: %s", reflect.TypeOf(serverToClientMessage).String())) + return + } + } + }() + + return peerConn, nil +} diff --git a/peerbroker/dial_test.go b/peerbroker/dial_test.go new file mode 100644 index 0000000000000..c88a36a0eb1bf --- /dev/null +++ b/peerbroker/dial_test.go @@ -0,0 +1,48 @@ +package peerbroker_test + +import ( + "context" + "testing" + + "github.com/coder/coder/peerbroker" + "github.com/coder/coder/peerbroker/proto" + "github.com/coder/coder/provisionersdk" + "github.com/pion/webrtc/v3" + "github.com/stretchr/testify/require" + "go.uber.org/goleak" + "storj.io/drpc/drpcconn" +) + +func TestMain(m *testing.M) { + goleak.VerifyTestMain(m) +} + +func TestDial(t *testing.T) { + t.Run("Connect", func(t *testing.T) { + ctx := context.Background() + client, server := provisionersdk.TransportPipe() + defer client.Close() + defer server.Close() + + listener, err := peerbroker.Listen(server, nil) + require.NoError(t, err) + + api := proto.NewDRPCPeerBrokerClient(drpcconn.New(client)) + stream, err := api.NegotiateConnection(ctx) + require.NoError(t, err) + clientConn, err := peerbroker.Dial(stream, []webrtc.ICEServer{{ + URLs: []string{"stun:stun.l.google.com:19302"}, + }}, nil) + require.NoError(t, err) + defer clientConn.Close() + + serverConn, err := listener.Accept() + require.NoError(t, err) + defer serverConn.Close() + _, err = serverConn.Ping() + require.NoError(t, err) + + _, err = clientConn.Ping() + require.NoError(t, err) + }) +} diff --git a/peerbroker/listen.go b/peerbroker/listen.go new file mode 100644 index 0000000000000..c63d283d0feae --- /dev/null +++ b/peerbroker/listen.go @@ -0,0 +1,195 @@ +package peerbroker + +import ( + "context" + "errors" + "io" + "reflect" + "sync" + + "github.com/pion/webrtc/v3" + "golang.org/x/xerrors" + "storj.io/drpc" + "storj.io/drpc/drpcmux" + "storj.io/drpc/drpcserver" + + "github.com/coder/coder/peer" + "github.com/coder/coder/peerbroker/proto" +) + +// Listen consumes the transport as the server-side of the PeerBroker dRPC service. +// The Accept function must be serviced, or new connections will hang. +func Listen(transport drpc.Transport, opts *peer.ConnOpts) (*Listener, error) { + ctx, cancelFunc := context.WithCancel(context.Background()) + listener := &Listener{ + connectionChannel: make(chan *peer.Conn), + + closeFunc: cancelFunc, + closed: make(chan struct{}), + } + + mux := drpcmux.New() + err := proto.DRPCRegisterPeerBroker(mux, &peerBrokerService{ + connOpts: opts, + + listener: listener, + }) + if err != nil { + return nil, xerrors.Errorf("register peer broker: %w", err) + } + srv := drpcserver.New(mux) + go func() { + err := srv.ServeOne(ctx, transport) + _ = listener.closeWithError(err) + }() + + return listener, nil +} + +type Listener struct { + connectionChannel chan *peer.Conn + + closeFunc context.CancelFunc + closed chan struct{} + closeMutex sync.Mutex + closeError error +} + +// Accept blocks until a connection arrives or the listener is closed. +func (l *Listener) Accept() (*peer.Conn, error) { + select { + case <-l.closed: + return nil, l.closeError + case conn := <-l.connectionChannel: + return conn, nil + } +} + +// Close ends the listener. This will block all new WebRTC connections +// from establishing, but will not close active connections. +func (l *Listener) Close() error { + return l.closeWithError(io.EOF) +} + +func (l *Listener) closeWithError(err error) error { + l.closeMutex.Lock() + defer l.closeMutex.Unlock() + + if l.isClosed() { + return l.closeError + } + + l.closeError = err + l.closeFunc() + close(l.closed) + + return nil +} + +func (l *Listener) isClosed() bool { + select { + case <-l.closed: + return true + default: + return false + } +} + +// Implements the PeerBroker service protobuf definition. +type peerBrokerService struct { + listener *Listener + + connOpts *peer.ConnOpts +} + +// NegotiateConnection negotiates a WebRTC connection. +func (b *peerBrokerService) NegotiateConnection(stream proto.DRPCPeerBroker_NegotiateConnectionStream) error { + // Start with no ICE servers. They can be sent by the client if provided. + peerConn, err := peer.Server([]webrtc.ICEServer{}, b.connOpts) + if err != nil { + return xerrors.Errorf("create peer connection: %w", err) + } + select { + case <-b.listener.closed: + return peerConn.CloseWithError(b.listener.closeError) + case b.listener.connectionChannel <- peerConn: + } + go func() { + defer stream.Close() + for { + select { + case <-peerConn.Closed(): + return + case sessionDescription := <-peerConn.LocalSessionDescription(): + err = stream.Send(&proto.NegotiateConnection_ServerToClient{ + Message: &proto.NegotiateConnection_ServerToClient_Answer{ + Answer: &proto.WebRTCSessionDescription{ + SdpType: int32(sessionDescription.Type), + Sdp: sessionDescription.SDP, + }, + }, + }) + if err != nil { + _ = peerConn.CloseWithError(xerrors.Errorf("send local session description: %w", err)) + return + } + case iceCandidate := <-peerConn.LocalCandidate(): + err = stream.Send(&proto.NegotiateConnection_ServerToClient{ + Message: &proto.NegotiateConnection_ServerToClient_IceCandidate{ + IceCandidate: iceCandidate.Candidate, + }, + }) + if err != nil { + _ = peerConn.CloseWithError(xerrors.Errorf("send local candidate: %w", err)) + return + } + } + } + }() + for { + clientToServerMessage, err := stream.Recv() + if err != nil { + if errors.Is(err, io.EOF) { + break + } + return peerConn.CloseWithError(xerrors.Errorf("recv: %w", err)) + } + + switch { + case clientToServerMessage.GetOffer() != nil: + peerConn.SetRemoteSessionDescription(webrtc.SessionDescription{ + Type: webrtc.SDPType(clientToServerMessage.GetOffer().SdpType), + SDP: clientToServerMessage.GetOffer().Sdp, + }) + break + case clientToServerMessage.GetServers() != nil: + // Convert protobuf ICE servers to the WebRTC type. + iceServers := make([]webrtc.ICEServer, 0, len(clientToServerMessage.GetServers().Servers)) + for _, iceServer := range clientToServerMessage.GetServers().Servers { + iceServers = append(iceServers, webrtc.ICEServer{ + URLs: iceServer.Urls, + Username: iceServer.Username, + Credential: iceServer.Credential, + CredentialType: webrtc.ICECredentialType(iceServer.CredentialType), + }) + } + err = peerConn.SetConfiguration(webrtc.Configuration{ + ICEServers: iceServers, + }) + if err != nil { + return peerConn.CloseWithError(xerrors.Errorf("set ice configuration: %w", err)) + } + case clientToServerMessage.GetIceCandidate() != "": + err = peerConn.AddRemoteCandidate(webrtc.ICECandidateInit{ + Candidate: clientToServerMessage.GetIceCandidate(), + }) + if err != nil { + return peerConn.CloseWithError(xerrors.Errorf("add remote candidate: %w", err)) + } + default: + return peerConn.CloseWithError(xerrors.Errorf("unhandled message: %s", reflect.TypeOf(clientToServerMessage).String())) + } + } + + return nil +} diff --git a/peerbroker/listen_test.go b/peerbroker/listen_test.go new file mode 100644 index 0000000000000..0118349adea1c --- /dev/null +++ b/peerbroker/listen_test.go @@ -0,0 +1,49 @@ +package peerbroker_test + +import ( + "context" + "io" + "testing" + + "github.com/coder/coder/peerbroker" + "github.com/coder/coder/peerbroker/proto" + "github.com/coder/coder/provisionersdk" + "github.com/stretchr/testify/require" + "storj.io/drpc/drpcconn" +) + +func TestListen(t *testing.T) { + // Ensures connections blocked on Accept() are + // closed if the listener is. + t.Run("NoAcceptClosed", func(t *testing.T) { + ctx := context.Background() + client, server := provisionersdk.TransportPipe() + defer client.Close() + defer server.Close() + + listener, err := peerbroker.Listen(server, nil) + require.NoError(t, err) + + api := proto.NewDRPCPeerBrokerClient(drpcconn.New(client)) + stream, err := api.NegotiateConnection(ctx) + require.NoError(t, err) + clientConn, err := peerbroker.Dial(stream, nil, nil) + require.NoError(t, err) + defer clientConn.Close() + + _ = listener.Close() + }) + + // Ensures Accept() properly exits when Close() is called. + t.Run("AcceptClosed", func(t *testing.T) { + client, server := provisionersdk.TransportPipe() + defer client.Close() + defer server.Close() + + listener, err := peerbroker.Listen(server, nil) + require.NoError(t, err) + go listener.Close() + _, err = listener.Accept() + require.ErrorIs(t, err, io.EOF) + }) +} diff --git a/peerbroker/proto/peerbroker.pb.go b/peerbroker/proto/peerbroker.pb.go new file mode 100644 index 0000000000000..f5a41277bd10f --- /dev/null +++ b/peerbroker/proto/peerbroker.pb.go @@ -0,0 +1,610 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.26.0 +// protoc v3.6.1 +// source: peerbroker.proto + +package proto + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +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 WebRTCSessionDescription struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + SdpType int32 `protobuf:"varint,1,opt,name=sdp_type,json=sdpType,proto3" json:"sdp_type,omitempty"` + Sdp string `protobuf:"bytes,2,opt,name=sdp,proto3" json:"sdp,omitempty"` +} + +func (x *WebRTCSessionDescription) Reset() { + *x = WebRTCSessionDescription{} + if protoimpl.UnsafeEnabled { + mi := &file_peerbroker_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *WebRTCSessionDescription) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*WebRTCSessionDescription) ProtoMessage() {} + +func (x *WebRTCSessionDescription) ProtoReflect() protoreflect.Message { + mi := &file_peerbroker_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use WebRTCSessionDescription.ProtoReflect.Descriptor instead. +func (*WebRTCSessionDescription) Descriptor() ([]byte, []int) { + return file_peerbroker_proto_rawDescGZIP(), []int{0} +} + +func (x *WebRTCSessionDescription) GetSdpType() int32 { + if x != nil { + return x.SdpType + } + return 0 +} + +func (x *WebRTCSessionDescription) GetSdp() string { + if x != nil { + return x.Sdp + } + return "" +} + +type WebRTCICEServer struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Urls []string `protobuf:"bytes,1,rep,name=urls,proto3" json:"urls,omitempty"` + Username string `protobuf:"bytes,2,opt,name=username,proto3" json:"username,omitempty"` + Credential string `protobuf:"bytes,3,opt,name=credential,proto3" json:"credential,omitempty"` + CredentialType int32 `protobuf:"varint,4,opt,name=credential_type,json=credentialType,proto3" json:"credential_type,omitempty"` +} + +func (x *WebRTCICEServer) Reset() { + *x = WebRTCICEServer{} + if protoimpl.UnsafeEnabled { + mi := &file_peerbroker_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *WebRTCICEServer) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*WebRTCICEServer) ProtoMessage() {} + +func (x *WebRTCICEServer) ProtoReflect() protoreflect.Message { + mi := &file_peerbroker_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use WebRTCICEServer.ProtoReflect.Descriptor instead. +func (*WebRTCICEServer) Descriptor() ([]byte, []int) { + return file_peerbroker_proto_rawDescGZIP(), []int{1} +} + +func (x *WebRTCICEServer) GetUrls() []string { + if x != nil { + return x.Urls + } + return nil +} + +func (x *WebRTCICEServer) GetUsername() string { + if x != nil { + return x.Username + } + return "" +} + +func (x *WebRTCICEServer) GetCredential() string { + if x != nil { + return x.Credential + } + return "" +} + +func (x *WebRTCICEServer) GetCredentialType() int32 { + if x != nil { + return x.CredentialType + } + return 0 +} + +type WebRTCICEServers struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Servers []*WebRTCICEServer `protobuf:"bytes,1,rep,name=servers,proto3" json:"servers,omitempty"` +} + +func (x *WebRTCICEServers) Reset() { + *x = WebRTCICEServers{} + if protoimpl.UnsafeEnabled { + mi := &file_peerbroker_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *WebRTCICEServers) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*WebRTCICEServers) ProtoMessage() {} + +func (x *WebRTCICEServers) ProtoReflect() protoreflect.Message { + mi := &file_peerbroker_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use WebRTCICEServers.ProtoReflect.Descriptor instead. +func (*WebRTCICEServers) Descriptor() ([]byte, []int) { + return file_peerbroker_proto_rawDescGZIP(), []int{2} +} + +func (x *WebRTCICEServers) GetServers() []*WebRTCICEServer { + if x != nil { + return x.Servers + } + return nil +} + +type NegotiateConnection struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *NegotiateConnection) Reset() { + *x = NegotiateConnection{} + if protoimpl.UnsafeEnabled { + mi := &file_peerbroker_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *NegotiateConnection) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*NegotiateConnection) ProtoMessage() {} + +func (x *NegotiateConnection) ProtoReflect() protoreflect.Message { + mi := &file_peerbroker_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use NegotiateConnection.ProtoReflect.Descriptor instead. +func (*NegotiateConnection) Descriptor() ([]byte, []int) { + return file_peerbroker_proto_rawDescGZIP(), []int{3} +} + +type NegotiateConnection_ClientToServer struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Types that are assignable to Message: + // *NegotiateConnection_ClientToServer_Servers + // *NegotiateConnection_ClientToServer_Offer + // *NegotiateConnection_ClientToServer_IceCandidate + Message isNegotiateConnection_ClientToServer_Message `protobuf_oneof:"message"` +} + +func (x *NegotiateConnection_ClientToServer) Reset() { + *x = NegotiateConnection_ClientToServer{} + if protoimpl.UnsafeEnabled { + mi := &file_peerbroker_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *NegotiateConnection_ClientToServer) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*NegotiateConnection_ClientToServer) ProtoMessage() {} + +func (x *NegotiateConnection_ClientToServer) ProtoReflect() protoreflect.Message { + mi := &file_peerbroker_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use NegotiateConnection_ClientToServer.ProtoReflect.Descriptor instead. +func (*NegotiateConnection_ClientToServer) Descriptor() ([]byte, []int) { + return file_peerbroker_proto_rawDescGZIP(), []int{3, 0} +} + +func (m *NegotiateConnection_ClientToServer) GetMessage() isNegotiateConnection_ClientToServer_Message { + if m != nil { + return m.Message + } + return nil +} + +func (x *NegotiateConnection_ClientToServer) GetServers() *WebRTCICEServers { + if x, ok := x.GetMessage().(*NegotiateConnection_ClientToServer_Servers); ok { + return x.Servers + } + return nil +} + +func (x *NegotiateConnection_ClientToServer) GetOffer() *WebRTCSessionDescription { + if x, ok := x.GetMessage().(*NegotiateConnection_ClientToServer_Offer); ok { + return x.Offer + } + return nil +} + +func (x *NegotiateConnection_ClientToServer) GetIceCandidate() string { + if x, ok := x.GetMessage().(*NegotiateConnection_ClientToServer_IceCandidate); ok { + return x.IceCandidate + } + return "" +} + +type isNegotiateConnection_ClientToServer_Message interface { + isNegotiateConnection_ClientToServer_Message() +} + +type NegotiateConnection_ClientToServer_Servers struct { + Servers *WebRTCICEServers `protobuf:"bytes,1,opt,name=servers,proto3,oneof"` +} + +type NegotiateConnection_ClientToServer_Offer struct { + Offer *WebRTCSessionDescription `protobuf:"bytes,2,opt,name=offer,proto3,oneof"` +} + +type NegotiateConnection_ClientToServer_IceCandidate struct { + IceCandidate string `protobuf:"bytes,3,opt,name=ice_candidate,json=iceCandidate,proto3,oneof"` +} + +func (*NegotiateConnection_ClientToServer_Servers) isNegotiateConnection_ClientToServer_Message() {} + +func (*NegotiateConnection_ClientToServer_Offer) isNegotiateConnection_ClientToServer_Message() {} + +func (*NegotiateConnection_ClientToServer_IceCandidate) isNegotiateConnection_ClientToServer_Message() { +} + +type NegotiateConnection_ServerToClient struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Types that are assignable to Message: + // *NegotiateConnection_ServerToClient_Answer + // *NegotiateConnection_ServerToClient_IceCandidate + Message isNegotiateConnection_ServerToClient_Message `protobuf_oneof:"message"` +} + +func (x *NegotiateConnection_ServerToClient) Reset() { + *x = NegotiateConnection_ServerToClient{} + if protoimpl.UnsafeEnabled { + mi := &file_peerbroker_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *NegotiateConnection_ServerToClient) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*NegotiateConnection_ServerToClient) ProtoMessage() {} + +func (x *NegotiateConnection_ServerToClient) ProtoReflect() protoreflect.Message { + mi := &file_peerbroker_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use NegotiateConnection_ServerToClient.ProtoReflect.Descriptor instead. +func (*NegotiateConnection_ServerToClient) Descriptor() ([]byte, []int) { + return file_peerbroker_proto_rawDescGZIP(), []int{3, 1} +} + +func (m *NegotiateConnection_ServerToClient) GetMessage() isNegotiateConnection_ServerToClient_Message { + if m != nil { + return m.Message + } + return nil +} + +func (x *NegotiateConnection_ServerToClient) GetAnswer() *WebRTCSessionDescription { + if x, ok := x.GetMessage().(*NegotiateConnection_ServerToClient_Answer); ok { + return x.Answer + } + return nil +} + +func (x *NegotiateConnection_ServerToClient) GetIceCandidate() string { + if x, ok := x.GetMessage().(*NegotiateConnection_ServerToClient_IceCandidate); ok { + return x.IceCandidate + } + return "" +} + +type isNegotiateConnection_ServerToClient_Message interface { + isNegotiateConnection_ServerToClient_Message() +} + +type NegotiateConnection_ServerToClient_Answer struct { + Answer *WebRTCSessionDescription `protobuf:"bytes,1,opt,name=answer,proto3,oneof"` +} + +type NegotiateConnection_ServerToClient_IceCandidate struct { + IceCandidate string `protobuf:"bytes,2,opt,name=ice_candidate,json=iceCandidate,proto3,oneof"` +} + +func (*NegotiateConnection_ServerToClient_Answer) isNegotiateConnection_ServerToClient_Message() {} + +func (*NegotiateConnection_ServerToClient_IceCandidate) isNegotiateConnection_ServerToClient_Message() { +} + +var File_peerbroker_proto protoreflect.FileDescriptor + +var file_peerbroker_proto_rawDesc = []byte{ + 0x0a, 0x10, 0x70, 0x65, 0x65, 0x72, 0x62, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x12, 0x0a, 0x70, 0x65, 0x65, 0x72, 0x62, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x22, 0x47, + 0x0a, 0x18, 0x57, 0x65, 0x62, 0x52, 0x54, 0x43, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x44, + 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x64, + 0x70, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x73, 0x64, + 0x70, 0x54, 0x79, 0x70, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x73, 0x64, 0x70, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x03, 0x73, 0x64, 0x70, 0x22, 0x8a, 0x01, 0x0a, 0x0f, 0x57, 0x65, 0x62, 0x52, + 0x54, 0x43, 0x49, 0x43, 0x45, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x75, + 0x72, 0x6c, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x75, 0x72, 0x6c, 0x73, 0x12, + 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x63, + 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0a, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x12, 0x27, 0x0a, 0x0f, 0x63, + 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x05, 0x52, 0x0e, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, + 0x54, 0x79, 0x70, 0x65, 0x22, 0x49, 0x0a, 0x10, 0x57, 0x65, 0x62, 0x52, 0x54, 0x43, 0x49, 0x43, + 0x45, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x12, 0x35, 0x0a, 0x07, 0x73, 0x65, 0x72, 0x76, + 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x70, 0x65, 0x65, 0x72, + 0x62, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x2e, 0x57, 0x65, 0x62, 0x52, 0x54, 0x43, 0x49, 0x43, 0x45, + 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x07, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x22, + 0xd7, 0x02, 0x0a, 0x13, 0x4e, 0x65, 0x67, 0x6f, 0x74, 0x69, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, + 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0xba, 0x01, 0x0a, 0x0e, 0x43, 0x6c, 0x69, 0x65, + 0x6e, 0x74, 0x54, 0x6f, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x38, 0x0a, 0x07, 0x73, 0x65, + 0x72, 0x76, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x70, 0x65, + 0x65, 0x72, 0x62, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x2e, 0x57, 0x65, 0x62, 0x52, 0x54, 0x43, 0x49, + 0x43, 0x45, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x48, 0x00, 0x52, 0x07, 0x73, 0x65, 0x72, + 0x76, 0x65, 0x72, 0x73, 0x12, 0x3c, 0x0a, 0x05, 0x6f, 0x66, 0x66, 0x65, 0x72, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x70, 0x65, 0x65, 0x72, 0x62, 0x72, 0x6f, 0x6b, 0x65, 0x72, + 0x2e, 0x57, 0x65, 0x62, 0x52, 0x54, 0x43, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x44, 0x65, + 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x05, 0x6f, 0x66, 0x66, + 0x65, 0x72, 0x12, 0x25, 0x0a, 0x0d, 0x69, 0x63, 0x65, 0x5f, 0x63, 0x61, 0x6e, 0x64, 0x69, 0x64, + 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0c, 0x69, 0x63, 0x65, + 0x43, 0x61, 0x6e, 0x64, 0x69, 0x64, 0x61, 0x74, 0x65, 0x42, 0x09, 0x0a, 0x07, 0x6d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x1a, 0x82, 0x01, 0x0a, 0x0e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x54, + 0x6f, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x12, 0x3e, 0x0a, 0x06, 0x61, 0x6e, 0x73, 0x77, 0x65, + 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x70, 0x65, 0x65, 0x72, 0x62, 0x72, + 0x6f, 0x6b, 0x65, 0x72, 0x2e, 0x57, 0x65, 0x62, 0x52, 0x54, 0x43, 0x53, 0x65, 0x73, 0x73, 0x69, + 0x6f, 0x6e, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, + 0x06, 0x61, 0x6e, 0x73, 0x77, 0x65, 0x72, 0x12, 0x25, 0x0a, 0x0d, 0x69, 0x63, 0x65, 0x5f, 0x63, + 0x61, 0x6e, 0x64, 0x69, 0x64, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, + 0x52, 0x0c, 0x69, 0x63, 0x65, 0x43, 0x61, 0x6e, 0x64, 0x69, 0x64, 0x61, 0x74, 0x65, 0x42, 0x09, + 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x32, 0x87, 0x01, 0x0a, 0x0a, 0x50, 0x65, + 0x65, 0x72, 0x42, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x12, 0x79, 0x0a, 0x13, 0x4e, 0x65, 0x67, 0x6f, + 0x74, 0x69, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, + 0x2e, 0x2e, 0x70, 0x65, 0x65, 0x72, 0x62, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x2e, 0x4e, 0x65, 0x67, + 0x6f, 0x74, 0x69, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x54, 0x6f, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x1a, + 0x2e, 0x2e, 0x70, 0x65, 0x65, 0x72, 0x62, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x2e, 0x4e, 0x65, 0x67, + 0x6f, 0x74, 0x69, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x54, 0x6f, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x28, + 0x01, 0x30, 0x01, 0x42, 0x29, 0x5a, 0x27, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, + 0x6d, 0x2f, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x70, 0x65, + 0x65, 0x72, 0x62, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_peerbroker_proto_rawDescOnce sync.Once + file_peerbroker_proto_rawDescData = file_peerbroker_proto_rawDesc +) + +func file_peerbroker_proto_rawDescGZIP() []byte { + file_peerbroker_proto_rawDescOnce.Do(func() { + file_peerbroker_proto_rawDescData = protoimpl.X.CompressGZIP(file_peerbroker_proto_rawDescData) + }) + return file_peerbroker_proto_rawDescData +} + +var file_peerbroker_proto_msgTypes = make([]protoimpl.MessageInfo, 6) +var file_peerbroker_proto_goTypes = []interface{}{ + (*WebRTCSessionDescription)(nil), // 0: peerbroker.WebRTCSessionDescription + (*WebRTCICEServer)(nil), // 1: peerbroker.WebRTCICEServer + (*WebRTCICEServers)(nil), // 2: peerbroker.WebRTCICEServers + (*NegotiateConnection)(nil), // 3: peerbroker.NegotiateConnection + (*NegotiateConnection_ClientToServer)(nil), // 4: peerbroker.NegotiateConnection.ClientToServer + (*NegotiateConnection_ServerToClient)(nil), // 5: peerbroker.NegotiateConnection.ServerToClient +} +var file_peerbroker_proto_depIdxs = []int32{ + 1, // 0: peerbroker.WebRTCICEServers.servers:type_name -> peerbroker.WebRTCICEServer + 2, // 1: peerbroker.NegotiateConnection.ClientToServer.servers:type_name -> peerbroker.WebRTCICEServers + 0, // 2: peerbroker.NegotiateConnection.ClientToServer.offer:type_name -> peerbroker.WebRTCSessionDescription + 0, // 3: peerbroker.NegotiateConnection.ServerToClient.answer:type_name -> peerbroker.WebRTCSessionDescription + 4, // 4: peerbroker.PeerBroker.NegotiateConnection:input_type -> peerbroker.NegotiateConnection.ClientToServer + 5, // 5: peerbroker.PeerBroker.NegotiateConnection:output_type -> peerbroker.NegotiateConnection.ServerToClient + 5, // [5:6] is the sub-list for method output_type + 4, // [4:5] 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_peerbroker_proto_init() } +func file_peerbroker_proto_init() { + if File_peerbroker_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_peerbroker_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*WebRTCSessionDescription); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_peerbroker_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*WebRTCICEServer); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_peerbroker_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*WebRTCICEServers); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_peerbroker_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*NegotiateConnection); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_peerbroker_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*NegotiateConnection_ClientToServer); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_peerbroker_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*NegotiateConnection_ServerToClient); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + file_peerbroker_proto_msgTypes[4].OneofWrappers = []interface{}{ + (*NegotiateConnection_ClientToServer_Servers)(nil), + (*NegotiateConnection_ClientToServer_Offer)(nil), + (*NegotiateConnection_ClientToServer_IceCandidate)(nil), + } + file_peerbroker_proto_msgTypes[5].OneofWrappers = []interface{}{ + (*NegotiateConnection_ServerToClient_Answer)(nil), + (*NegotiateConnection_ServerToClient_IceCandidate)(nil), + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_peerbroker_proto_rawDesc, + NumEnums: 0, + NumMessages: 6, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_peerbroker_proto_goTypes, + DependencyIndexes: file_peerbroker_proto_depIdxs, + MessageInfos: file_peerbroker_proto_msgTypes, + }.Build() + File_peerbroker_proto = out.File + file_peerbroker_proto_rawDesc = nil + file_peerbroker_proto_goTypes = nil + file_peerbroker_proto_depIdxs = nil +} diff --git a/peerbroker/proto/peerbroker.proto b/peerbroker/proto/peerbroker.proto new file mode 100644 index 0000000000000..c4f660231c5a4 --- /dev/null +++ b/peerbroker/proto/peerbroker.proto @@ -0,0 +1,48 @@ + +syntax = "proto3"; +option go_package = "github.com/coder/coder/peerbroker/proto"; + +package peerbroker; + +message WebRTCSessionDescription { + int32 sdp_type = 1; + string sdp = 2; +} + +message WebRTCICEServer { + repeated string urls = 1; + string username = 2; + string credential = 3; + int32 credential_type = 4; +} + +message WebRTCICEServers { + repeated WebRTCICEServer servers = 1; +} + +message NegotiateConnection { + message ClientToServer { + oneof message { + WebRTCICEServers servers = 1; + WebRTCSessionDescription offer = 2; + string ice_candidate = 3; + } + } + message ServerToClient { + oneof message { + WebRTCSessionDescription answer = 1; + string ice_candidate = 2; + } + } +} + +// PeerBroker mediates WebRTC connection signaling. +service PeerBroker { + // NegotiateConnection establishes a bidirectional stream to negotiate a new WebRTC connection. + // 1. Client sends WebRTCSessionDescription and WebRTCICEServers to the server. + // 2. Server sends WebRTCSessionDescription to the client, exchanging encryption keys. + // 3. Client<->Server exchange ICE Candidates to establish a peered connection. + // + // See: https://davekilian.com/webrtc-the-hard-way.html + rpc NegotiateConnection(stream NegotiateConnection.ClientToServer) returns (stream NegotiateConnection.ServerToClient); +} diff --git a/peerbroker/proto/peerbroker_drpc.pb.go b/peerbroker/proto/peerbroker_drpc.pb.go new file mode 100644 index 0000000000000..bbf5e1e2c0cbd --- /dev/null +++ b/peerbroker/proto/peerbroker_drpc.pb.go @@ -0,0 +1,146 @@ +// Code generated by protoc-gen-go-drpc. DO NOT EDIT. +// protoc-gen-go-drpc version: v0.0.26 +// source: peerbroker.proto + +package proto + +import ( + context "context" + errors "errors" + protojson "google.golang.org/protobuf/encoding/protojson" + proto "google.golang.org/protobuf/proto" + drpc "storj.io/drpc" + drpcerr "storj.io/drpc/drpcerr" +) + +type drpcEncoding_File_peerbroker_proto struct{} + +func (drpcEncoding_File_peerbroker_proto) Marshal(msg drpc.Message) ([]byte, error) { + return proto.Marshal(msg.(proto.Message)) +} + +func (drpcEncoding_File_peerbroker_proto) MarshalAppend(buf []byte, msg drpc.Message) ([]byte, error) { + return proto.MarshalOptions{}.MarshalAppend(buf, msg.(proto.Message)) +} + +func (drpcEncoding_File_peerbroker_proto) Unmarshal(buf []byte, msg drpc.Message) error { + return proto.Unmarshal(buf, msg.(proto.Message)) +} + +func (drpcEncoding_File_peerbroker_proto) JSONMarshal(msg drpc.Message) ([]byte, error) { + return protojson.Marshal(msg.(proto.Message)) +} + +func (drpcEncoding_File_peerbroker_proto) JSONUnmarshal(buf []byte, msg drpc.Message) error { + return protojson.Unmarshal(buf, msg.(proto.Message)) +} + +type DRPCPeerBrokerClient interface { + DRPCConn() drpc.Conn + + NegotiateConnection(ctx context.Context) (DRPCPeerBroker_NegotiateConnectionClient, error) +} + +type drpcPeerBrokerClient struct { + cc drpc.Conn +} + +func NewDRPCPeerBrokerClient(cc drpc.Conn) DRPCPeerBrokerClient { + return &drpcPeerBrokerClient{cc} +} + +func (c *drpcPeerBrokerClient) DRPCConn() drpc.Conn { return c.cc } + +func (c *drpcPeerBrokerClient) NegotiateConnection(ctx context.Context) (DRPCPeerBroker_NegotiateConnectionClient, error) { + stream, err := c.cc.NewStream(ctx, "/peerbroker.PeerBroker/NegotiateConnection", drpcEncoding_File_peerbroker_proto{}) + if err != nil { + return nil, err + } + x := &drpcPeerBroker_NegotiateConnectionClient{stream} + return x, nil +} + +type DRPCPeerBroker_NegotiateConnectionClient interface { + drpc.Stream + Send(*NegotiateConnection_ClientToServer) error + Recv() (*NegotiateConnection_ServerToClient, error) +} + +type drpcPeerBroker_NegotiateConnectionClient struct { + drpc.Stream +} + +func (x *drpcPeerBroker_NegotiateConnectionClient) Send(m *NegotiateConnection_ClientToServer) error { + return x.MsgSend(m, drpcEncoding_File_peerbroker_proto{}) +} + +func (x *drpcPeerBroker_NegotiateConnectionClient) Recv() (*NegotiateConnection_ServerToClient, error) { + m := new(NegotiateConnection_ServerToClient) + if err := x.MsgRecv(m, drpcEncoding_File_peerbroker_proto{}); err != nil { + return nil, err + } + return m, nil +} + +func (x *drpcPeerBroker_NegotiateConnectionClient) RecvMsg(m *NegotiateConnection_ServerToClient) error { + return x.MsgRecv(m, drpcEncoding_File_peerbroker_proto{}) +} + +type DRPCPeerBrokerServer interface { + NegotiateConnection(DRPCPeerBroker_NegotiateConnectionStream) error +} + +type DRPCPeerBrokerUnimplementedServer struct{} + +func (s *DRPCPeerBrokerUnimplementedServer) NegotiateConnection(DRPCPeerBroker_NegotiateConnectionStream) error { + return drpcerr.WithCode(errors.New("Unimplemented"), drpcerr.Unimplemented) +} + +type DRPCPeerBrokerDescription struct{} + +func (DRPCPeerBrokerDescription) NumMethods() int { return 1 } + +func (DRPCPeerBrokerDescription) Method(n int) (string, drpc.Encoding, drpc.Receiver, interface{}, bool) { + switch n { + case 0: + return "/peerbroker.PeerBroker/NegotiateConnection", drpcEncoding_File_peerbroker_proto{}, + func(srv interface{}, ctx context.Context, in1, in2 interface{}) (drpc.Message, error) { + return nil, srv.(DRPCPeerBrokerServer). + NegotiateConnection( + &drpcPeerBroker_NegotiateConnectionStream{in1.(drpc.Stream)}, + ) + }, DRPCPeerBrokerServer.NegotiateConnection, true + default: + return "", nil, nil, nil, false + } +} + +func DRPCRegisterPeerBroker(mux drpc.Mux, impl DRPCPeerBrokerServer) error { + return mux.Register(impl, DRPCPeerBrokerDescription{}) +} + +type DRPCPeerBroker_NegotiateConnectionStream interface { + drpc.Stream + Send(*NegotiateConnection_ServerToClient) error + Recv() (*NegotiateConnection_ClientToServer, error) +} + +type drpcPeerBroker_NegotiateConnectionStream struct { + drpc.Stream +} + +func (x *drpcPeerBroker_NegotiateConnectionStream) Send(m *NegotiateConnection_ServerToClient) error { + return x.MsgSend(m, drpcEncoding_File_peerbroker_proto{}) +} + +func (x *drpcPeerBroker_NegotiateConnectionStream) Recv() (*NegotiateConnection_ClientToServer, error) { + m := new(NegotiateConnection_ClientToServer) + if err := x.MsgRecv(m, drpcEncoding_File_peerbroker_proto{}); err != nil { + return nil, err + } + return m, nil +} + +func (x *drpcPeerBroker_NegotiateConnectionStream) RecvMsg(m *NegotiateConnection_ClientToServer) error { + return x.MsgRecv(m, drpcEncoding_File_peerbroker_proto{}) +} diff --git a/provisioner/terraform/terraform.tfstate b/provisioner/terraform/terraform.tfstate deleted file mode 100644 index e69de29bb2d1d..0000000000000