CUGL 3.0
Cornell University Game Library
All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends
Classes | Public Types | Public Member Functions | Static Public Member Functions | List of all members
cugl::netcode::WebSocketServer Class Reference

#include <CUWebSocketServer.h>

Inheritance diagram for cugl::netcode::WebSocketServer:

Public Types

typedef std::function< void(const std::string client, const std::string path)> ConnectionCallback
 
typedef std::function< void(const std::string source, const std::vector< std::byte > &message, Uint64 time)> Dispatcher
 

Public Member Functions

 WebSocketServer ()
 
 ~WebSocketServer ()
 
bool isActive () const
 
uint16_t getPort () const
 
size_t getCapacity ()
 
void setCapacity (size_t capacity)
 
const std::unordered_set< std::string > getConnections ()
 
const std::unordered_set< std::string > getConnections (std::string path)
 
bool isConnected (const std::string client)
 
size_t getNumConnections ()
 
void start ()
 
void stop ()
 
bool sendTo (const std::string dst, const std::vector< std::byte > &data)
 
bool sendTo (const std::string dst, std::vector< std::byte > &&data)
 
bool broadcast (const std::string path, const std::vector< std::byte > &data)
 
bool broadcast (const std::vector< std::byte > &data)
 
void receive (const Dispatcher &dispatcher)
 
void onReceipt (Dispatcher callback)
 
void onConnect (ConnectionCallback callback)
 
void onDisconnect (ConnectionCallback callback)
 
void setDebug (bool flag)
 
bool getDebug () const
 

Static Public Member Functions

static std::shared_ptr< WebSocketServeralloc (const WebSocketConfig &config)
 
static std::shared_ptr< WebSocketServeralloc (WebSocketConfig &&config)
 

Detailed Description

This class to supports a long running websocket server.

The class NetcodeConnection is built upon WebRTC for high speed communication. A side effect of this is that CUGL has access to websockets, an ubiquitous framework for creating servers. While not as performant as WebRTC, websockets are relatively simple to use, which makes sense to expose them to the rest of the engine. This particular class allows you to set up a server inside of CUGL. When combined with headless mode, this make it possible to deploy an instance of CUGL on the cloud.

Websockets can still be a little difficult for beginners, as bi-directional communication requires either a multi-threaded or an asynchronous (e.g. coroutines) environment. While these are possible in CUGL, it makes much more sense to synchronize messages receival and dispatch with the game loop, in much the same way that we did for NetcodeConnection. Hence this class shares a lot of the same features as that class.

In particular, this class is as if the application were running an instance of NetcodeConnection in host mode. It is periodically notified of connections (and disconnections). And it can receive messages from each connection and identify the source of the message. And it can send messages either to a single connection, or broadcast to a group of them.

There are some important difference from NetcodeConnection, however. There is no lobby, as this class acts as the server lobby. That means this device must have a publicly available address to connect to. This is unlikely to be the case between mobile devices (our primary application).

In addition, as a layer on top of TCP, the performance of this connection will not be as high as that of NetcodeConnection which uses UDP style communication.

One last difference is how this class refers to its connections. Unlike NetcodeConnection, we do not use UUIDs to reference connections. Instead a connection is refered to by its remote internet address (address and port) plus the connection timestamp in hexadecimal form.

In addition, all connections have a path, which is a string resembling a file name path. In NetcodeConnection we used these paths to differentiate connections. However, paths do not have to be unique. They are simply a way of grouping together connections of similar functionality.

It is completely unsafe for network connections to be used on the stack. For that reason, this class hides the initialization methods (and the constructors create uninitialized connections). You are forced to go through the static allocator alloc to create instances of this class.

Member Typedef Documentation

◆ ConnectionCallback

This type represents a callback for the WebSocketServer class.

This type refers to two different possible callbacks: one when a client connects and another when it disconnects. In each case the client id and path are identified. The client id is a string built from its remote internet address (as seen by the server) and the timestamp of connection in hexadecimal form.

Callback functions differ from listeners (found in the input classes) in that only one callback of any type is allowed in a WebSocketServer class. Callback functions are guaranteed to be called at the start of an animation frame, before the method Application#update(float).

The function type is equivalent to

 std::function<void(const std::string client, const std::string path)>
Parameters
clientThe client identifier
pathThe connection path

◆ Dispatcher

The dispatcher is called by the receive function to consume data from the message buffer. Not only does it relay the message data, but it also communicates the client that sent it. We also include a timestamp of the number of microseconds that have passed since the function NetworkLayer#start was called.

The function type is equivalent to

 const std::function<void(const std::string client,
                          const std::vector<std::byte>& message
                          Uint64 time)>
Parameters
clientThe client identifier
messageThe message data
timeThe number of microseconds since NetworkLayer#start

Constructor & Destructor Documentation

◆ WebSocketServer()

cugl::netcode::WebSocketServer::WebSocketServer ( )

Creates a degenerate websocket server

This object has not been initialized with a WebSocketConfig and cannot be used.

You should NEVER USE THIS CONSTRUCTOR. All connections should be created by the static constructor alloc instead.

