Go Runtime #
Nakama server can run trusted game server code written in Go, allowing you to separate sensitive code such as purchases, daily rewards, etc., from running on clients.
Choosing to write your game server custom logic using Go brings with it the advantage that Go runtime code has full low-level access to the server and its environment.
Prerequisites #
You will need to have these tools installed to use the Nakama Go server runtimes:
- The Go Binaries
- Basic UNIX tools or knowledge on the Windows equivalents
- Docker Desktop if you’re planning to run Nakama using Docker
Nakama Common version #
Be sure your project’s go.mod
file references the correct Nakama Common version for your Nakama release:
Nakama Version | Nakama Common Version |
---|---|
3.25.0 | 1.35.0 |
3.24.2 | 1.34.0 |
3.24.1 | 1.34.0 |
3.24.0 | 1.34.0 |
3.23.0 | 1.33.0 |
3.22.0 | 1.32.0 |
3.21.1 | 1.31.0 |
3.21.0 | 1.31.0 |
3.20.1 | 1.30.1 |
3.20.0 | 1.30.1 |
3.19.0 | 1.30.0 |
3.18.0 | 1.29.0 |
3.17.1 | 1.28.1 |
3.17.0 | 1.28.0 |
3.16.0 | 1.27.0 |
3.15.0 | 1.26.0 |
3.14.0 | 1.25.0 |
3.13.1 | 1.24.0 |
3.12.0 | 1.23.0 |
3.11.0 | 1.22.0 |
3.10.0 | 1.21.0 |
3.9.0 | 1.20.0 |
3.8.0 | 1.19.0 |
3.7.0 | 1.18.0 |
3.6.0 | 1.17.0 |
3.5.0 | 1.16.0 |
3.4.0 | 1.15.0 |
3.3.0 | 1.14.0 |
3.2.1 | 1.13.1 |
3.2.0 | 1.13.0 |
3.1.2 | 1.12.1 |
3.1.1 | 1.12.1 |
3.1.0 | 1.12.0 |
3.0.0 | 1.11.0 |
Restrictions #
Before getting started with Go runtime code, be aware of the following restrictions and limitations:
Compatibility #
Go runtime code can make use of the full range of standard library functions and packages.
Go runtime available functionality depends on the version of Go each Nakama release is compiled with. This is usually the latest stable version at the time of release. Check server startup logs for the exact Go version used by your Nakama installation.
Single threaded #
The use of multi-threaded processing (goroutines) in your runtime code is discouraged due to difficulties of implementation in a multi-node environment.
Global state #
The Go runtime can use global variables as a way to store state in memory and store and share data as needed, but concurrency and access controls are the responsibility of the developer.
Sharing state is discouraged and should be avoided in your runtime code as it is not supported in multi-node environments.
Sandboxing #
There is no sandboxing when using Go for your runtime code. Go runtime code has full low-level access to the server and its environment.
This allows full flexibility and control to include powerful features and offer high performance, but cannot guarantee error safety. The server does not guard against fatal errors in Go runtime code, such as segmentation faults or pointer dereference failures.
Initialize the project #
These steps will set up a workspace to write all your project code to be run by the game server.
Define the folder name that will be the workspace for the project.
|
|
Use Go to initialize the project, providing a valid Go module path, and install the Nakama runtime package.
|
|
Develop code #
All code must start execution from a function that the game server looks for in the global scope at startup. This function must be called InitModule
and is how you register RPCs, before/after hooks, and other event functions managed by the server.
The code below is a simple Hello World example which uses the Logger
to write a message. Name the source file main.go
. You can write it in your favorite editor or IDE.
|
|
With this code added, head back to your Terminal/Command Prompt and run the following command to vendor your Go package dependencies.
|
|
When you Vendor your Go package dependencies it will place a copy of them inside a vendor/
folder at the root of your project, as well as a go.sum
file. Both of these should be checked in to your source control repository.
Next add a local.yml
Nakama server configuration file. You can read more about what configuration options are available.
|
|
Error handling #
Go functions typically return error values when an error occurs. To handle the error thrown by a custom function or one provided by the runtime, you must inspect the error return value.
|
|
We recommend you use this pattern and wrap all runtime API calls for error handling and inspection.
|
|
Returning errors to the client #
When writing your own custom runtime code, you should ensure that any errors that occur when processing a request are passed back to the client appropriately. This means that the error returned to the client should contain a clear and informative error message and an appropriate HTTP status code.
Internally the Nakama runtime uses gRPC error codes and converts them to the appropriate HTTP status codes when returning the error to the client.
You can define the gRPC error codes as constants in your Go module as shown below:
|
|
Once you have defined the error code constants, you can use them to define error
objects using the runtime.NewError("error message", GRPC_CODE)
function. The following are some examples of errors you might define in your module.
|
|
Below is an example of how you would return appropriate errors both in an RPC call and in a Before Hook.
|
|
Build the Go shared object #
In order to use your custom logic inside the Nakama server, you need to compile it into a shared object.
|
|
If you are using Windows you will not be able to run this command as there is currently no support for building Go Plugins on Windows. You can use the Dockerfile example below instead to run the server using Docker.
If you’re using the Docker method of running the Nakama server below, you do not need to build the Go Shared Object separately as the Dockerfile
will take of this.
Running the project #
With Docker #
The easiest way to run your server locally is with Docker. For your Go module to work with Nakama it needs to be compiled using the same version of Go as was used to compile the Nakama binary itself. You can guarantee this by using the same version tags of the nakama-pluginbuilder
and nakama
images as you can see below.
Create a file called Dockerfile
.
|
|
Next create a docker-compose.yml
file. For more information see the Install Nakama with Docker Compose documentation.
|
|
Now run the server with the command:
|
|
Without Docker #
Install a Nakama binary stack for Linux, Windows, or macOS. When this is complete you can run the game server and have it load your code:
|
|
Confirming the server is running #
The server logs will show this output or similar which shows that the code we wrote above was loaded and executed at startup.
|
|
Register Raw HTTP Handlers #
You can attach new HTTP handlers to specified paths on the main client API server endpoint.
|
|
You can also register new HTTP handles for specific methods only. The methods that can be registered are: GET, HEAD, POST, PUT, PATCH, DELETE, CONNECT, OPTIONS, and TRACE. If you don’t specify any method when defining the handler, such as the example above, it will register the endpoint for all of them.
Example of GET only:
|
|
Or of POST or PUT only:
|
|
Next steps #
Have a look at the Nakama project template which covers the following Nakama features: