feat: Create broker for negotiating connections (#14)

* feat: Create broker for negotiating connections

WebRTC require an exchange of encryption keys and network hops to connect. This package pipes the exchange over gRPC. This will be used in all connecting clients and agents.

* Regenerate protobuf definition

* Cache Go build and test

* Fix gRPC language with dRPC

Co-authored-by: Bryan <bryan@coder.com>

Co-authored-by: Bryan <bryan@coder.com>
This commit is contained in:
Kyle Carberry 2022-01-11 09:28:41 -06:00 committed by GitHub
parent 7c260f88d1
commit 53cfa8a45a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 1258 additions and 1 deletions

1
.gitattributes vendored
View File

@ -1,2 +1,3 @@
# Generated files
peerbroker/proto/*.go linguist-generated=true
provisionersdk/proto/*.go linguist-generated=true

View File

@ -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:

View File

@ -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 \

View File

@ -21,4 +21,5 @@ coverage:
ignore:
# This is generated code.
- peerbroker/proto
- provisionersdk/proto

View File

@ -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:

View File

@ -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)

113
peerbroker/dial.go Normal file
View File

@ -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
}

48
peerbroker/dial_test.go Normal file
View File

@ -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)
})
}

195
peerbroker/listen.go Normal file
View File

@ -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
}

49
peerbroker/listen_test.go Normal file
View File

@ -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)
})
}

610
peerbroker/proto/peerbroker.pb.go generated Normal file
View File

@ -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
}

View File

@ -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);
}

146
peerbroker/proto/peerbroker_drpc.pb.go generated Normal file
View File

@ -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{})
}