◆ ~WebSocketServer()

cugl::netcode::WebSocketServer::~WebSocketServer ( )

Deletes this websocket server, disposing all resources

Member Function Documentation

◆ alloc() [1/2]

static std::shared_ptr< WebSocketServer > cugl::netcode::WebSocketServer::alloc ( const WebSocketConfig config)
inlinestatic

Returns a newly allocated websocket server.

This method initializes this websocket server with all of the correct settings. However, it does not actually start the server. You must call the method start to allow incoming connections. This design decision is intended to give the user a chance to set the callback functions before connection is established.

This method will always return false if the NetworkLayer failed to initialize.

Parameters
configThe server configuration
Returns
a newly allocated websocket server.

◆ alloc() [2/2]

static std::shared_ptr< WebSocketServer > cugl::netcode::WebSocketServer::alloc ( WebSocketConfig &&  config)
inlinestatic

Returns a newly allocated websocket server.

This method initializes this websocket server with all of the correct settings. However, it does not actually start the server. You must call the method start to allow incoming connections. This design decision is intended to give the user a chance to set the callback functions before connection is established.

This method will always return false if the NetworkLayer failed to initialize.

Parameters
configThe server configuration
Returns
a newly allocated websocket server.

◆ broadcast() [1/2]

bool cugl::netcode::WebSocketServer::broadcast ( const std::string  path,
const std::vector< std::byte > &  data 
)

Sends a byte array to all other connections on the given path.

This message will be sent to all clients that connected via the given path. As with sendTo, communication to a particular client is guaranteed to be ordered. So if we broadcasts two messages, all matching clients will receive those messages in the same order. However, there is no relationship between the messages arriving at different clients. This method also respects the order of sendTo.

You may choose to either send a byte array directly, or you can use the NetcodeSerializer and NetcodeDeserializer classes to encode more complex data.

This requires that there be at least one connection on the given path. Otherwise it will return false. In fact, to return true, it must succeed on sending to all of the connections.

Parameters
pathThe path to broadcast to
dataThe byte array to send.
Returns
true if the message was (apparently) sent

◆ broadcast() [2/2]

bool cugl::netcode::WebSocketServer::broadcast ( const std::vector< std::byte > &  data)

Sends a byte array to all connections.

This message will be sent to all connected clients. As with sendTo, communication to a particular client is guaranteed to be ordered. So if we broadcasts two messages, all clients will receive those messages in the same order. However, there is no relationship between the messages arriving at different clients. This method also respects the order of sendTo.

You may choose to either send a byte array directly, or you can use the NetcodeSerializer and NetcodeDeserializer classes to encode more complex data.

This requires that there be at least one connection on the given path. Otherwise it will return false. In fact, to return true, it must succeed on sending to all of the connections.

Parameters
dataThe byte array to send.
Returns
true if the message was (apparently) sent

◆ getCapacity()

size_t cugl::netcode::WebSocketServer::getCapacity ( )

Returns the message buffer capacity.

It is possible for this connection to receive several messages over the network before it has a chance to all receive. This buffer stores those messages to be read later. The capacity indicates the number of messages that can be stored.

Note that this is NOT the same as the capacity of a single message. That value was set as part of the initial WebSocketConfig.

This method is not const because it requires a lock.

Returns
the message buffer capacity.

◆ getConnections() [1/2]

const std::unordered_set< std::string > cugl::netcode::WebSocketServer::getConnections ( )

Returns the list of active connections

This vector stores the identifiers of all the connections. These identifiers are a string built from the connection remote internet address (as seen by the server) and the timestamp of connection in hexadecimal form.

This method is not const because it requires a lock.

Returns
the list of active connections

◆ getConnections() [2/2]

const std::unordered_set< std::string > cugl::netcode::WebSocketServer::getConnections ( std::string  path)

Returns the list of active connections for the given path

This vector stores the identifiers of all the connections. These identifiers are a string built from the connection remote internet address (as seen by the server) and the timestamp of connection in hexadecimal form.

This method is not const because it requires a lock.

Parameters
pathThe path to query
Returns
the list of active connections for the given path

◆ getDebug()

bool cugl::netcode::WebSocketServer::getDebug ( ) const
inline

Returns the debugging status of this connection.

If debugging is active, connections will be quite verbose

Returns
the debugging status of this connection.

◆ getNumConnections()

size_t cugl::netcode::WebSocketServer::getNumConnections ( )

Returns the number of clients currently connected to this server

This does not include any clients that have been disconnected.

This method is not const because it requires a lock.

Returns
the number of clients currently connected to this server

◆ getPort()

uint16_t cugl::netcode::WebSocketServer::getPort ( ) const

Returns the port for this server

Returns
the port for this server

◆ isActive()

bool cugl::netcode::WebSocketServer::isActive ( ) const
inline

Returns true if this server is active and accepting connections.

Returns
true if this server is active and accepting connections.

◆ isConnected()

bool cugl::netcode::WebSocketServer::isConnected ( const std::string  client)

Returns true if the given client is currently connected.

A client id is a string built from its remote internet address (as seen by the server) and the timestamp of connection in hexadecimal form.

This method is not const because it requires a lock.

Parameters
clientThe player to test for connection
Returns
true if the given client is currently connected.

◆ onConnect()

void cugl::netcode::WebSocketServer::onConnect ( ConnectionCallback  callback)

Sets a callback function to invoke on player connections

The websocket will keep a player aware of any connections that may happen. This callback will update getConnections after any such connection. Hence connections can be detected through polling or this callback interface. If this information is important to you, the callback interface is preferred.

All callback functions are guaranteed to be called on the main thread. They are called at the start of an animation frame, before the method Application#update(float).

Parameters
callbackThe connection callback

◆ onDisconnect()

void cugl::netcode::WebSocketServer::onDisconnect ( ConnectionCallback  callback)

Sets a callback function to invoke on player disconnections

The websocket will keep a player aware of any disconnections that may happen. This callback will update getConnections after any such disconnection. Hence disconnections can be detected through polling or this callback interface. If this information is important to you, the callback interface is preferred.

All callback functions are guaranteed to be called on the main thread. They are called at the start of an animation frame, before the method Application#update(float).

Parameters
callbackThe disconnection callback

◆ onReceipt()

void cugl::netcode::WebSocketServer::onReceipt ( Dispatcher  callback)

Sets a callback function to invoke on message receipt

This callback is alternative to the method receive. Instead of buffering messages and calling that method each frame, this callback function will be invoked as soon as the message is received.

All callback functions are guaranteed to be called on the main thread. They are called at the start of an animation frame, before the method Application#update(float).

Parameters
callbackThe dispatcher callback

◆ receive()

void cugl::netcode::WebSocketServer::receive ( const Dispatcher dispatcher)

Receives incoming network messages.

When executed, the function dispatch willl be called on every received byte array since the last call to receive. It is up to you to interpret this data on your own or with NetcodeDeserializer

A network frame can, but need not be, the same as a render frame. Your dispatch function should be prepared to be called multiple times a render frame, or even not at all.

If a dispatcher callback has been registered with onReceipt, this method will never do anything. In that case, messages are not buffered and are processed as soon as they are received. However, this method has the advantage that it can be read on a separate thread.

Parameters
dispatcherThe function to process received data

◆ sendTo() [1/2]

bool cugl::netcode::WebSocketServer::sendTo ( const std::string  dst,
const std::vector< std::byte > &  data 
)

Sends a byte array to the specified connection.

As a websocket server can have multiple connections, this method i sused to send a communication to a specific client. Communication from this server is guaranteed to be ordered for an individual client. So if this server sends to messages to client B, client B will receive those messages in the same order. However, there is no relationship between the messages sent to different clients.

You may choose to either send a byte array directly, or you can use the NetcodeSerializer and NetcodeDeserializer classes to encode more complex data.

This requires that the destination be connected. Otherwise it will return false.

Parameters
dstThe identifier of the client to send to
dataThe byte array to send.
Returns
true if the message was (apparently) sent

◆ sendTo() [2/2]

bool cugl::netcode::WebSocketServer::sendTo ( const std::string  dst,
std::vector< std::byte > &&  data 
)

Sends a byte array to the specified connection.

As a websocket server can have multiple connections, this method i sused to send a communication to a specific client. Communication from this server is guaranteed to be ordered for an individual client. So if this server sends to messages to client B, client B will receive those messages in the same order. However, there is no relationship between the messages sent to different clients.

You may choose to either send a byte array directly, or you can use the NetcodeSerializer and NetcodeDeserializer classes to encode more complex data.

This requires that the destination be connected. Otherwise it will return false.

Parameters
dstThe identifier of the client to send to
dataThe byte array to send.
Returns
true if the message was (apparently) sent

◆ setCapacity()

void cugl::netcode::WebSocketServer::setCapacity ( size_t  capacity)

Sets the message buffer capacity.

It is possible for this connection to receive several messages over the network before it has a chance to all receive. This buffer stores those messages to be read later. The capacity indicates the number of messages that can be stored.

Note that this is NOT the same as the capacity of a single message. That value was set as part of the initial WebSocketConfig.

Parameters
capacityThe new message buffer capacity.

◆ setDebug()

void cugl::netcode::WebSocketServer::setDebug ( bool  flag)

Toggles the debugging status of this connection.

If debugging is active, connections will be quite verbose

Parameters
flagWhether to activate debugging

◆ start()

void cugl::netcode::WebSocketServer::start ( )

Starts this websocket server, allowing it to receive incoming connections.

The server start is instantaneous. It is not like a WebSocket or NetcodeConnection where we have to wait for a negotitation to complete.

Calling this method on an active websocket server does nothing. However, it is possible to use this method to restart a server that previously was shutdown by stop.

◆ stop()

void cugl::netcode::WebSocketServer::stop ( )

Stops this websocket server, closing all connections.

Shutdown of a websocket server is immediate, and all connections are closed. However, it is possible to restart the server (with no initial connections) using start.


The documentation for this class was generated from the following file: