diff --git a/cmd/sdk-server/main.go b/cmd/sdk-server/main.go index 05adf3f9a1..a482d4b920 100644 --- a/cmd/sdk-server/main.go +++ b/cmd/sdk-server/main.go @@ -30,8 +30,6 @@ import ( sdkalpha "agones.dev/agones/pkg/sdk/alpha" sdkbeta "agones.dev/agones/pkg/sdk/beta" "agones.dev/agones/pkg/sdkserver" - serveralpha "agones.dev/agones/pkg/sdkserver/alpha" - serverbeta "agones.dev/agones/pkg/sdkserver/beta" "agones.dev/agones/pkg/util/runtime" "agones.dev/agones/pkg/util/signals" gwruntime "github.com/grpc-ecosystem/grpc-gateway/runtime" @@ -154,8 +152,8 @@ func main() { } }() sdk.RegisterSDKServer(grpcServer, s) - sdkalpha.RegisterSDKServer(grpcServer, serveralpha.NewSDKServer()) - sdkbeta.RegisterSDKServer(grpcServer, serverbeta.NewSDKServer()) + sdkalpha.RegisterSDKServer(grpcServer, s) + sdkbeta.RegisterSDKServer(grpcServer, s) } grpcEndpoint := fmt.Sprintf("%s:%d", ctlConf.Address, ctlConf.GRPCPort) @@ -185,45 +183,37 @@ func registerLocal(grpcServer *grpc.Server, ctlConf config) (func(), error) { } } - stableSDK, err := sdkserver.NewLocalSDKServer(filePath) + s, err := sdkserver.NewLocalSDKServer(filePath) if err != nil { return nil, err } - alphaSDK := serveralpha.NewLocalSDKServer() - betaSDK := serverbeta.NewLocalSDKServer() - sdk.RegisterSDKServer(grpcServer, stableSDK) - sdkalpha.RegisterSDKServer(grpcServer, alphaSDK) - sdkbeta.RegisterSDKServer(grpcServer, betaSDK) + sdk.RegisterSDKServer(grpcServer, s) + sdkalpha.RegisterSDKServer(grpcServer, s) + sdkbeta.RegisterSDKServer(grpcServer, s) return func() { - alphaSDK.Close() - betaSDK.Close() - stableSDK.Close() + s.Close() }, err } // registerLocal registers the local test SDK servers, and returns a cancel func that // closes all the SDK implementations func registerTestSdkServer(grpcServer *grpc.Server, ctlConf config) (func(), error) { - stableSDK, err := sdkserver.NewLocalSDKServer("") + s, err := sdkserver.NewLocalSDKServer("") if err != nil { return nil, err } - alphaSDK := serveralpha.NewLocalSDKServer() - betaSDK := serverbeta.NewLocalSDKServer() - stableSDK.SetTestMode(true) - stableSDK.GenerateUID() + s.SetTestMode(true) + s.GenerateUID() expectedFuncs := strings.Split(ctlConf.Test, ",") - stableSDK.SetExpectedSequence(expectedFuncs) + s.SetExpectedSequence(expectedFuncs) - sdk.RegisterSDKServer(grpcServer, stableSDK) - sdkalpha.RegisterSDKServer(grpcServer, alphaSDK) - sdkbeta.RegisterSDKServer(grpcServer, betaSDK) + sdk.RegisterSDKServer(grpcServer, s) + sdkalpha.RegisterSDKServer(grpcServer, s) + sdkbeta.RegisterSDKServer(grpcServer, s) return func() { - alphaSDK.Close() - betaSDK.Close() - stableSDK.Close() + s.Close() }, err } @@ -281,7 +271,7 @@ func parseEnvFlags() config { pflag.Int(httpPortFlag, viper.GetInt(httpPortFlag), fmt.Sprintf("Port on which to bind the HTTP server. Defaults to %d", defaultHTTPPort)) pflag.Int(delayFlag, viper.GetInt(delayFlag), "Time to delay (in seconds) before starting to execute main. Useful for tests") pflag.Int(timeoutFlag, viper.GetInt(timeoutFlag), "Time of execution (in seconds) before close. Useful for tests") - pflag.String(testFlag, viper.GetString(testFlag), "List functions which shoud be called during the SDK Conformance test run.") + pflag.String(testFlag, viper.GetString(testFlag), "List functions which should be called during the SDK Conformance test run.") runtime.FeaturesBindFlags() pflag.Parse() diff --git a/pkg/apis/agones/v1/gameserver.go b/pkg/apis/agones/v1/gameserver.go index 32e287f9ee..35cf88e0ee 100644 --- a/pkg/apis/agones/v1/gameserver.go +++ b/pkg/apis/agones/v1/gameserver.go @@ -313,10 +313,12 @@ func (gs *GameServer) applyStatusDefaults() { } if runtime.FeatureEnabled(runtime.FeaturePlayerTracking) { + // set value if enabled, otherwise very easy to accidentally panic + // when gs.Status.Players is nil + if gs.Status.Players == nil { + gs.Status.Players = &PlayerStatus{} + } if gs.Spec.Players != nil { - if gs.Status.Players == nil { - gs.Status.Players = &PlayerStatus{} - } gs.Status.Players.Capacity = gs.Spec.Players.InitialCapacity } } diff --git a/pkg/sdkserver/alpha/localsdk.go b/pkg/sdkserver/alpha/localsdk.go deleted file mode 100644 index fb48a0c34c..0000000000 --- a/pkg/sdkserver/alpha/localsdk.go +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2020 Google LLC All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package alpha - -import ( - "context" - - "agones.dev/agones/pkg/sdk/alpha" -) - -var _ alpha.SDKServer = LocalSDKServer{} - -// LocalSDKServer is the local sdk server implementation -// for alpha features. -type LocalSDKServer struct{} - -// NewLocalSDKServer is a constructor for the alpha local SDK Server. -func NewLocalSDKServer() *LocalSDKServer { - return &LocalSDKServer{} -} - -// Close tears down all the things. -func (l *LocalSDKServer) Close() { - // placeholder in case things need to be shut down -} - -// PlayerConnect should be called when a player connects. -func (l LocalSDKServer) PlayerConnect(ctx context.Context, id *alpha.PlayerId) (*alpha.Empty, error) { - panic("implement me") -} - -// PlayerDisconnect should be called when a player disconnects. -func (l LocalSDKServer) PlayerDisconnect(ctx context.Context, id *alpha.PlayerId) (*alpha.Empty, error) { - panic("implement me") -} - -// SetPlayerCapacity to change the game server's player capacity. -func (l LocalSDKServer) SetPlayerCapacity(ctx context.Context, count *alpha.Count) (*alpha.Empty, error) { - panic("implement me") -} - -// GetPlayerCapacity returns the current player capacity. -func (l LocalSDKServer) GetPlayerCapacity(ctx context.Context, _ *alpha.Empty) (*alpha.Count, error) { - panic("implement me") -} - -// GetPlayerCount returns the current player count. -func (l LocalSDKServer) GetPlayerCount(ctx context.Context, _ *alpha.Empty) (*alpha.Count, error) { - panic("implement me") -} diff --git a/pkg/sdkserver/alpha/sdkserver.go b/pkg/sdkserver/alpha/sdkserver.go deleted file mode 100644 index 8e881f2963..0000000000 --- a/pkg/sdkserver/alpha/sdkserver.go +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2020 Google LLC All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package alpha - -import ( - "context" - - "agones.dev/agones/pkg/sdk/alpha" -) - -var _ alpha.SDKServer = SDKServer{} - -// SDKServer is the local sdk server implementation -// for alpha features. -type SDKServer struct{} - -// NewSDKServer is a constructor for the alpha SDK Server. -func NewSDKServer() *SDKServer { - return &SDKServer{} -} - -// PlayerConnect should be called when a player connects. -func (s SDKServer) PlayerConnect(ctx context.Context, id *alpha.PlayerId) (*alpha.Empty, error) { - panic("implement me") -} - -// PlayerDisconnect should be called when a player disconnects. -func (s SDKServer) PlayerDisconnect(ctx context.Context, id *alpha.PlayerId) (*alpha.Empty, error) { - panic("implement me") -} - -// SetPlayerCapacity to change the game server's player capacity. -func (s SDKServer) SetPlayerCapacity(ctx context.Context, count *alpha.Count) (*alpha.Empty, error) { - panic("implement me") -} - -// GetPlayerCapacity returns the current player capacity. -func (s SDKServer) GetPlayerCapacity(ctx context.Context, _ *alpha.Empty) (*alpha.Count, error) { - panic("implement me") -} - -// GetPlayerCount returns the current player count. -func (s SDKServer) GetPlayerCount(ctx context.Context, _ *alpha.Empty) (*alpha.Count, error) { - panic("implement me") -} diff --git a/pkg/sdkserver/beta/localsdk.go b/pkg/sdkserver/beta/localsdk.go deleted file mode 100644 index f5283f96cb..0000000000 --- a/pkg/sdkserver/beta/localsdk.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2020 Google LLC All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package beta - -import "agones.dev/agones/pkg/sdk/beta" - -var _ beta.SDKServer = LocalSDKServer{} - -// LocalSDKServer is the local sdk server implementation -// for beta features -type LocalSDKServer struct{} - -// NewLocalSDKServer is a constructor for the beta local SDK Server -func NewLocalSDKServer() *LocalSDKServer { - return &LocalSDKServer{} -} - -// Close tears down all the things -func (l *LocalSDKServer) Close() { - // placeholder in case things need to be shut down -} diff --git a/pkg/sdkserver/beta/sdkserver.go b/pkg/sdkserver/beta/sdkserver.go deleted file mode 100644 index 3adc84801e..0000000000 --- a/pkg/sdkserver/beta/sdkserver.go +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2020 Google LLC All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package beta - -import "agones.dev/agones/pkg/sdk/beta" - -var _ beta.SDKServer = SDKServer{} - -// SDKServer is the sdk server implementation -// for beta features -type SDKServer struct{} - -// NewSDKServer is a constructor for the beta SDK Server -func NewSDKServer() *SDKServer { - return &SDKServer{} -} diff --git a/pkg/sdkserver/localsdk.go b/pkg/sdkserver/localsdk.go index 63b8af0f59..4f1d06cff2 100644 --- a/pkg/sdkserver/localsdk.go +++ b/pkg/sdkserver/localsdk.go @@ -25,6 +25,8 @@ import ( agonesv1 "agones.dev/agones/pkg/apis/agones/v1" "agones.dev/agones/pkg/sdk" + "agones.dev/agones/pkg/sdk/alpha" + "agones.dev/agones/pkg/sdk/beta" "github.com/fsnotify/fsnotify" "github.com/pkg/errors" "github.com/sirupsen/logrus" @@ -33,7 +35,9 @@ import ( ) var ( - _ sdk.SDKServer = &LocalSDKServer{} + _ sdk.SDKServer = &LocalSDKServer{} + _ alpha.SDKServer = &LocalSDKServer{} + _ beta.SDKServer = &LocalSDKServer{} defaultGs = &sdk.GameServer{ ObjectMeta: &sdk.GameServer_ObjectMeta{ @@ -425,3 +429,30 @@ func (l *LocalSDKServer) setGameServerFromFilePath(filePath string) error { l.gs = convert(&gs) return nil } + +/* Alpha Functionality */ + +// PlayerConnect should be called when a player connects. +func (l *LocalSDKServer) PlayerConnect(ctx context.Context, id *alpha.PlayerId) (*alpha.Empty, error) { + panic("implement me") +} + +// PlayerDisconnect should be called when a player disconnects. +func (l *LocalSDKServer) PlayerDisconnect(ctx context.Context, id *alpha.PlayerId) (*alpha.Empty, error) { + panic("implement me") +} + +// SetPlayerCapacity to change the game server's player capacity. +func (l *LocalSDKServer) SetPlayerCapacity(ctx context.Context, count *alpha.Count) (*alpha.Empty, error) { + panic("implement me") +} + +// GetPlayerCapacity returns the current player capacity. +func (l *LocalSDKServer) GetPlayerCapacity(ctx context.Context, _ *alpha.Empty) (*alpha.Count, error) { + panic("implement me") +} + +// GetPlayerCount returns the current player count. +func (l *LocalSDKServer) GetPlayerCount(ctx context.Context, _ *alpha.Empty) (*alpha.Count, error) { + panic("implement me") +} diff --git a/pkg/sdkserver/sdkserver.go b/pkg/sdkserver/sdkserver.go index b305d3a4de..db7c467b8e 100644 --- a/pkg/sdkserver/sdkserver.go +++ b/pkg/sdkserver/sdkserver.go @@ -29,6 +29,8 @@ import ( "agones.dev/agones/pkg/client/informers/externalversions" listersv1 "agones.dev/agones/pkg/client/listers/agones/v1" "agones.dev/agones/pkg/sdk" + "agones.dev/agones/pkg/sdk/alpha" + "agones.dev/agones/pkg/sdk/beta" "agones.dev/agones/pkg/util/logfields" "agones.dev/agones/pkg/util/runtime" "agones.dev/agones/pkg/util/workerqueue" @@ -51,12 +53,17 @@ import ( type Operation string const ( - updateState Operation = "updateState" - updateLabel Operation = "updateLabel" - updateAnnotation Operation = "updateAnnotation" + updateState Operation = "updateState" + updateLabel Operation = "updateLabel" + updateAnnotation Operation = "updateAnnotation" + updatePlayerCapacity Operation = "updatePlayerCapacity" ) -var _ sdk.SDKServer = &SDKServer{} +var ( + _ sdk.SDKServer = &SDKServer{} + _ alpha.SDKServer = &LocalSDKServer{} + _ beta.SDKServer = &LocalSDKServer{} +) // SDKServer is a gRPC server, that is meant to be a sidecar // for a GameServer that will update the game server status on SDK requests @@ -88,6 +95,7 @@ type SDKServer struct { gsWaitForSync sync.WaitGroup reserveTimer *time.Timer gsReserveDuration *time.Duration + gsPlayerCapacity int64 } // NewSDKServer creates a SDKServer that sets up an @@ -222,6 +230,13 @@ func (s *SDKServer) Run(stop <-chan struct{}) error { go wait.Until(s.runHealth, s.healthTimeout, stop) } + // populate player capacity value + if runtime.FeatureEnabled(runtime.FeaturePlayerTracking) { + s.gsUpdateMutex.Lock() + s.gsPlayerCapacity = gs.Status.Players.Capacity + s.gsUpdateMutex.Unlock() + } + // then start the http endpoints s.logger.Debug("Starting SDKServer http health check...") go func() { @@ -253,6 +268,8 @@ func (s *SDKServer) syncGameServer(key string) error { return s.updateLabels() case updateAnnotation: return s.updateAnnotations() + case updatePlayerCapacity: + return s.updatePlayerCapacity() } return errors.Errorf("could not sync game server key: %s", key) @@ -588,3 +605,66 @@ func (s *SDKServer) healthy() bool { defer s.healthMutex.RUnlock() return s.healthFailureCount < s.health.FailureThreshold } + +/* Alpha Functionality */ + +// PlayerConnect should be called when a player connects. +func (s *SDKServer) PlayerConnect(ctx context.Context, id *alpha.PlayerId) (*alpha.Empty, error) { + panic("implement me") +} + +// PlayerDisconnect should be called when a player disconnects. +func (s *SDKServer) PlayerDisconnect(ctx context.Context, id *alpha.PlayerId) (*alpha.Empty, error) { + panic("implement me") +} + +// GetPlayerCount returns the current player count. +func (s *SDKServer) GetPlayerCount(ctx context.Context, _ *alpha.Empty) (*alpha.Count, error) { + panic("implement me") +} + +// SetPlayerCapacity to change the game server's player capacity. +func (s *SDKServer) SetPlayerCapacity(ctx context.Context, count *alpha.Count) (*alpha.Empty, error) { + if !runtime.FeatureEnabled(runtime.FeaturePlayerTracking) { + return nil, errors.New(string(runtime.FeaturePlayerTracking) + " not enabled") + } + s.gsUpdateMutex.Lock() + s.gsPlayerCapacity = count.Count + s.gsUpdateMutex.Unlock() + s.workerqueue.Enqueue(cache.ExplicitKey(string(updatePlayerCapacity))) + + return &alpha.Empty{}, nil +} + +// GetPlayerCapacity returns the current player capacity. +func (s *SDKServer) GetPlayerCapacity(ctx context.Context, _ *alpha.Empty) (*alpha.Count, error) { + if !runtime.FeatureEnabled(runtime.FeaturePlayerTracking) { + return nil, errors.New(string(runtime.FeaturePlayerTracking) + " not enabled") + } + s.gsUpdateMutex.RLock() + defer s.gsUpdateMutex.RUnlock() + + count := &alpha.Count{Count: s.gsPlayerCapacity} + return count, nil +} + +// updatePlayerCapacity updates the Player Capacity field in the GameServer's Status. +func (s *SDKServer) updatePlayerCapacity() error { + if !runtime.FeatureEnabled(runtime.FeaturePlayerTracking) { + return errors.New(string(runtime.FeaturePlayerTracking) + " not enabled") + } + s.logger.WithField("capacity", s.gsPlayerCapacity).Debug("updating player capacity") + gs, err := s.gameServer() + if err != nil { + return err + } + + gsCopy := gs.DeepCopy() + + s.gsUpdateMutex.RLock() + gsCopy.Status.Players.Capacity = s.gsPlayerCapacity + s.gsUpdateMutex.RUnlock() + + _, err = s.gameServerGetter.GameServers(s.namespace).Update(gsCopy) + return err +} diff --git a/pkg/sdkserver/sdkserver_test.go b/pkg/sdkserver/sdkserver_test.go index 360134af4f..bd338f5fec 100644 --- a/pkg/sdkserver/sdkserver_test.go +++ b/pkg/sdkserver/sdkserver_test.go @@ -22,7 +22,9 @@ import ( agonesv1 "agones.dev/agones/pkg/apis/agones/v1" "agones.dev/agones/pkg/sdk" + "agones.dev/agones/pkg/sdk/alpha" agtesting "agones.dev/agones/pkg/testing" + agruntime "agones.dev/agones/pkg/util/runtime" "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" "golang.org/x/net/context" @@ -906,6 +908,83 @@ func TestSDKServerReserveTimeout(t *testing.T) { wg.Wait() } +/* Alpha Functionality */ + +func TestSDKServerPlayerCapacity(t *testing.T) { + t.Parallel() + agruntime.FeatureTestMutex.Lock() + defer agruntime.FeatureTestMutex.Unlock() + + err := agruntime.ParseFeatures(string(agruntime.FeaturePlayerTracking) + "=true") + assert.NoError(t, err) + + m := agtesting.NewMocks() + stop := make(chan struct{}) + defer close(stop) + + sc, err := defaultSidecar(m) + assert.Nil(t, err) + + m.AgonesClient.AddReactor("list", "gameservers", func(action k8stesting.Action) (bool, runtime.Object, error) { + gs := agonesv1.GameServer{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", Namespace: "default", + }, + Spec: agonesv1.GameServerSpec{ + SdkServer: agonesv1.SdkServer{ + LogLevel: "Debug", + }, + Players: &agonesv1.PlayersSpec{ + InitialCapacity: 10, + }, + }, + } + gs.ApplyDefaults() + return true, &agonesv1.GameServerList{Items: []agonesv1.GameServer{gs}}, nil + }) + + updated := make(chan int64, 10) + m.AgonesClient.AddReactor("update", "gameservers", func(action k8stesting.Action) (bool, runtime.Object, error) { + ua := action.(k8stesting.UpdateAction) + gs := ua.GetObject().(*agonesv1.GameServer) + updated <- gs.Status.Players.Capacity + return true, gs, nil + }) + + sc.informerFactory.Start(stop) + assert.True(t, cache.WaitForCacheSync(stop, sc.gameServerSynced)) + + go func() { + err = sc.Run(stop) + assert.NoError(t, err) + }() + + // check initial value comes through + + // async, so check after a period + err = wait.Poll(time.Second, 10*time.Second, func() (bool, error) { + count, err := sc.GetPlayerCapacity(context.Background(), &alpha.Empty{}) + return count.Count == 10, err + }) + assert.NoError(t, err) + + // on update from the SDK, the value is available from GetPlayerCapacity + _, err = sc.SetPlayerCapacity(context.Background(), &alpha.Count{Count: 20}) + assert.NoError(t, err) + + count, err := sc.GetPlayerCapacity(context.Background(), &alpha.Empty{}) + assert.NoError(t, err) + assert.Equal(t, int64(20), count.Count) + + // on an update, confirm that the update hits the K8s api + select { + case value := <-updated: + assert.Equal(t, int64(20), value) + case <-time.After(time.Minute): + assert.Fail(t, "Should have been updated") + } +} + func defaultSidecar(m agtesting.Mocks) (*SDKServer, error) { server, err := NewSDKServer("test", "default", m.KubeClient, m.AgonesClient) if err != nil { diff --git a/proto/sdk/alpha/alpha.proto b/proto/sdk/alpha/alpha.proto index 67916581e2..280f932dea 100644 --- a/proto/sdk/alpha/alpha.proto +++ b/proto/sdk/alpha/alpha.proto @@ -37,7 +37,7 @@ service SDK { }; } - // change the player capacity to a new value + // changes the player capacity to a new value rpc SetPlayerCapacity (Count) returns (Empty) { option (google.api.http) = { post: "/alpha/player/capacity" @@ -45,7 +45,8 @@ service SDK { }; } - // get the current player capacity + // Get the last player capacity that was set through the SDK. + // If the player capacity is set from outside the SDK, use SDK.GameServer() instead. rpc GetPlayerCapacity(Empty) returns (Count) { option (google.api.http) = { get: "/alpha/player/capacity" diff --git a/sdks/go/alpha.go b/sdks/go/alpha.go new file mode 100644 index 0000000000..11edb00e72 --- /dev/null +++ b/sdks/go/alpha.go @@ -0,0 +1,50 @@ +// Copyright 2020 Google LLC All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package sdk + +import ( + "context" + + "agones.dev/agones/pkg/sdk/alpha" + "github.com/pkg/errors" + "google.golang.org/grpc" +) + +// Alpha is the struct for Alpha SDK functionality +type Alpha struct { + client alpha.SDKClient + ctx context.Context +} + +// newAlpha creates a new Alpha SDK with the passed in connection. +func newAlpha(conn *grpc.ClientConn) *Alpha { + return &Alpha{ + ctx: context.Background(), + client: alpha.NewSDKClient(conn), + } +} + +// GetPlayerCapacity gets the last player capacity that was set through the SDK. +// If the player capacity is set from outside the SDK, use SDK.Alpha.GameServer() instead. +func (a *Alpha) GetPlayerCapacity() (int64, error) { + c, err := a.client.GetPlayerCapacity(a.ctx, &alpha.Empty{}) + return c.Count, errors.Wrap(err, "could not get player capacity") +} + +// SetPlayerCapacity changes the player capacity to a new value +func (a *Alpha) SetPlayerCapacity(capacity int64) error { + _, err := a.client.SetPlayerCapacity(a.ctx, &alpha.Count{Count: capacity}) + return errors.Wrap(err, "could not set player capacity") +} diff --git a/sdks/go/alpha_test.go b/sdks/go/alpha_test.go new file mode 100644 index 0000000000..8fa3e0558a --- /dev/null +++ b/sdks/go/alpha_test.go @@ -0,0 +1,65 @@ +// Copyright 2020 Google LLC All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package sdk + +import ( + "context" + "testing" + + "agones.dev/agones/pkg/sdk/alpha" + "github.com/stretchr/testify/assert" + "google.golang.org/grpc" +) + +func TestAlphaGetAndSetPlayerCapacity(t *testing.T) { + mock := &alphaMock{} + a := Alpha{ + ctx: context.Background(), + client: mock, + } + + err := a.SetPlayerCapacity(15) + assert.NoError(t, err) + assert.Equal(t, int64(15), mock.capacity) + + capacity, err := a.GetPlayerCapacity() + assert.NoError(t, err) + assert.Equal(t, int64(15), capacity) +} + +type alphaMock struct { + capacity int64 +} + +func (a *alphaMock) PlayerConnect(ctx context.Context, in *alpha.PlayerId, opts ...grpc.CallOption) (*alpha.Empty, error) { + panic("implement me") +} + +func (a *alphaMock) PlayerDisconnect(ctx context.Context, in *alpha.PlayerId, opts ...grpc.CallOption) (*alpha.Empty, error) { + panic("implement me") +} + +func (a *alphaMock) SetPlayerCapacity(ctx context.Context, in *alpha.Count, opts ...grpc.CallOption) (*alpha.Empty, error) { + a.capacity = in.Count + return &alpha.Empty{}, nil +} + +func (a *alphaMock) GetPlayerCapacity(ctx context.Context, in *alpha.Empty, opts ...grpc.CallOption) (*alpha.Count, error) { + return &alpha.Count{Count: a.capacity}, nil +} + +func (a *alphaMock) GetPlayerCount(ctx context.Context, in *alpha.Empty, opts ...grpc.CallOption) (*alpha.Count, error) { + panic("implement me") +} diff --git a/sdks/go/sdk.go b/sdks/go/sdk.go index 7e67d384de..3d3dfddc13 100644 --- a/sdks/go/sdk.go +++ b/sdks/go/sdk.go @@ -36,6 +36,7 @@ type SDK struct { client sdk.SDKClient ctx context.Context health sdk.SDK_HealthClient + alpha *Alpha } // NewSDK starts a new SDK instance, and connects to @@ -59,9 +60,15 @@ func NewSDK() (*SDK, error) { } s.client = sdk.NewSDKClient(conn) s.health, err = s.client.Health(s.ctx) + s.alpha = newAlpha(conn) return s, errors.Wrap(err, "could not set up health check") } +// Alpha returns the Alpha SDK +func (s *SDK) Alpha() *Alpha { + return s.alpha +} + // Ready marks the Game Server as ready to // receive connections func (s *SDK) Ready() error {