Skip to content

Commit 5ec9dfa

Browse files
Robert Baileymarkmandel
authored andcommitted
Updates to the C++ SDK along with the simple example that exercises (agones-dev#934)
it. Create a tutorial to show how to build / run the simple C++ example.
1 parent 3fef404 commit 5ec9dfa

9 files changed

Lines changed: 378 additions & 93 deletions

File tree

‎examples/cpp-simple/Makefile‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ REPOSITORY = gcr.io/agones-images
2828
# Directory that this Makefile is in.
2929
mkfile_path := $(abspath $(lastword $(MAKEFILE_LIST)))
3030
project_path := $(dir $(mkfile_path))
31-
server_tag = $(REPOSITORY)/cpp-simple-server:0.5
31+
server_tag = $(REPOSITORY)/cpp-simple-server:0.9
3232
root_path = $(realpath $(project_path)/../..)
3333

3434
# _____ _

‎examples/cpp-simple/README.md‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,12 @@ It will
88
- Every 10 seconds, write a log saying "Hi! I'm a Game Server"
99
- After 60 seconds, call `SDK::Shutdown()` to shut the server down.
1010

11+
To learn how to deploy this example service to GKE, please see the tutorial [Build and Run a Simple Gameserver (C++)](https://agones.dev/site/docs/tutorials/simple-gameserver-cpp/).
12+
1113
## Building
1214

13-
Easiest way is to run `make build` from this directory. This will run the `docker build` command with the correct context.
15+
If you want to modify the source code and/or build an updated container image, run `make build` from this directory.
16+
This will run the `docker build` command with the correct context.
1417

1518
This example uses the [Docker builder pattern](https://docs.docker.com/develop/develop-images/multistage-build/) to
1619
build the SDK, example and host it inside a container.

‎examples/cpp-simple/fleet.yaml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,5 +30,5 @@ spec:
3030
spec:
3131
containers:
3232
- name: cpp-simple
33-
image: gcr.io/agones-images/cpp-simple-server:0.5
33+
image: gcr.io/agones-images/cpp-simple-server:0.9
3434
# imagePullPolicy: Always # add for development

‎examples/cpp-simple/gameserver.yaml‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,5 +27,5 @@ spec:
2727
spec:
2828
containers:
2929
- name: cpp-simple
30-
image: gcr.io/agones-images/cpp-simple-server:0.5
31-
# imagePullPolicy: Always # add for development
30+
image: gcr.io/agones-images/cpp-simple-server:0.9
31+
imagePullPolicy: Always # add for development

‎examples/cpp-simple/server.cc‎

Lines changed: 87 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -16,101 +16,104 @@
1616
// This example really does nothing other than show how to integrate
1717
// the C++ SDK.
1818

19-
#include <iostream>
20-
#include <thread>
2119
#include <agones/sdk.h>
2220
#include <grpc++/grpc++.h>
21+
#include <iostream>
22+
#include <thread>
2323

2424
// send health check pings
25-
void doHealth(agones::SDK *sdk) {
26-
while (true) {
27-
if (!sdk->Health()) {
28-
std::cout << "Health ping failed" << std::endl;
29-
} else {
30-
std::cout << "Health ping sent" << std::endl;
31-
}
32-
std::this_thread::sleep_for(std::chrono::seconds(2));
33-
}
25+
void DoHealth(std::shared_ptr<agones::SDK> sdk) {
26+
while (true) {
27+
bool ok = sdk->Health();
28+
std::cout << "Health ping " << (ok ? "sent" : "failed") << "\n"
29+
<< std::flush;
30+
std::this_thread::sleep_for(std::chrono::seconds(2));
31+
}
3432
}
3533

3634
// watch GameServer Updates
37-
void watchUpdates(agones::SDK *sdk) {
38-
std::cout << "Starting to watch GameServer updates..." << std::endl;
39-
sdk->WatchGameServer([](stable::agones::dev::sdk::GameServer gameserver){
40-
std::cout << "GameServer Update, name: " << gameserver.object_meta().name() << std::endl;
41-
std::cout << "GameServer Update, state: " << gameserver.status().state() << std::endl;
42-
});
35+
void WatchUpdates(std::shared_ptr<agones::SDK> sdk) {
36+
std::cout << "Starting to watch GameServer updates...\n" << std::flush;
37+
sdk->WatchGameServer([](agones::dev::sdk::GameServer gameserver) {
38+
std::cout << "GameServer Update:\n" //
39+
<< "\tname: " << gameserver.object_meta().name() << "\n" //
40+
<< "\tstate: " << gameserver.status().state() << "\n"
41+
<< std::flush;
42+
});
4343
}
4444

4545
int main() {
46-
std::cout << "C++ Game Server has started!" << std::endl;
47-
48-
std::cout << "Getting the instance of the SDK!" << std::endl;
49-
agones::SDK *sdk = new agones::SDK();
50-
51-
std::cout << "Attempting to connect..." << std::endl;
52-
bool connected = sdk->Connect();
53-
if (!connected) {
54-
std::cout << "Could not connect to the sidecar. Exiting!" << std::endl;
55-
return -1;
56-
}
57-
std::cout << "...handshake complete." << std::endl;
58-
59-
std::thread health (doHealth, sdk);
60-
std::thread watch (watchUpdates, sdk);
61-
62-
std::cout << "Setting a label" << std::endl;
63-
grpc::Status status = sdk->SetLabel("test-label", "test-value");
64-
if (!status.ok()) {
65-
std::cout << "Could not run SetLabel(): "+ status.error_message() + ". Exiting!" << std::endl;
66-
return -1;
67-
}
68-
69-
std::cout << "Setting an annotation" << std::endl;
70-
status = sdk->SetAnnotation("test-annotation", "test value");
71-
if (!status.ok()) {
72-
std::cout << "Could not run SetAnnotation(): "+ status.error_message() + ". Exiting!" << std::endl;
46+
std::cout << "C++ Game Server has started!\n"
47+
<< "Getting the instance of the SDK.\n"
48+
<< std::flush;
49+
auto sdk = std::make_shared<agones::SDK>();
50+
51+
std::cout << "Attempting to connect...\n" << std::flush;
52+
if (!sdk->Connect()) {
53+
std::cerr << "Could not connect to the sidecar. Exiting!\n";
54+
return -1;
55+
}
56+
std::cout << "...handshake complete.\n" << std::flush;
57+
58+
std::thread health(DoHealth, sdk);
59+
std::thread watch(WatchUpdates, sdk);
60+
61+
std::cout << "Setting a label\n" << std::flush;
62+
grpc::Status status = sdk->SetLabel("test-label", "test-value");
63+
if (!status.ok()) {
64+
std::cerr << "Could not run SetLabel(): " << status.error_message()
65+
<< ". Exiting!\n";
66+
return -1;
67+
}
68+
69+
std::cout << "Setting an annotation\n" << std::flush;
70+
status = sdk->SetAnnotation("test-annotation", "test value");
71+
if (!status.ok()) {
72+
std::cerr << "Could not run SetAnnotation(): " << status.error_message()
73+
<< ". Exiting!\n";
74+
return -1;
75+
}
76+
77+
std::cout << "Marking server as ready...\n" << std::flush;
78+
status = sdk->Ready();
79+
if (!status.ok()) {
80+
std::cerr << "Could not run Ready(): " << status.error_message()
81+
<< ". Exiting!\n";
82+
return -1;
83+
}
84+
std::cout << "...marked Ready\n" << std::flush;
85+
86+
std::cout << "Getting GameServer details...\n" << std::flush;
87+
agones::dev::sdk::GameServer gameserver;
88+
status = sdk->GameServer(&gameserver);
89+
90+
if (!status.ok()) {
91+
std::cerr << "Could not run GameServer(): " << status.error_message()
92+
<< ". Exiting!\n";
93+
return -1;
94+
}
95+
96+
std::cout << "GameServer name: " << gameserver.object_meta().name() << "\n"
97+
<< std::flush;
98+
99+
for (int i = 0; i < 10; i++) {
100+
int time = i * 10;
101+
std::cout << "Running for " + std::to_string(time) + " seconds !\n"
102+
<< std::flush;
103+
104+
std::this_thread::sleep_for(std::chrono::seconds(10));
105+
106+
if (i == 5) {
107+
std::cout << "Shutting down after 60 seconds...\n" << std::flush;
108+
grpc::Status status = sdk->Shutdown();
109+
if (!status.ok()) {
110+
std::cerr << "Could not run Shutdown():" << status.error_message()
111+
<< ". Exiting!\n";
73112
return -1;
113+
}
114+
std::cout << "...marked for Shutdown\n" << std::flush;
74115
}
116+
}
75117

76-
std::cout << "Marking server as ready..." << std::endl;
77-
status = sdk->Ready();
78-
if (!status.ok()) {
79-
std::cout << "Could not run Ready(): "+ status.error_message() + ". Exiting!" << std::endl;
80-
return -1;
81-
}
82-
83-
std::cout << "...marked Ready" << std::endl;
84-
85-
std::cout << "Getting GameServer details..." << std::endl;
86-
stable::agones::dev::sdk::GameServer gameserver;
87-
status = sdk->GameServer(&gameserver);
88-
89-
if (!status.ok()) {
90-
std::cout << "Could not run GameServer(): "+ status.error_message() + ". Exiting!" << std::endl;
91-
return -1;
92-
}
93-
94-
std::cout << "GameServer name: " << gameserver.object_meta().name() << std::endl;
95-
96-
for (int i = 0; i < 10; i++) {
97-
int time = i*10;
98-
std::cout << "Running for " + std::to_string(time) + " seconds !" << std::endl;
99-
100-
std::this_thread::sleep_for(std::chrono::seconds(10));
101-
102-
if (i == 5) {
103-
std::cout << "Shutting down after 60 seconds..." << std::endl;
104-
grpc::Status status = sdk->Shutdown();
105-
if (!status.ok()) {
106-
std::cout << "Could not run Shutdown():" + status.error_message() + ". Exiting!" << std::endl;
107-
return -1;
108-
}
109-
std::cout << "...marked for Shutdown" << std::endl;
110-
}
111-
}
112-
113-
delete sdk;
114-
115-
return 0;
118+
return 0;
116119
}

‎sdks/cpp/CMakeLists.txt‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,9 +179,14 @@ install(
179179
FILES ${HEADER_FILES} "${CMAKE_CURRENT_BINARY_DIR}/${EXPORT_HEADER}" "${CMAKE_CURRENT_BINARY_DIR}/${GLOBAL_HEADER}"
180180
DESTINATION ${_INCLUDE_DIRS}/${PROJECT_NAME}
181181
)
182+
# Generated header files
183+
install(
184+
FILES ${GENERATED_HEADER_FILES}
185+
DESTINATION ${_INCLUDE_DIRS}/${PROJECT_NAME}
186+
)
182187
# Google header files
183188
install(
184-
FILES ${GOOGLE_HEADER_FILES}
189+
FILES ${GENERATED_GOOGLE_HEADER_FILES}
185190
DESTINATION ${_INCLUDE_DIRS}/google/api
186191
)
187192

‎sdks/cpp/sources.cmake‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,19 @@ set(HEADER_FILES
99
set(GENERATED_SOURCE_FILES
1010
src/agones/sdk.grpc.pb.cc
1111
src/agones/sdk.pb.cc
12+
)
13+
14+
set(GENERATED_GOOGLE_SOURCE_FILES
1215
src/google/annotations.pb.cc
1316
src/google/http.pb.cc
1417
)
1518

1619
set(GENERATED_HEADER_FILES
1720
include/agones/sdk.grpc.pb.h
1821
include/agones/sdk.pb.h
22+
)
23+
24+
set(GENERATED_GOOGLE_HEADER_FILES
1925
include/google/api/annotations.pb.h
2026
include/google/api/http.pb.h
2127
)
@@ -24,7 +30,9 @@ set(ALL_FILES
2430
${SOURCE_FILES}
2531
${HEADER_FILES}
2632
${GENERATED_SOURCE_FILES}
33+
${GENERATED_GOOGLE_SOURCE_FILES}
2734
${GENERATED_HEADER_FILES}
35+
${GENERATED_GOOGLE_HEADER_FILES}
2836
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}_export.h"
2937
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}_global.h"
3038
)

‎sdks/cpp/src/agones/sdk.cc‎

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ struct SDK::SDKImpl {
2323
std::shared_ptr<grpc::Channel> channel_;
2424
std::unique_ptr<agones::dev::sdk::SDK::Stub> stub_;
2525
std::unique_ptr<grpc::ClientWriter<agones::dev::sdk::Empty>> health_;
26+
std::unique_ptr<grpc::ClientContext> health_context_;
2627
};
2728

2829
SDK::SDK() : pimpl_{std::make_unique<SDKImpl>()} {
@@ -41,10 +42,11 @@ bool SDK::Connect() {
4142

4243
pimpl_->stub_ = agones::dev::sdk::SDK::NewStub(pimpl_->channel_);
4344

44-
// make the health connection
45+
// Make the health connection.
4546
agones::dev::sdk::Empty response;
46-
grpc::ClientContext context;
47-
pimpl_->health_ = pimpl_->stub_->Health(&context, &response);
47+
pimpl_->health_context_ =
48+
std::unique_ptr<grpc::ClientContext>(new grpc::ClientContext);
49+
pimpl_->health_ = pimpl_->stub_->Health(&*pimpl_->health_context_, &response);
4850

4951
return true;
5052
}

0 commit comments

Comments
 (0)