Third-party service integration
This guide takes you through some of the things to think about when integrating a third-party service into your SpatialOS game.
Workers are just normal programs
In general, a worker is just a normal program that connects to SpatialOS at some point of its lifecycle (usually when it starts). It then receives updates from SpatialOS, and the worker can choose to do whatever it likes with those updates.
When creating a worker, or using one of the existing worker SDKs, you can choose when the worker connects to SpatialOS, you can create other threads to perform other tasks, you can make any HTTP requests you like and you can use any third-party SDK like normal. SpatialOS doesn’t aim to restrict you to a closed ecosystem of services.
There are however, a couple of things you need to be careful about:
Don’t block on any SpatialOS callbacks
A good practice would be to add tasks to a queue in the callbacks, then have other consumer tasks processing the queue, performing longer tasks with the data.
Not blocking on the callbacks can also help prevent any deadlocks appearing in the callbacks. A deadlock could prevent the worker from processing updates from SpatialOS.
Managed workers should connect to SpatialOS as soon as they start
In order to load balance, SpatialOS can dynamically adjust the number of workers required for a task. This means it needs to be able to spin up and tear down managed workers quickly. To facilitate this, managed workers should connect to SpatialOS quickly after starting.
External workers however, for example a client, can connect to SpatialOS whenever they like. For instance, you may want to have an OAuth flow or a traditional game lobby before you connect to SpatialOS.
Storing secret keys
Often a third-party service will have secret API keys that are sent with the requests from the server side.
It’s very important that the binaries you send to the players do not contain these secret keys. For example, if you are compiling a managed worker and a client from the same codebase, any string you have in that codebase will be compiled in with both the managed worker and the client. Therefore, if you store a secret key as a constant, a player could decompile the client and retrieve this secret key.
One method of preventing this is to pass the secret key as a command line argument to the managed workers using the worker.json’s launch configuration section.
Alternatively, you could use a compilation flag to only compile the secret key with the managed worker codebase.
Typically, a third-party service would have endpoints for the client to authenticate the player, and possibly read player data, update some player state etc. The service would also have endpoints for the server which has full authority to change state about the game, or state about any player.
The server will typically identify the player by some player ID which is obtained during the authentication procedure. The server can then send this player ID when it makes requests to the service.
In SpatialOS, the external worker can authenticate the player (for example, by logging in). Data identifying the player can then be sent to the managed workers and can be kept in a component on the player entity.
It is really important that the player ID in the player’s component is the correct player ID for that player, as if they could change it, they can effectively play as a different player. There are two ways a player could give the false player ID:
The client could modify the player ID component value
It is important to assume that the client can be hacked, and they can change any component which they have authority over. For this reason, you need to have the managed workers authoritative over any components identifying the player.
The client could send a false player ID to the managed workers initially
When the client logs in to the third-party service, it will receive data identifying the player. This data can then be sent to the managed workers in order to identify the player when making server side requests during the game.
Often, data such as the player ID can be easily fabricated or changed, they could even be public for each user. This means a client could be hacked to send over a different player ID when the player entity is spawned, allowing them to play as another user.
To prevent this, you need to send authentication data from the client to the managed workers which cannot easily be fabricated. Many third-party services will have systems like session tickets for this. The client can then send over a ticket generated at login, and then the managed workers can use a server side endpoint to verify the given ticket and get back the correct player data.