diff --git a/.gitignore b/.gitignore index fdc48d6ecd..10a921e8f7 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,4 @@ !.gitignore *.iml bin +*.o \ No newline at end of file diff --git a/README.md b/README.md index ce333a0904..b76f0fb040 100644 --- a/README.md +++ b/README.md @@ -3,15 +3,12 @@ Agon is a library for running dedicated game servers on [Kubernetes](https://kubernetes.io). ## Disclaimer -This software is currenty alpha, and subject to change. Not to be used in production systems. +This software is currently alpha, and subject to change. Not to be used in production systems. -## Roadmap for 0.1 release -- Develop a [Custom Resource Defintion](https://kubernetes.io/docs/concepts/api-extension/custom-resources/#customresourcedefinitions) for dedicated game server -- Sidecar for managing the DGS lifecycle and recorded status, e.g. registering the port the server has started on -- A Kubernetes operator that registers the CRD, and creates a Pod with the DGS in it, with the accompanying sidecar for system registration. -- A basic client library for integration with a DGS -- Simple example code -- Documentation of the above +## Major Features +- Be able to define a `GameServer` within Kubernetes - either through yaml or the via API +- Manage GameServer lifecycles - including health checking and connection information. +- Client SDKs for integration with dedicated game servers to work with Agon. ## Requirements - Requires a Kubernetes cluster of version 1.8+ @@ -26,10 +23,14 @@ and edit to match your settings. _Note:_ There has yet to be a release of Agon, so you will need to edit the `install.yaml` to specify a development release or [build from source](build/README.md) +## Game Server SDKs +Game Servers are required to have the [Agon SDK](sdks) integrated, to help manage Game Server state, health checking +and more. + ## Usage See the [examples](./examples) directory -## Development +## Development and Contribution See the tools in the [build](build/README.md) directory for testing and building Agon from source. ## Licence diff --git a/build/Makefile b/build/Makefile index f8b854f87a..ec4e3a4a45 100644 --- a/build/Makefile +++ b/build/Makefile @@ -68,7 +68,13 @@ go_version_flags = -ldflags "-X github.com/agonio/agon/pkg.Version=$(VERSION)" # |___/ # build all -build: build-gameservers-controller-image build-gameservers-sidecar-image +build: build-images build-sdks + +# build the docker images +build-images: build-gameservers-controller-image build-gameservers-sidecar-image + +#build all the sdks +build-sdks: build-sdk-cpp # Run all tests test: ensure-image @@ -105,13 +111,18 @@ build-gameservers-sidecar-binary: ensure-image build-gameservers-sidecar-image: ensure-image build-gameservers-sidecar-binary docker build $(agon_path)/gameservers/sidecar/ --tag=$(sidecar_tag) +# Build the cpp sdk linux archive +build-sdk-cpp: ensure-image + docker run --rm $(common_mounts) -w $(mount_path)/sdks/cpp --entrypoint make $(build_tag) build install archive + # push the gameservers sidecar image push-gameservers-sidecar-image: ensure-image docker push $(sidecar_tag) -# Generate the sidecar gRPC code -gen-gameservers-sidecar-grpc: ensure-image +# Generate the SDK gRPC server and client code +gen-gameservers-sdk-grpc: ensure-image docker run --rm $(common_mounts) --entrypoint="/root/gen-grpc-go.sh" $(build_tag) + docker run --rm $(common_mounts) --entrypoint="/root/gen-grpc-cpp.sh" $(build_tag) # Generate the client for our CustomResourceDefinition gen-crd-client: ensure-image @@ -137,14 +148,12 @@ godoc: docker run -p 8888:8888 --rm $(common_mounts) -v $(build_path)/.index:/root/.index \ --entrypoint=godoc $(build_tag) -http=":8888" -index=true -index_files=/root/.index -.PHONY: build-image - # Creates the build docker image -build-image: +build-build-image: docker build --tag=$(build_tag) $(build_path)/build-image # Deletes the local build docker image -clean-image: +clean-build-image: docker rmi $(build_tag) ensure-config: @@ -154,7 +163,7 @@ ensure-config: ensure-image: ensure-config @if [ -z $$(docker images -q $(build_tag)) ]; then\ echo "Could not find $(build_tag) image. Building...";\ - $(MAKE) build-image;\ + $(MAKE) build-build-image;\ fi # Initialise the gcloud login and project configuration, if you are working with GCP diff --git a/build/README.md b/build/README.md index 87aa8c93e1..9ebad0a35e 100644 --- a/build/README.md +++ b/build/README.md @@ -18,14 +18,18 @@ This is not required if you are simply building using the `make` targets Make sure you are in the `build` directory to start. First, let's test all the code. To do this, run `make test`, which will execute all the unit tests for the codebase. + If you haven't run any of the `build` make targets before then this will also create the build image, and then run the tests. +Building the `build-image` may take ~10 minutes to finish (depending on machine). +Feel free to make cup of tea or coffee at this point. ☕️ The build image is only created the first time one of the make targets is executed, and will only rebuild if the build Dockerfile has changed. Assuming that the tests all pass, let's go ahead an compile the code and build the Docker images that Agon consists of. -To compile the code and create the Docker images run `make build`. This will compile the code and create the docker image. +To compile the code, create the Docker images, and compile and archive the sdks, +run `make build`. This will compile the code and create the docker image. You may note that the docker image is tagged with a concatenation of the upcoming release number and short git hash for the current commit. This has also been set in the code itself, so that it can be seen in log statements. @@ -108,8 +112,17 @@ All targets will create the build image if it is not present. Targets for developing with the build image #### `make build` +Build all the images required for Agon, as well as the SDKs + +#### `make build-images` Build all the images required for Agon +#### `make build-sdks` +Build all the sdks required for Agon + +#### `make build-sdk-cpp` +Build the cpp sdk static and dynamic libraries (linux libraries only) + #### `make test` Run all tests @@ -131,8 +144,8 @@ Compile the gameserver sidecar and then build the docker image #### `make gen-crd-client` Generate the Custom Resource Definition client(s) -#### `make gen-gameservers-sidecar-grpc` -Generate the gRPC sidecar Server and Client +#### `make gen-gameservers-sdk-grpc` +Generate the SDK gRPC server and client code ### Build Image Targets @@ -141,10 +154,10 @@ Targets for building the build image ### `make clean-config` Cleans the kubernetes and gcloud configurations -### `make clean-image` +### `make clean-build-image` Deletes the local build docker image -### `make build-image` +### `make build-build-image` Creates the build docker image ## Google Cloud Platform diff --git a/build/build-image/Dockerfile b/build/build-image/Dockerfile index 5e8d64e12d..00a984d7a3 100644 --- a/build/build-image/Dockerfile +++ b/build/build-image/Dockerfile @@ -14,7 +14,7 @@ FROM golang:1.9.2 -RUN apt-get update && apt-get install -y wget unzip bash-completion rsync +RUN apt-get update && apt-get install -y wget unzip bash-completion rsync autoconf automake libtool make g++ WORKDIR / @@ -26,18 +26,18 @@ ENV PATH /google-cloud-sdk/bin:$PATH RUN gcloud components update && gcloud components install kubectl RUN echo "source <(kubectl completion bash)" >> /root/.bashrc -# install protoc for grpc -ENV PB_VER 3.5.0 -ENV PB_URL https://github.com/google/protobuf/releases/download/v${PB_VER}/protoc-${PB_VER}-linux-x86_64.zip -RUN mkdir -p /tmp/protoc && \ - curl -L ${PB_URL} > /tmp/protoc/protoc.zip && \ - cd /tmp/protoc && \ - unzip protoc.zip && \ - cp /tmp/protoc/bin/protoc /usr/local/bin && \ - cp -R /tmp/protoc/include/* /usr/local/include && \ - chmod go+rx /usr/local/bin/protoc && \ - cd /tmp && \ - rm -r /tmp/protoc +# install protobuf first, then grpc +ENV GRPC_RELEASE_TAG v1.8.x +RUN git clone -b ${GRPC_RELEASE_TAG} https://github.com/grpc/grpc /var/local/git/grpc && \ + cd /var/local/git/grpc && \ + git submodule update --init && \ + echo "--- installing protobuf ---" && \ + cd third_party/protobuf && \ + ./autogen.sh && ./configure --enable-shared && \ + make -j$(nproc) && make -j$(nproc) check && make install && make clean && ldconfig && \ + echo "--- installing grpc ---" && \ + cd /var/local/git/grpc && \ + make -j$(nproc) && make install && make clean && ldconfig # install go tooling for building and testing RUN go get -u github.com/golang/dep/cmd/dep && \ diff --git a/build/build-image/gen-grpc-cpp.sh b/build/build-image/gen-grpc-cpp.sh new file mode 100644 index 0000000000..d05ef0fdb2 --- /dev/null +++ b/build/build-image/gen-grpc-cpp.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash + +# Copyright 2017 Google Inc. 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. + +cd /go/src/github.com/agonio/agon +protoc -I . --grpc_out=./sdks/cpp --plugin=protoc-gen-grpc=`which grpc_cpp_plugin` sdk.proto +protoc -I . --cpp_out=./sdks/cpp sdk.proto +mkdir /tmp/cpp +ls ./sdks/cpp | xargs -I@ bash -c "cat ./build/boilerplate.go.txt ./sdks/cpp/@ >> /tmp/cpp/@" +# already has a header, so we'll remove it +rm /tmp/cpp/sdk.grpc.pb.h +mv /tmp/cpp/* ./sdks/cpp/ + diff --git a/examples/cpp-simple/Dockerfile b/examples/cpp-simple/Dockerfile new file mode 100644 index 0000000000..e7ddd70653 --- /dev/null +++ b/examples/cpp-simple/Dockerfile @@ -0,0 +1,23 @@ +# Copyright 2017 Google Inc. 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. + +FROM debian:stretch +RUN useradd -m server + +COPY ./bin/server-static /home/server/server-static +RUN chown -R server /home/server && \ + chmod o+x /home/server/server-static + +USER server +ENTRYPOINT /home/server/server-static \ No newline at end of file diff --git a/examples/cpp-simple/Makefile b/examples/cpp-simple/Makefile new file mode 100644 index 0000000000..f6f726a8e9 --- /dev/null +++ b/examples/cpp-simple/Makefile @@ -0,0 +1,65 @@ +# Copyright 2017 Google Inc. 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. + +# +# Makefile for building the world's simplest C++ game server +# + +# __ __ _ _ _ +# \ \ / /_ _ _ __(_) __ _| |__ | | ___ ___ +# \ \ / / _` | '__| |/ _` | '_ \| |/ _ \ __| +# \ V / (_| | | | | (_| | |_) | | __\__ \ +# \_/ \__,_|_| |_|\__,_|_.__/|_|\___|___/ +# + +CXX = g++ +CPPFLAGS += -I/usr/local/include -pthread +CXXFLAGS += -std=c++11 +LDFLAGS += -L/usr/local/lib -lagonsdk -lgrpc++_unsecure -lgrpc -lprotobuf -lpthread -ldl +REPOSITORY = gcr.io/agon-images + +# Directory that this Makefile is in. +mkfile_path := $(abspath $(lastword $(MAKEFILE_LIST))) +project_path := $(dir $(mkfile_path)) +server_tag = $(REPOSITORY)/cpp-simple-server:0.1 + +# _____ _ +# |_ _|_ _ _ __ __ _ ___| |_ ___ +# | |/ _` | '__/ _` |/ _ \ __/ __| +# | | (_| | | | (_| | __/ |_\__ \ +# |_|\__,_|_| \__, |\___|\__|___/ +# |___/ + +# build the library +build: ensure-bin server-dynamic server-static + +# Build a docker image for the server, and tag it +build-image: + docker build $(project_path) --tag=$(server_tag) + +# make the server executable +server-dynamic: server.o + $(CXX) $^ $(LDFLAGS) -o $(project_path)bin/$@ + +# make the server executable +server-static: server.o + $(CXX) $^ $(LDFLAGS) -o $(project_path)bin/$@ -static + +# make sure the bin directory exists +ensure-bin: + -mkdir $(project_path)/bin + +clean: + -rm -r $(project_path)/bin + -rm *.o diff --git a/examples/cpp-simple/README.md b/examples/cpp-simple/README.md new file mode 100644 index 0000000000..8c3679b2af --- /dev/null +++ b/examples/cpp-simple/README.md @@ -0,0 +1,12 @@ +# Simple C++ Example + +This is a very simple "server" that doesn't do much other than show how the SDK works in C++. + +It will +- Setup the Agon SDK +- Call `SDK::Ready()` to register that it is ready with Agon. +- Every 10 seconds, write a log saying "Hi! I'm a Game Server" +- After 60 seconds, call `SDK::Shutdown()` to shut the server down. + +## Building +Depends on the [`sdks/cpp`](../../sdks/cpp) SDK and its dependencies have been compiled and installed. \ No newline at end of file diff --git a/examples/cpp-simple/gameserver.yaml b/examples/cpp-simple/gameserver.yaml new file mode 100644 index 0000000000..ab3de3ff75 --- /dev/null +++ b/examples/cpp-simple/gameserver.yaml @@ -0,0 +1,28 @@ +# Copyright 2017 Google Inc. 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. + +apiVersion: "stable.agon.io/v1alpha1" +kind: GameServer +metadata: + name: cpp-simple +spec: + portPolicy: "static" + containerPort: 7654 + hostPort: 7778 + template: + spec: + containers: + - name: cpp-simple + image: gcr.io/agon-images/cpp-simple-server:0.1 + imagePullPolicy: Always \ No newline at end of file diff --git a/examples/cpp-simple/server.cc b/examples/cpp-simple/server.cc new file mode 100644 index 0000000000..dba5d161c8 --- /dev/null +++ b/examples/cpp-simple/server.cc @@ -0,0 +1,66 @@ +// Copyright 2017 Google Inc. 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. + +/* + A server that starts, and then stops after 60 seconds. + This example really does nothing other than show how to integrate + the C++ SDK. +*/ + +#include +#include +#include +#include + +int main() { + std::cout << "C++ Game Server has started!" << std::endl; + + std::cout << "Getting the instance of the SDK!" << std::endl; + agon::SDK *sdk = new agon::SDK(); + + std::cout << "Attempting to connect..." << std::endl; + bool connected = sdk->Connect(); + if (!connected) { + std::cout << "Could not connect to the sidecar. Exiting!" << std::endl; + return -1; + } + std::cout << "...handshake complete." << std::endl; + + std::cout << "Marking server as ready..." << std::endl; + grpc::Status status = sdk->Ready(); + if (!status.ok()) { + std::cout << "Could not run Ready(): "+ status.error_message() + ". Exiting!" << std::endl; + return -1; + } + std::cout << "...marked Ready" << std::endl; + + for (int i = 0; i < 10; i++) { + int time = i*10; + std::cout << "Running for " + std::to_string(time) + " seconds !" << std::endl; + + std::this_thread::sleep_for(std::chrono::seconds(10)); + + if (i == 5) { + std::cout << "Shutting down after 60 seconds..." << std::endl; + grpc::Status status = sdk->Shutdown(); + if (!status.ok()) { + std::cout << "Could not run Shutdown():" + status.error_message() + ". Exiting!" << std::endl; + return -1; + } + std::cout << "...marked for Shutdown" << std::endl; + } + } + + return 0; +} \ No newline at end of file diff --git a/examples/xonotic/Dockerfile b/examples/xonotic/Dockerfile index 83678d2497..517c18b768 100644 --- a/examples/xonotic/Dockerfile +++ b/examples/xonotic/Dockerfile @@ -1,3 +1,17 @@ +# Copyright 2017 Google Inc. 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. + FROM debian:stretch RUN apt-get update && apt-get install -y unzip curl diff --git a/sdks/README.md b/sdks/README.md new file mode 100644 index 0000000000..0a73c9ad90 --- /dev/null +++ b/sdks/README.md @@ -0,0 +1,37 @@ +# Agon Game Server Client SDKs + +The SDKs are integration points for game servers with Agon itself. + +They are required to be integrated with your game server to work with Agon. + +There are currently two support SDKs: +- [C++](cpp) +- [Go](go) + +The SDKs are mostly thin wrappers around [gRPC](https://grpc.io), generated clients, +which connects to a small process that Agon coordinates to run alongside the Game Server +in the Pod. This means that more languages can easily be supported in the future +(but pull requests are welcome! 😊 ). + +## Function Reference + +While each of the SDKs are canonical to their languages, they all have the following +functions that implement the core responsibilities of the SDK. + +For language specific documentation, have a look at the respective source, +and the [examples](../examples) + +### Ready() +This tells Agon that the Game Server is ready to take player connections. +One a Game Server has specified that it is `Ready`, then the Kubernetes +GameServer record will be moved to the `Ready` state, and the details +for it's public address and connection port will be populated. + +### Shutdown() +This tells Agon to shut down the currently running game server. +The GameServer state will be set `Shutdown` and the +backing [`Pod`](https://kubernetes.io/docs/concepts/workloads/pods/pod-overview/) +will be deleted, if they have not shut themselves down already. + +## Local Development +_documentation forthcoming_ diff --git a/sdks/cpp/Makefile b/sdks/cpp/Makefile new file mode 100644 index 0000000000..cebbcae23f --- /dev/null +++ b/sdks/cpp/Makefile @@ -0,0 +1,76 @@ +# Copyright 2017 Google Inc. 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. + +# +# Makefile for testing and building the C++ SDK +# + +# __ __ _ _ _ +# \ \ / /_ _ _ __(_) __ _| |__ | | ___ ___ +# \ \ / / _` | '__| |/ _` | '_ \| |/ _ \ __| +# \ V / (_| | | | | (_| | |_) | | __\__ \ +# \_/ \__,_|_| |_|\__,_|_.__/|_|\___|___/ +# + +CXX = g++ +CPPFLAGS += -I/usr/local/include -pthread -fPIC +CXXFLAGS += -std=c++11 +LDFLAGS += -L/usr/local/lib -lgrpc++_unsecure -lgrpc -lprotobuf -lpthread -ldl + +# Directory that this Makefile is in. +mkfile_path := $(abspath $(lastword $(MAKEFILE_LIST))) +build_path := $(dir $(mkfile_path)) + +# _____ _ +# |_ _|_ _ _ __ __ _ ___| |_ ___ +# | |/ _` | '__/ _` |/ _ \ __/ __| +# | | (_| | | | (_| | __/ |_\__ \ +# |_|\__,_|_| \__, |\___|\__|___/ +# |___/ + +# build the library +build: ensure-bin libagonsdk + +# install into /usr/local in the appropriate places +# make sure to install protoc and grpc from source first to build dependencies +install: + cp $(build_path)/bin/libagonsdk.* /usr/local/lib + -mkdir -p /usr/local/include/agon + cp $(build_path)/*.h /usr/local/include/agon/ + ldconfig + +# make the .so build +libagonsdk: sdk.grpc.pb.o sdk.pb.o sdk.o + $(CXX) $^ $(LDFLAGS) -shared -o $(build_path)/bin/$@.so + ar rcs $(build_path)/bin/$@.a $^ + +# make sure the bin directory exists +ensure-bin: + -mkdir $(build_path)/bin + +# build dev and runtime tarballs +archive: + -rm $(build_path)/bin/argonsdk-dev-linux-arch_64.tar.gz + -rm $(build_path)/bin/argonsdk-runtime-linux-arch_64.tar.gz + cp /usr/local/lib/libgrpc.so.5 $(build_path)/bin/ + cp /usr/local/lib/libprotobuf.so.15 $(build_path)/bin/ + cp /usr/local/lib/libagonsdk.so $(build_path)/bin/ + cp /usr/local/lib/libgpr.so.5 $(build_path)/bin/ + cp /usr/local/lib/libgrpc_unsecure.so.5 $(build_path)/bin/ + cd $(build_path)/bin && tar cvf argonsdk-runtime-linux-arch_64.tar.gz * + cd /usr/local && tar cvf $(build_path)/bin/argonsdk-dev-linux-arch_64.tar.gz lib include + +clean: + -rm -r $(build_path)/bin + -rm *.o diff --git a/sdks/cpp/README.md b/sdks/cpp/README.md new file mode 100644 index 0000000000..26871e7420 --- /dev/null +++ b/sdks/cpp/README.md @@ -0,0 +1,27 @@ +# C++ Game Server Client SDK + +## Usage +Read the [SDK Overview](../), check out [sdk.h](sdk.h) and also look at the +[C++ example](../../examples/cpp-simple). + +## Dynamic and Static Libraries +_Note:_ There has yet to be a release of Agon, so if you want static and dynamic libraries, +you will need to [build from source](build/README.md). + +The `make` target `build-sdk-cpp` will compile both static and dynamic libraries for Debian/Linux +for your usage, and build two archives that can be untar'd in /usr/local (or wherever you like +to keep you .h and .so/.a files) in a `bin` directory inside this one. + +- `argonsdk-dev-linux-arch_64.tar.gz`: This includes all the +headers and dynamic and static libraries that are needed for development and runtime. +- `argonsdk-runtime-linux-arch_64.tar.gz`: This includes just the dynamic libraries that +are needed to run a binary compiled against the SDK and its dependencies. + +## Building From Source +If you wish to compile from source, you will need to also need the following dependencies: + +- [gRPC](https://grpc.io), v1.8.x - [C++ compilation guide](https://github.com/grpc/grpc/blob/v1.8.x/INSTALL.md) +- [protobuf](https://developers.google.com/protocol-buffers/), v3.5.0 - [C++ compilation guide](https://github.com/google/protobuf/blob/master/src/README.md) + +For convenience, it's worth noting that protobuf is include in gRPC's `third_party` +directory, and can be compiled from there, rather than pulling down separately. \ No newline at end of file diff --git a/sdks/cpp/sdk.cc b/sdks/cpp/sdk.cc new file mode 100644 index 0000000000..8348fdb28d --- /dev/null +++ b/sdks/cpp/sdk.cc @@ -0,0 +1,52 @@ +// Copyright 2017 Google Inc. 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. + +#include "sdk.h" +#include "sdk.pb.h" + +namespace agon { + + const int port = 59357; + + SDK::SDK() { + channel = grpc::CreateChannel("localhost:" + std::to_string(port), grpc::InsecureChannelCredentials()); + } + + bool SDK::Connect() { + if (!channel->WaitForConnected(gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), gpr_time_from_seconds(30, GPR_TIMESPAN)))) { + return false; + } + + stub = stable::agon::io::sdk::SDK::NewStub(channel); + return true; + } + + grpc::Status SDK::Ready() { + grpc::ClientContext *context = new grpc::ClientContext(); + context->set_deadline(gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), gpr_time_from_seconds(30, GPR_TIMESPAN))); + stable::agon::io::sdk::Empty request; + stable::agon::io::sdk::Empty response; + + return stub->Ready(context, request, &response); + } + + grpc::Status SDK::Shutdown() { + grpc::ClientContext *context = new grpc::ClientContext(); + context->set_deadline(gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), gpr_time_from_seconds(30, GPR_TIMESPAN))); + stable::agon::io::sdk::Empty request; + stable::agon::io::sdk::Empty response; + + return stub->Shutdown(context, request, &response); + } +} \ No newline at end of file diff --git a/sdks/cpp/sdk.grpc.pb.cc b/sdks/cpp/sdk.grpc.pb.cc new file mode 100644 index 0000000000..b12aae458c --- /dev/null +++ b/sdks/cpp/sdk.grpc.pb.cc @@ -0,0 +1,110 @@ +// Copyright 2017 Google Inc. 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. + +// This code was autogenerated. Do not edit directly. +// Generated by the gRPC C++ plugin. +// If you make any local change, they will be lost. +// source: sdk.proto + +#include "sdk.pb.h" +#include "sdk.grpc.pb.h" + +#include +#include +#include +#include +#include +#include +#include +#include +namespace stable { +namespace agon { +namespace io { +namespace sdk { + +static const char* SDK_method_names[] = { + "/stable.agon.io.sdk.SDK/Ready", + "/stable.agon.io.sdk.SDK/Shutdown", +}; + +std::unique_ptr< SDK::Stub> SDK::NewStub(const std::shared_ptr< ::grpc::ChannelInterface>& channel, const ::grpc::StubOptions& options) { + std::unique_ptr< SDK::Stub> stub(new SDK::Stub(channel)); + return stub; +} + +SDK::Stub::Stub(const std::shared_ptr< ::grpc::ChannelInterface>& channel) + : channel_(channel), rpcmethod_Ready_(SDK_method_names[0], ::grpc::internal::RpcMethod::NORMAL_RPC, channel) + , rpcmethod_Shutdown_(SDK_method_names[1], ::grpc::internal::RpcMethod::NORMAL_RPC, channel) + {} + +::grpc::Status SDK::Stub::Ready(::grpc::ClientContext* context, const ::stable::agon::io::sdk::Empty& request, ::stable::agon::io::sdk::Empty* response) { + return ::grpc::internal::BlockingUnaryCall(channel_.get(), rpcmethod_Ready_, context, request, response); +} + +::grpc::ClientAsyncResponseReader< ::stable::agon::io::sdk::Empty>* SDK::Stub::AsyncReadyRaw(::grpc::ClientContext* context, const ::stable::agon::io::sdk::Empty& request, ::grpc::CompletionQueue* cq) { + return ::grpc::internal::ClientAsyncResponseReaderFactory< ::stable::agon::io::sdk::Empty>::Create(channel_.get(), cq, rpcmethod_Ready_, context, request, true); +} + +::grpc::ClientAsyncResponseReader< ::stable::agon::io::sdk::Empty>* SDK::Stub::PrepareAsyncReadyRaw(::grpc::ClientContext* context, const ::stable::agon::io::sdk::Empty& request, ::grpc::CompletionQueue* cq) { + return ::grpc::internal::ClientAsyncResponseReaderFactory< ::stable::agon::io::sdk::Empty>::Create(channel_.get(), cq, rpcmethod_Ready_, context, request, false); +} + +::grpc::Status SDK::Stub::Shutdown(::grpc::ClientContext* context, const ::stable::agon::io::sdk::Empty& request, ::stable::agon::io::sdk::Empty* response) { + return ::grpc::internal::BlockingUnaryCall(channel_.get(), rpcmethod_Shutdown_, context, request, response); +} + +::grpc::ClientAsyncResponseReader< ::stable::agon::io::sdk::Empty>* SDK::Stub::AsyncShutdownRaw(::grpc::ClientContext* context, const ::stable::agon::io::sdk::Empty& request, ::grpc::CompletionQueue* cq) { + return ::grpc::internal::ClientAsyncResponseReaderFactory< ::stable::agon::io::sdk::Empty>::Create(channel_.get(), cq, rpcmethod_Shutdown_, context, request, true); +} + +::grpc::ClientAsyncResponseReader< ::stable::agon::io::sdk::Empty>* SDK::Stub::PrepareAsyncShutdownRaw(::grpc::ClientContext* context, const ::stable::agon::io::sdk::Empty& request, ::grpc::CompletionQueue* cq) { + return ::grpc::internal::ClientAsyncResponseReaderFactory< ::stable::agon::io::sdk::Empty>::Create(channel_.get(), cq, rpcmethod_Shutdown_, context, request, false); +} + +SDK::Service::Service() { + AddMethod(new ::grpc::internal::RpcServiceMethod( + SDK_method_names[0], + ::grpc::internal::RpcMethod::NORMAL_RPC, + new ::grpc::internal::RpcMethodHandler< SDK::Service, ::stable::agon::io::sdk::Empty, ::stable::agon::io::sdk::Empty>( + std::mem_fn(&SDK::Service::Ready), this))); + AddMethod(new ::grpc::internal::RpcServiceMethod( + SDK_method_names[1], + ::grpc::internal::RpcMethod::NORMAL_RPC, + new ::grpc::internal::RpcMethodHandler< SDK::Service, ::stable::agon::io::sdk::Empty, ::stable::agon::io::sdk::Empty>( + std::mem_fn(&SDK::Service::Shutdown), this))); +} + +SDK::Service::~Service() { +} + +::grpc::Status SDK::Service::Ready(::grpc::ServerContext* context, const ::stable::agon::io::sdk::Empty* request, ::stable::agon::io::sdk::Empty* response) { + (void) context; + (void) request; + (void) response; + return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); +} + +::grpc::Status SDK::Service::Shutdown(::grpc::ServerContext* context, const ::stable::agon::io::sdk::Empty* request, ::stable::agon::io::sdk::Empty* response) { + (void) context; + (void) request; + (void) response; + return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); +} + + +} // namespace stable +} // namespace agon +} // namespace io +} // namespace sdk + diff --git a/sdks/cpp/sdk.grpc.pb.h b/sdks/cpp/sdk.grpc.pb.h new file mode 100644 index 0000000000..44658b0ca0 --- /dev/null +++ b/sdks/cpp/sdk.grpc.pb.h @@ -0,0 +1,241 @@ +// Generated by the gRPC C++ plugin. +// If you make any local change, they will be lost. +// source: sdk.proto +// Original file comments: +// Copyright 2017 Google Inc. 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. +// +#ifndef GRPC_sdk_2eproto__INCLUDED +#define GRPC_sdk_2eproto__INCLUDED + +#include "sdk.pb.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace grpc { +class CompletionQueue; +class Channel; +class ServerCompletionQueue; +class ServerContext; +} // namespace grpc + +namespace stable { +namespace agon { +namespace io { +namespace sdk { + +// SDK service to be used in the GameServer SDK to the Pod Sidecar +class SDK final { + public: + static constexpr char const* service_full_name() { + return "stable.agon.io.sdk.SDK"; + } + class StubInterface { + public: + virtual ~StubInterface() {} + // Call when the GameServer is ready + virtual ::grpc::Status Ready(::grpc::ClientContext* context, const ::stable::agon::io::sdk::Empty& request, ::stable::agon::io::sdk::Empty* response) = 0; + std::unique_ptr< ::grpc::ClientAsyncResponseReaderInterface< ::stable::agon::io::sdk::Empty>> AsyncReady(::grpc::ClientContext* context, const ::stable::agon::io::sdk::Empty& request, ::grpc::CompletionQueue* cq) { + return std::unique_ptr< ::grpc::ClientAsyncResponseReaderInterface< ::stable::agon::io::sdk::Empty>>(AsyncReadyRaw(context, request, cq)); + } + std::unique_ptr< ::grpc::ClientAsyncResponseReaderInterface< ::stable::agon::io::sdk::Empty>> PrepareAsyncReady(::grpc::ClientContext* context, const ::stable::agon::io::sdk::Empty& request, ::grpc::CompletionQueue* cq) { + return std::unique_ptr< ::grpc::ClientAsyncResponseReaderInterface< ::stable::agon::io::sdk::Empty>>(PrepareAsyncReadyRaw(context, request, cq)); + } + // Call when the GmaeServer is shutting down + virtual ::grpc::Status Shutdown(::grpc::ClientContext* context, const ::stable::agon::io::sdk::Empty& request, ::stable::agon::io::sdk::Empty* response) = 0; + std::unique_ptr< ::grpc::ClientAsyncResponseReaderInterface< ::stable::agon::io::sdk::Empty>> AsyncShutdown(::grpc::ClientContext* context, const ::stable::agon::io::sdk::Empty& request, ::grpc::CompletionQueue* cq) { + return std::unique_ptr< ::grpc::ClientAsyncResponseReaderInterface< ::stable::agon::io::sdk::Empty>>(AsyncShutdownRaw(context, request, cq)); + } + std::unique_ptr< ::grpc::ClientAsyncResponseReaderInterface< ::stable::agon::io::sdk::Empty>> PrepareAsyncShutdown(::grpc::ClientContext* context, const ::stable::agon::io::sdk::Empty& request, ::grpc::CompletionQueue* cq) { + return std::unique_ptr< ::grpc::ClientAsyncResponseReaderInterface< ::stable::agon::io::sdk::Empty>>(PrepareAsyncShutdownRaw(context, request, cq)); + } + private: + virtual ::grpc::ClientAsyncResponseReaderInterface< ::stable::agon::io::sdk::Empty>* AsyncReadyRaw(::grpc::ClientContext* context, const ::stable::agon::io::sdk::Empty& request, ::grpc::CompletionQueue* cq) = 0; + virtual ::grpc::ClientAsyncResponseReaderInterface< ::stable::agon::io::sdk::Empty>* PrepareAsyncReadyRaw(::grpc::ClientContext* context, const ::stable::agon::io::sdk::Empty& request, ::grpc::CompletionQueue* cq) = 0; + virtual ::grpc::ClientAsyncResponseReaderInterface< ::stable::agon::io::sdk::Empty>* AsyncShutdownRaw(::grpc::ClientContext* context, const ::stable::agon::io::sdk::Empty& request, ::grpc::CompletionQueue* cq) = 0; + virtual ::grpc::ClientAsyncResponseReaderInterface< ::stable::agon::io::sdk::Empty>* PrepareAsyncShutdownRaw(::grpc::ClientContext* context, const ::stable::agon::io::sdk::Empty& request, ::grpc::CompletionQueue* cq) = 0; + }; + class Stub final : public StubInterface { + public: + Stub(const std::shared_ptr< ::grpc::ChannelInterface>& channel); + ::grpc::Status Ready(::grpc::ClientContext* context, const ::stable::agon::io::sdk::Empty& request, ::stable::agon::io::sdk::Empty* response) override; + std::unique_ptr< ::grpc::ClientAsyncResponseReader< ::stable::agon::io::sdk::Empty>> AsyncReady(::grpc::ClientContext* context, const ::stable::agon::io::sdk::Empty& request, ::grpc::CompletionQueue* cq) { + return std::unique_ptr< ::grpc::ClientAsyncResponseReader< ::stable::agon::io::sdk::Empty>>(AsyncReadyRaw(context, request, cq)); + } + std::unique_ptr< ::grpc::ClientAsyncResponseReader< ::stable::agon::io::sdk::Empty>> PrepareAsyncReady(::grpc::ClientContext* context, const ::stable::agon::io::sdk::Empty& request, ::grpc::CompletionQueue* cq) { + return std::unique_ptr< ::grpc::ClientAsyncResponseReader< ::stable::agon::io::sdk::Empty>>(PrepareAsyncReadyRaw(context, request, cq)); + } + ::grpc::Status Shutdown(::grpc::ClientContext* context, const ::stable::agon::io::sdk::Empty& request, ::stable::agon::io::sdk::Empty* response) override; + std::unique_ptr< ::grpc::ClientAsyncResponseReader< ::stable::agon::io::sdk::Empty>> AsyncShutdown(::grpc::ClientContext* context, const ::stable::agon::io::sdk::Empty& request, ::grpc::CompletionQueue* cq) { + return std::unique_ptr< ::grpc::ClientAsyncResponseReader< ::stable::agon::io::sdk::Empty>>(AsyncShutdownRaw(context, request, cq)); + } + std::unique_ptr< ::grpc::ClientAsyncResponseReader< ::stable::agon::io::sdk::Empty>> PrepareAsyncShutdown(::grpc::ClientContext* context, const ::stable::agon::io::sdk::Empty& request, ::grpc::CompletionQueue* cq) { + return std::unique_ptr< ::grpc::ClientAsyncResponseReader< ::stable::agon::io::sdk::Empty>>(PrepareAsyncShutdownRaw(context, request, cq)); + } + + private: + std::shared_ptr< ::grpc::ChannelInterface> channel_; + ::grpc::ClientAsyncResponseReader< ::stable::agon::io::sdk::Empty>* AsyncReadyRaw(::grpc::ClientContext* context, const ::stable::agon::io::sdk::Empty& request, ::grpc::CompletionQueue* cq) override; + ::grpc::ClientAsyncResponseReader< ::stable::agon::io::sdk::Empty>* PrepareAsyncReadyRaw(::grpc::ClientContext* context, const ::stable::agon::io::sdk::Empty& request, ::grpc::CompletionQueue* cq) override; + ::grpc::ClientAsyncResponseReader< ::stable::agon::io::sdk::Empty>* AsyncShutdownRaw(::grpc::ClientContext* context, const ::stable::agon::io::sdk::Empty& request, ::grpc::CompletionQueue* cq) override; + ::grpc::ClientAsyncResponseReader< ::stable::agon::io::sdk::Empty>* PrepareAsyncShutdownRaw(::grpc::ClientContext* context, const ::stable::agon::io::sdk::Empty& request, ::grpc::CompletionQueue* cq) override; + const ::grpc::internal::RpcMethod rpcmethod_Ready_; + const ::grpc::internal::RpcMethod rpcmethod_Shutdown_; + }; + static std::unique_ptr NewStub(const std::shared_ptr< ::grpc::ChannelInterface>& channel, const ::grpc::StubOptions& options = ::grpc::StubOptions()); + + class Service : public ::grpc::Service { + public: + Service(); + virtual ~Service(); + // Call when the GameServer is ready + virtual ::grpc::Status Ready(::grpc::ServerContext* context, const ::stable::agon::io::sdk::Empty* request, ::stable::agon::io::sdk::Empty* response); + // Call when the GmaeServer is shutting down + virtual ::grpc::Status Shutdown(::grpc::ServerContext* context, const ::stable::agon::io::sdk::Empty* request, ::stable::agon::io::sdk::Empty* response); + }; + template + class WithAsyncMethod_Ready : public BaseClass { + private: + void BaseClassMustBeDerivedFromService(const Service *service) {} + public: + WithAsyncMethod_Ready() { + ::grpc::Service::MarkMethodAsync(0); + } + ~WithAsyncMethod_Ready() override { + BaseClassMustBeDerivedFromService(this); + } + // disable synchronous version of this method + ::grpc::Status Ready(::grpc::ServerContext* context, const ::stable::agon::io::sdk::Empty* request, ::stable::agon::io::sdk::Empty* response) final override { + abort(); + return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); + } + void RequestReady(::grpc::ServerContext* context, ::stable::agon::io::sdk::Empty* request, ::grpc::ServerAsyncResponseWriter< ::stable::agon::io::sdk::Empty>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { + ::grpc::Service::RequestAsyncUnary(0, context, request, response, new_call_cq, notification_cq, tag); + } + }; + template + class WithAsyncMethod_Shutdown : public BaseClass { + private: + void BaseClassMustBeDerivedFromService(const Service *service) {} + public: + WithAsyncMethod_Shutdown() { + ::grpc::Service::MarkMethodAsync(1); + } + ~WithAsyncMethod_Shutdown() override { + BaseClassMustBeDerivedFromService(this); + } + // disable synchronous version of this method + ::grpc::Status Shutdown(::grpc::ServerContext* context, const ::stable::agon::io::sdk::Empty* request, ::stable::agon::io::sdk::Empty* response) final override { + abort(); + return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); + } + void RequestShutdown(::grpc::ServerContext* context, ::stable::agon::io::sdk::Empty* request, ::grpc::ServerAsyncResponseWriter< ::stable::agon::io::sdk::Empty>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { + ::grpc::Service::RequestAsyncUnary(1, context, request, response, new_call_cq, notification_cq, tag); + } + }; + typedef WithAsyncMethod_Ready > AsyncService; + template + class WithGenericMethod_Ready : public BaseClass { + private: + void BaseClassMustBeDerivedFromService(const Service *service) {} + public: + WithGenericMethod_Ready() { + ::grpc::Service::MarkMethodGeneric(0); + } + ~WithGenericMethod_Ready() override { + BaseClassMustBeDerivedFromService(this); + } + // disable synchronous version of this method + ::grpc::Status Ready(::grpc::ServerContext* context, const ::stable::agon::io::sdk::Empty* request, ::stable::agon::io::sdk::Empty* response) final override { + abort(); + return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); + } + }; + template + class WithGenericMethod_Shutdown : public BaseClass { + private: + void BaseClassMustBeDerivedFromService(const Service *service) {} + public: + WithGenericMethod_Shutdown() { + ::grpc::Service::MarkMethodGeneric(1); + } + ~WithGenericMethod_Shutdown() override { + BaseClassMustBeDerivedFromService(this); + } + // disable synchronous version of this method + ::grpc::Status Shutdown(::grpc::ServerContext* context, const ::stable::agon::io::sdk::Empty* request, ::stable::agon::io::sdk::Empty* response) final override { + abort(); + return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); + } + }; + template + class WithStreamedUnaryMethod_Ready : public BaseClass { + private: + void BaseClassMustBeDerivedFromService(const Service *service) {} + public: + WithStreamedUnaryMethod_Ready() { + ::grpc::Service::MarkMethodStreamed(0, + new ::grpc::internal::StreamedUnaryHandler< ::stable::agon::io::sdk::Empty, ::stable::agon::io::sdk::Empty>(std::bind(&WithStreamedUnaryMethod_Ready::StreamedReady, this, std::placeholders::_1, std::placeholders::_2))); + } + ~WithStreamedUnaryMethod_Ready() override { + BaseClassMustBeDerivedFromService(this); + } + // disable regular version of this method + ::grpc::Status Ready(::grpc::ServerContext* context, const ::stable::agon::io::sdk::Empty* request, ::stable::agon::io::sdk::Empty* response) final override { + abort(); + return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); + } + // replace default version of method with streamed unary + virtual ::grpc::Status StreamedReady(::grpc::ServerContext* context, ::grpc::ServerUnaryStreamer< ::stable::agon::io::sdk::Empty,::stable::agon::io::sdk::Empty>* server_unary_streamer) = 0; + }; + template + class WithStreamedUnaryMethod_Shutdown : public BaseClass { + private: + void BaseClassMustBeDerivedFromService(const Service *service) {} + public: + WithStreamedUnaryMethod_Shutdown() { + ::grpc::Service::MarkMethodStreamed(1, + new ::grpc::internal::StreamedUnaryHandler< ::stable::agon::io::sdk::Empty, ::stable::agon::io::sdk::Empty>(std::bind(&WithStreamedUnaryMethod_Shutdown::StreamedShutdown, this, std::placeholders::_1, std::placeholders::_2))); + } + ~WithStreamedUnaryMethod_Shutdown() override { + BaseClassMustBeDerivedFromService(this); + } + // disable regular version of this method + ::grpc::Status Shutdown(::grpc::ServerContext* context, const ::stable::agon::io::sdk::Empty* request, ::stable::agon::io::sdk::Empty* response) final override { + abort(); + return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); + } + // replace default version of method with streamed unary + virtual ::grpc::Status StreamedShutdown(::grpc::ServerContext* context, ::grpc::ServerUnaryStreamer< ::stable::agon::io::sdk::Empty,::stable::agon::io::sdk::Empty>* server_unary_streamer) = 0; + }; + typedef WithStreamedUnaryMethod_Ready > StreamedUnaryService; + typedef Service SplitStreamedService; + typedef WithStreamedUnaryMethod_Ready > StreamedService; +}; + +} // namespace sdk +} // namespace io +} // namespace agon +} // namespace stable + + +#endif // GRPC_sdk_2eproto__INCLUDED diff --git a/sdks/cpp/sdk.h b/sdks/cpp/sdk.h new file mode 100644 index 0000000000..f142b40d85 --- /dev/null +++ b/sdks/cpp/sdk.h @@ -0,0 +1,45 @@ +// Copyright 2017 Google Inc. 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. + +#include +#include "sdk.grpc.pb.h" + +namespace agon { + + // The Agon SDK + class SDK { + public: + // Creates a new instance of the SDK. + // Does not connect to anything. + SDK(); + + // Must be called before any other functions on the SDK. + // This will attempt to do a handshake with the sdk server, timing out + // after 30 seconds. + // Returns true if the connection was successful, false if not. + bool Connect(); + + // Marks the Game Server as ready to receive connections + grpc::Status Ready(); + + // Marks the Game Server as ready to shutdown + grpc::Status Shutdown(); + + ~SDK(); + + private: + std::shared_ptr channel; + std::unique_ptr stub; + }; +} diff --git a/sdks/cpp/sdk.pb.cc b/sdks/cpp/sdk.pb.cc new file mode 100644 index 0000000000..d9d730d850 --- /dev/null +++ b/sdks/cpp/sdk.pb.cc @@ -0,0 +1,339 @@ +// Copyright 2017 Google Inc. 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. + +// This code was autogenerated. Do not edit directly. +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: sdk.proto + +#include "sdk.pb.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +// This is a temporary google only hack +#ifdef GOOGLE_PROTOBUF_ENFORCE_UNIQUENESS +#include "third_party/protobuf/version.h" +#endif +// @@protoc_insertion_point(includes) +namespace stable { +namespace agon { +namespace io { +namespace sdk { +class EmptyDefaultTypeInternal { + public: + ::google::protobuf::internal::ExplicitlyConstructed + _instance; +} _Empty_default_instance_; +} // namespace sdk +} // namespace io +} // namespace agon +} // namespace stable +namespace protobuf_sdk_2eproto { +void InitDefaultsEmptyImpl() { + GOOGLE_PROTOBUF_VERIFY_VERSION; + +#ifdef GOOGLE_PROTOBUF_ENFORCE_UNIQUENESS + ::google::protobuf::internal::InitProtobufDefaultsForceUnique(); +#else + ::google::protobuf::internal::InitProtobufDefaults(); +#endif // GOOGLE_PROTOBUF_ENFORCE_UNIQUENESS + { + void* ptr = &::stable::agon::io::sdk::_Empty_default_instance_; + new (ptr) ::stable::agon::io::sdk::Empty(); + ::google::protobuf::internal::OnShutdownDestroyMessage(ptr); + } + ::stable::agon::io::sdk::Empty::InitAsDefaultInstance(); +} + +void InitDefaultsEmpty() { + static GOOGLE_PROTOBUF_DECLARE_ONCE(once); + ::google::protobuf::GoogleOnceInit(&once, &InitDefaultsEmptyImpl); +} + +::google::protobuf::Metadata file_level_metadata[1]; + +const ::google::protobuf::uint32 TableStruct::offsets[] GOOGLE_PROTOBUF_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = { + ~0u, // no _has_bits_ + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(::stable::agon::io::sdk::Empty, _internal_metadata_), + ~0u, // no _extensions_ + ~0u, // no _oneof_case_ + ~0u, // no _weak_field_map_ +}; +static const ::google::protobuf::internal::MigrationSchema schemas[] GOOGLE_PROTOBUF_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = { + { 0, -1, sizeof(::stable::agon::io::sdk::Empty)}, +}; + +static ::google::protobuf::Message const * const file_default_instances[] = { + reinterpret_cast(&::stable::agon::io::sdk::_Empty_default_instance_), +}; + +void protobuf_AssignDescriptors() { + AddDescriptors(); + ::google::protobuf::MessageFactory* factory = NULL; + AssignDescriptors( + "sdk.proto", schemas, file_default_instances, TableStruct::offsets, factory, + file_level_metadata, NULL, NULL); +} + +void protobuf_AssignDescriptorsOnce() { + static GOOGLE_PROTOBUF_DECLARE_ONCE(once); + ::google::protobuf::GoogleOnceInit(&once, &protobuf_AssignDescriptors); +} + +void protobuf_RegisterTypes(const ::std::string&) GOOGLE_PROTOBUF_ATTRIBUTE_COLD; +void protobuf_RegisterTypes(const ::std::string&) { + protobuf_AssignDescriptorsOnce(); + ::google::protobuf::internal::RegisterAllTypes(file_level_metadata, 1); +} + +void AddDescriptorsImpl() { + InitDefaults(); + static const char descriptor[] GOOGLE_PROTOBUF_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = { + "\n\tsdk.proto\022\022stable.agon.io.sdk\"\007\n\005Empty" + "2\212\001\n\003SDK\022\?\n\005Ready\022\031.stable.agon.io.sdk.E" + "mpty\032\031.stable.agon.io.sdk.Empty\"\000\022B\n\010Shu" + "tdown\022\031.stable.agon.io.sdk.Empty\032\031.stabl" + "e.agon.io.sdk.Empty\"\000B\005Z\003sdkb\006proto3" + }; + ::google::protobuf::DescriptorPool::InternalAddGeneratedFile( + descriptor, 196); + ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile( + "sdk.proto", &protobuf_RegisterTypes); +} + +void AddDescriptors() { + static GOOGLE_PROTOBUF_DECLARE_ONCE(once); + ::google::protobuf::GoogleOnceInit(&once, &AddDescriptorsImpl); +} +// Force AddDescriptors() to be called at dynamic initialization time. +struct StaticDescriptorInitializer { + StaticDescriptorInitializer() { + AddDescriptors(); + } +} static_descriptor_initializer; +} // namespace protobuf_sdk_2eproto +namespace stable { +namespace agon { +namespace io { +namespace sdk { + +// =================================================================== + +void Empty::InitAsDefaultInstance() { +} +#if !defined(_MSC_VER) || _MSC_VER >= 1900 +#endif // !defined(_MSC_VER) || _MSC_VER >= 1900 + +Empty::Empty() + : ::google::protobuf::Message(), _internal_metadata_(NULL) { + if (GOOGLE_PREDICT_TRUE(this != internal_default_instance())) { + ::protobuf_sdk_2eproto::InitDefaultsEmpty(); + } + SharedCtor(); + // @@protoc_insertion_point(constructor:stable.agon.io.sdk.Empty) +} +Empty::Empty(const Empty& from) + : ::google::protobuf::Message(), + _internal_metadata_(NULL), + _cached_size_(0) { + _internal_metadata_.MergeFrom(from._internal_metadata_); + // @@protoc_insertion_point(copy_constructor:stable.agon.io.sdk.Empty) +} + +void Empty::SharedCtor() { + _cached_size_ = 0; +} + +Empty::~Empty() { + // @@protoc_insertion_point(destructor:stable.agon.io.sdk.Empty) + SharedDtor(); +} + +void Empty::SharedDtor() { +} + +void Empty::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} +const ::google::protobuf::Descriptor* Empty::descriptor() { + ::protobuf_sdk_2eproto::protobuf_AssignDescriptorsOnce(); + return ::protobuf_sdk_2eproto::file_level_metadata[kIndexInFileMessages].descriptor; +} + +const Empty& Empty::default_instance() { + ::protobuf_sdk_2eproto::InitDefaultsEmpty(); + return *internal_default_instance(); +} + +Empty* Empty::New(::google::protobuf::Arena* arena) const { + Empty* n = new Empty; + if (arena != NULL) { + arena->Own(n); + } + return n; +} + +void Empty::Clear() { +// @@protoc_insertion_point(message_clear_start:stable.agon.io.sdk.Empty) + ::google::protobuf::uint32 cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + _internal_metadata_.Clear(); +} + +bool Empty::MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input) { +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure + ::google::protobuf::uint32 tag; + // @@protoc_insertion_point(parse_start:stable.agon.io.sdk.Empty) + for (;;) { + ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoffNoLastTag(127u); + tag = p.first; + if (!p.second) goto handle_unusual; + handle_unusual: + if (tag == 0) { + goto success; + } + DO_(::google::protobuf::internal::WireFormat::SkipField( + input, tag, _internal_metadata_.mutable_unknown_fields())); + } +success: + // @@protoc_insertion_point(parse_success:stable.agon.io.sdk.Empty) + return true; +failure: + // @@protoc_insertion_point(parse_failure:stable.agon.io.sdk.Empty) + return false; +#undef DO_ +} + +void Empty::SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const { + // @@protoc_insertion_point(serialize_start:stable.agon.io.sdk.Empty) + ::google::protobuf::uint32 cached_has_bits = 0; + (void) cached_has_bits; + + if ((_internal_metadata_.have_unknown_fields() && ::google::protobuf::internal::GetProto3PreserveUnknownsDefault())) { + ::google::protobuf::internal::WireFormat::SerializeUnknownFields( + (::google::protobuf::internal::GetProto3PreserveUnknownsDefault() ? _internal_metadata_.unknown_fields() : _internal_metadata_.default_instance()), output); + } + // @@protoc_insertion_point(serialize_end:stable.agon.io.sdk.Empty) +} + +::google::protobuf::uint8* Empty::InternalSerializeWithCachedSizesToArray( + bool deterministic, ::google::protobuf::uint8* target) const { + (void)deterministic; // Unused + // @@protoc_insertion_point(serialize_to_array_start:stable.agon.io.sdk.Empty) + ::google::protobuf::uint32 cached_has_bits = 0; + (void) cached_has_bits; + + if ((_internal_metadata_.have_unknown_fields() && ::google::protobuf::internal::GetProto3PreserveUnknownsDefault())) { + target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( + (::google::protobuf::internal::GetProto3PreserveUnknownsDefault() ? _internal_metadata_.unknown_fields() : _internal_metadata_.default_instance()), target); + } + // @@protoc_insertion_point(serialize_to_array_end:stable.agon.io.sdk.Empty) + return target; +} + +size_t Empty::ByteSizeLong() const { +// @@protoc_insertion_point(message_byte_size_start:stable.agon.io.sdk.Empty) + size_t total_size = 0; + + if ((_internal_metadata_.have_unknown_fields() && ::google::protobuf::internal::GetProto3PreserveUnknownsDefault())) { + total_size += + ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( + (::google::protobuf::internal::GetProto3PreserveUnknownsDefault() ? _internal_metadata_.unknown_fields() : _internal_metadata_.default_instance())); + } + int cached_size = ::google::protobuf::internal::ToCachedSize(total_size); + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = cached_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); + return total_size; +} + +void Empty::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:stable.agon.io.sdk.Empty) + GOOGLE_DCHECK_NE(&from, this); + const Empty* source = + ::google::protobuf::internal::DynamicCastToGenerated( + &from); + if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:stable.agon.io.sdk.Empty) + ::google::protobuf::internal::ReflectionOps::Merge(from, this); + } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:stable.agon.io.sdk.Empty) + MergeFrom(*source); + } +} + +void Empty::MergeFrom(const Empty& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:stable.agon.io.sdk.Empty) + GOOGLE_DCHECK_NE(&from, this); + _internal_metadata_.MergeFrom(from._internal_metadata_); + ::google::protobuf::uint32 cached_has_bits = 0; + (void) cached_has_bits; + +} + +void Empty::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:stable.agon.io.sdk.Empty) + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +void Empty::CopyFrom(const Empty& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:stable.agon.io.sdk.Empty) + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +bool Empty::IsInitialized() const { + return true; +} + +void Empty::Swap(Empty* other) { + if (other == this) return; + InternalSwap(other); +} +void Empty::InternalSwap(Empty* other) { + using std::swap; + _internal_metadata_.Swap(&other->_internal_metadata_); + swap(_cached_size_, other->_cached_size_); +} + +::google::protobuf::Metadata Empty::GetMetadata() const { + protobuf_sdk_2eproto::protobuf_AssignDescriptorsOnce(); + return ::protobuf_sdk_2eproto::file_level_metadata[kIndexInFileMessages]; +} + + +// @@protoc_insertion_point(namespace_scope) +} // namespace sdk +} // namespace io +} // namespace agon +} // namespace stable + +// @@protoc_insertion_point(global_scope) diff --git a/sdks/cpp/sdk.pb.h b/sdks/cpp/sdk.pb.h new file mode 100644 index 0000000000..39e3710c41 --- /dev/null +++ b/sdks/cpp/sdk.pb.h @@ -0,0 +1,198 @@ +// Copyright 2017 Google Inc. 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. + +// This code was autogenerated. Do not edit directly. +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: sdk.proto + +#ifndef PROTOBUF_sdk_2eproto__INCLUDED +#define PROTOBUF_sdk_2eproto__INCLUDED + +#include + +#include + +#if GOOGLE_PROTOBUF_VERSION < 3005000 +#error This file was generated by a newer version of protoc which is +#error incompatible with your Protocol Buffer headers. Please update +#error your headers. +#endif +#if 3005000 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION +#error This file was generated by an older version of protoc which is +#error incompatible with your Protocol Buffer headers. Please +#error regenerate this file with a newer version of protoc. +#endif + +#include +#include +#include +#include +#include +#include +#include +#include // IWYU pragma: export +#include // IWYU pragma: export +#include +// @@protoc_insertion_point(includes) + +namespace protobuf_sdk_2eproto { +// Internal implementation detail -- do not use these members. +struct TableStruct { + static const ::google::protobuf::internal::ParseTableField entries[]; + static const ::google::protobuf::internal::AuxillaryParseTableField aux[]; + static const ::google::protobuf::internal::ParseTable schema[1]; + static const ::google::protobuf::internal::FieldMetadata field_metadata[]; + static const ::google::protobuf::internal::SerializationTable serialization_table[]; + static const ::google::protobuf::uint32 offsets[]; +}; +void AddDescriptors(); +void InitDefaultsEmptyImpl(); +void InitDefaultsEmpty(); +inline void InitDefaults() { + InitDefaultsEmpty(); +} +} // namespace protobuf_sdk_2eproto +namespace stable { +namespace agon { +namespace io { +namespace sdk { +class Empty; +class EmptyDefaultTypeInternal; +extern EmptyDefaultTypeInternal _Empty_default_instance_; +} // namespace sdk +} // namespace io +} // namespace agon +} // namespace stable +namespace stable { +namespace agon { +namespace io { +namespace sdk { + +// =================================================================== + +class Empty : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:stable.agon.io.sdk.Empty) */ { + public: + Empty(); + virtual ~Empty(); + + Empty(const Empty& from); + + inline Empty& operator=(const Empty& from) { + CopyFrom(from); + return *this; + } + #if LANG_CXX11 + Empty(Empty&& from) noexcept + : Empty() { + *this = ::std::move(from); + } + + inline Empty& operator=(Empty&& from) noexcept { + if (GetArenaNoVirtual() == from.GetArenaNoVirtual()) { + if (this != &from) InternalSwap(&from); + } else { + CopyFrom(from); + } + return *this; + } + #endif + static const ::google::protobuf::Descriptor* descriptor(); + static const Empty& default_instance(); + + static void InitAsDefaultInstance(); // FOR INTERNAL USE ONLY + static inline const Empty* internal_default_instance() { + return reinterpret_cast( + &_Empty_default_instance_); + } + static PROTOBUF_CONSTEXPR int const kIndexInFileMessages = + 0; + + void Swap(Empty* other); + friend void swap(Empty& a, Empty& b) { + a.Swap(&b); + } + + // implements Message ---------------------------------------------- + + inline Empty* New() const PROTOBUF_FINAL { return New(NULL); } + + Empty* New(::google::protobuf::Arena* arena) const PROTOBUF_FINAL; + void CopyFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL; + void MergeFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL; + void CopyFrom(const Empty& from); + void MergeFrom(const Empty& from); + void Clear() PROTOBUF_FINAL; + bool IsInitialized() const PROTOBUF_FINAL; + + size_t ByteSizeLong() const PROTOBUF_FINAL; + bool MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input) PROTOBUF_FINAL; + void SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const PROTOBUF_FINAL; + ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray( + bool deterministic, ::google::protobuf::uint8* target) const PROTOBUF_FINAL; + int GetCachedSize() const PROTOBUF_FINAL { return _cached_size_; } + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const PROTOBUF_FINAL; + void InternalSwap(Empty* other); + private: + inline ::google::protobuf::Arena* GetArenaNoVirtual() const { + return NULL; + } + inline void* MaybeArenaPtr() const { + return NULL; + } + public: + + ::google::protobuf::Metadata GetMetadata() const PROTOBUF_FINAL; + + // nested types ---------------------------------------------------- + + // accessors ------------------------------------------------------- + + // @@protoc_insertion_point(class_scope:stable.agon.io.sdk.Empty) + private: + + ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_; + mutable int _cached_size_; + friend struct ::protobuf_sdk_2eproto::TableStruct; + friend void ::protobuf_sdk_2eproto::InitDefaultsEmptyImpl(); +}; +// =================================================================== + + +// =================================================================== + +#ifdef __GNUC__ + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wstrict-aliasing" +#endif // __GNUC__ +// Empty + +#ifdef __GNUC__ + #pragma GCC diagnostic pop +#endif // __GNUC__ + +// @@protoc_insertion_point(namespace_scope) + +} // namespace sdk +} // namespace io +} // namespace agon +} // namespace stable + +// @@protoc_insertion_point(global_scope) + +#endif // PROTOBUF_sdk_2eproto__INCLUDED