Skip to content

Commit

Permalink
Support bidirectional streaming using WebSockets (minekube#2)
Browse files Browse the repository at this point in the history
  • Loading branch information
robinbraemer authored Mar 2, 2022
1 parent 98f4e78 commit 0207f68
Show file tree
Hide file tree
Showing 27 changed files with 925 additions and 94 deletions.
28 changes: 16 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,21 @@ with our highly available, performant and low latency edge proxies network neare
## Features

- [x] ProtoBuf/gRPC service API definitions
- [x] Client side service tooling in Go
- [x] Server side service tooling in Go
- [ ] Minekube Connect plugin support for:
- [ ] [Gate](https://github.com/minekube/gate)
- [ ] Spigot/PaperMC
- [ ] Velocity
- [ ] BungeeCord
- [x] ProtoBuf typed
- [x] Streaming transport protocols
- [x] WebSocket support
- equally or more efficient than gRPC
- better web proxy support: cloudflared, nginx, ...
- [ ] gRPC support (improved developer experience)
- No immediate support planned, [see](internal/grpc)
- [x] Minekube Connect plugin support for:
- [x] [Gate](https://github.com/minekube/gate)
- [x] [Spigot/PaperMC](https://github.com/minekube/connect-java)
- [x] [Velocity](https://github.com/minekube/connect-java)
- [x] [BungeeCord](https://github.com/minekube/connect-java)
- [ ] Sponge
- [ ] Minestom
- [ ] Client side service tooling in Java
- [x] Provide test tunnel service implementation in Go
- [ ] Provide test tunnel service implementation in Java
- [ ] Easy documentation website
- [x] Client side service tooling in Go
- [x] Server side service tooling in Go
- [x] Client- & service-side tests implementation in Go
- [ ] Awesome documentation website
45 changes: 4 additions & 41 deletions aliases.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package connect

import (
pb "go.minekube.com/connect/internal/api/minekube/connect/v1alpha1"
"google.golang.org/genproto/googleapis/rpc/status"

pb "go.minekube.com/connect/internal/api/minekube/connect/v1alpha1"
)

// Type alias to better support updating versions.
Expand All @@ -21,44 +22,6 @@ type (
GameProfile = pb.GameProfile
GameProfileProperty = pb.GameProfileProperty

WatchServiceClient = pb.WatchServiceClient
WatchServiceServer = pb.WatchServiceServer
WatchService_WatchClient = pb.WatchService_WatchClient
WatchService_WatchServer = pb.WatchService_WatchServer
WatchRequest = pb.WatchRequest
WatchResponse = pb.WatchResponse

TunnelServiceClient = pb.TunnelServiceClient
TunnelServiceServer = pb.TunnelServiceServer
TunnelService_TunnelClient = pb.TunnelService_TunnelClient
TunnelService_TunnelServer = pb.TunnelService_TunnelServer
TunnelRequest = pb.TunnelRequest
TunnelResponse = pb.TunnelResponse

UnimplementedWatchServiceServer struct {
pb.UnimplementedWatchServiceServer
}
UnimplementedTunnelServiceServer struct {
pb.UnimplementedTunnelServiceServer
}
)

// Alias to better support updating versions.
// See the referenced type for documentation.
//
// Other go files should only ever use the provided
// alias type and never import a specific proto version.
var (
NewWatchServiceClient = pb.NewWatchServiceClient
NewTunnelServiceClient = pb.NewTunnelServiceClient

RegisterWatchServiceServer = pb.RegisterWatchServiceServer
RegisterTunnelServiceServer = pb.RegisterTunnelServiceServer
)

// Well-known metadata keys
const (
MDPrefix = "connect-" // The prefix of metadata keys.
MDSession = MDPrefix + "session" // Metadata key specifying the session id when calling the TunnelService.
MDEndpoint = MDPrefix + "endpoint" // Metadata key specifying the endpoint when calling the WatchService.
WatchRequest = pb.WatchRequest
WatchResponse = pb.WatchResponse
)
6 changes: 3 additions & 3 deletions api/buf.lock
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@ deps:
owner: googleapis
repository: googleapis
branch: main
commit: 0b64ae0918a6421b8deeffb20bd7c58a
digest: b1-rcRLiZYvmis9EDBO1iRVlWakV5U988o2oNLyldwzo6Q=
create_time: 2022-02-24T15:04:40.484238Z
commit: 6f475a54b1614e6cafd96fd376b1738d
digest: b1-a7t276NpOOZlwSgobbKDlRuKe1lyAcZHdiangmLShGg=
create_time: 2022-03-02T15:12:37.274824Z
106 changes: 106 additions & 0 deletions connect.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package connect

import (
"context"
"net"

"go.minekube.com/connect/internal/ctxkey"
)

// Well-known headers / metadata keys
const (
MDPrefix = "connect-" // The prefix of Connect metadata keys.
MDSession = MDPrefix + "session" // Metadata key specifying the session id for a Tunnel.
MDEndpoint = MDPrefix + "endpoint" // Metadata key specifying the watching Endpoint.
)

// Tunnel represents an outbound only tunnel initiated by
// an Endpoint for a specific SessionProposal.
type Tunnel net.Conn

// Tunneler creates a Tunnel.
type Tunneler interface {
Tunnel(context.Context) (Tunnel, error)
}

// Watcher registers the calling endpoint and watches for sessions
// proposed by the WatchService. To stop watching cancel the context.
// If ReceiveProposal returns a non-nil non-EOF error Watch returns it.
type Watcher interface {
Watch(context.Context, ReceiveProposal) error
}

// ReceiveProposal is called when Watcher receives a SessionProposal.
type ReceiveProposal func(proposal SessionProposal) error

// SessionProposal specifies an incoming session proposal.
// Use the Session to create the connection tunnel or reject the session with an optional reason.
type SessionProposal interface {
Session() *Session // The session proposed to connect to the Endpoint.
Reject(context.Context, *RejectionReason) error // Rejects the session proposal with an optional reason.
}

// Endpoint is an endpoint that listens for
// sessions to either reject them or establish
// a tunnel for receiving the connection.
type Endpoint interface {
Watcher
Tunneler
}

// TunnelListener is a network listener for tunnel connections.
type TunnelListener interface {
AcceptTunnel(context.Context, Tunnel) error
}

// EndpointListener is a network listener for endpoint watches.
type EndpointListener interface {
AcceptEndpoint(context.Context, EndpointWatch) error
}

// EndpointWatch is a watching Endpoint.
type EndpointWatch interface {
// Propose proposes a session to the Endpoint.
// The Endpoint either rejects the proposal or initiates
// a Tunnel to receive the session connection.
Propose(context.Context, *Session) error
Rejections() <-chan *SessionRejection // Rejections receives rejected session proposals from the Endpoint.
}

// Listener listens for watching endpoints and tunnel connections from endpoints.
type Listener interface {
EndpointListener
TunnelListener
}

// TunnelOptions are options for Tunneler and TunnelListener.
// Use WithTunnelOptions to propagate TunnelOptions in context.
type TunnelOptions struct {
// LocalAddr fakes the local address of the Tunnel when specified.
//
// If this TunnelOptions destine to Tunneler
// it is recommended to use the Endpoint address/name.
//
// If this TunnelOptions destine to TunnelListener
// it is recommended to use the underlying network listener address.
LocalAddr net.Addr
// RemoteAddr fakes the remote address of the Tunnel when specified.
//
// If this TunnelOptions destine to Tunneler
// it is recommended to use the underlying connection remote address.
//
// If this TunnelOptions destine to TunnelListener
// it is recommended to use the Endpoint address/name.
RemoteAddr net.Addr // It is recommended to use the player address.
}

// WithTunnelOptions stores TunnelOptions in a context.
func WithTunnelOptions(ctx context.Context, opts TunnelOptions) context.Context {
return context.WithValue(ctx, ctxkey.TunnelOptions{}, opts)
}

// Addr is an address in the "connect" network.
type Addr string

func (a Addr) String() string { return string(a) }
func (a Addr) Network() string { return "connect" }
17 changes: 14 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,25 @@ require (
google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350
google.golang.org/grpc v1.44.0
google.golang.org/protobuf v1.27.1
nhooyr.io/websocket v1.8.7
)

require (
github.com/davecgh/go-spew v1.1.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/gobwas/ws v1.1.0 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/google/go-cmp v0.5.7 // indirect
github.com/gorilla/websocket v1.5.0 // indirect
github.com/klauspost/compress v1.14.4 // indirect
github.com/kr/pretty v0.1.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd // indirect
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27 // indirect
golang.org/x/text v0.3.7 // indirect
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect
)

require (
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd // indirect
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27 // indirect
)
Loading

0 comments on commit 0207f68

Please sign in to comment.