You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
o3de/Code/CryEngine/CryCommon/IRemoteCommand.h

764 lines
20 KiB
C++

/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
// Description : Service network interface
#ifndef CRYINCLUDE_CRYCOMMON_IREMOTECOMMAND_H
#define CRYINCLUDE_CRYCOMMON_IREMOTECOMMAND_H
#pragma once
#include <CryString.h>
#include <BaseTypes.h>
//-----------------------------------------------------------------------------
// Helpers for writing/reading command data stream from network message packets.
// Those interfaces automatically handle byteswapping for big endian systems.
// The native format for data inside the messages is little endian.
//-----------------------------------------------------------------------------
/// Write stream interface
struct IDataWriteStream
{
public:
virtual ~IDataWriteStream() {};
public:
// Virtualized write method for general data buffer
virtual void Write(const void* pData, const uint32 size) = 0;
// Virtualized write method for types with size 8 (support byteswapping, a little bit faster than general case)
virtual void Write8(const void* pData) = 0;
// Virtualized write method for types with size 4 (support byteswapping, a little bit faster than general case)
virtual void Write4(const void* pData) = 0;
// Virtualized write method for types with size 2 (support byteswapping, a little bit faster than general case)
virtual void Write2(const void* pData) = 0;
// Virtualized write method for types with size 1 (a little bit faster than general case)
virtual void Write1(const void* pData) = 0;
// Get number of bytes written
virtual const uint32 GetSize() const = 0;
// Convert to service network message
virtual struct IServiceNetworkMessage* BuildMessage() const = 0;
// Save the data from this writer stream to the provided buffer
virtual void CopyToBuffer(void* pData) const = 0;
// Destroy object (if dynamically created)
virtual void Delete() = 0;
public:
IDataWriteStream& operator<<(const uint8& val)
{
Write1(&val);
return *this;
}
IDataWriteStream& operator<<(const uint16& val)
{
Write2(&val);
return *this;
}
IDataWriteStream& operator<<(const uint32& val)
{
Write4(&val);
return *this;
}
IDataWriteStream& operator<<(const uint64& val)
{
Write8(&val);
return *this;
}
IDataWriteStream& operator<<(const int8& val)
{
Write1(&val);
return *this;
}
IDataWriteStream& operator<<(const int16& val)
{
Write2(&val);
return *this;
}
IDataWriteStream& operator<<(const int32& val)
{
Write4(&val);
return *this;
}
IDataWriteStream& operator<<(const int64& val)
{
Write8(&val);
return *this;
}
IDataWriteStream& operator<<(const float& val)
{
Write4(&val);
return *this;
}
// Bool is saved by writing an 8 bit value to make it portable
IDataWriteStream& operator<<(const bool& val)
{
const uint8 uVal = val ? 1 : 0;
Write1(&uVal);
return *this;
}
public:
// Write C string to stream
void WriteString(const char* str);
// Write string to stream
void WriteString(const string& str);
// Write int8 value to stream
void WriteInt8(const int8 val)
{
Write1(&val);
}
// Write int16 value to stream
void WriteInt16(const int16 val)
{
Write2(&val);
}
// Write int32 value to stream
void WriteInt32(const int32 val)
{
Write4(&val);
}
// Write int64 value to stream
void WriteInt64(const int64 val)
{
Write8(&val);
}
// Write uint8 value to stream
void WriteUint8(const uint8 val)
{
Write1(&val);
}
// Write uint16 value to stream
void WriteUint16(const uint16 val)
{
Write2(&val);
}
// Write uint32 value to stream
void WriteUint32(const uint32 val)
{
Write4(&val);
}
// Write uint64 value to stream
void WriteUint64(const uint64 val)
{
Write8(&val);
}
// Write float value to stream
void WriteFloat(const float val)
{
Write4(&val);
}
};
//-----------------------------------------------------------------------------
/// Read stream interface
/// This interface should support endianess swapping
struct IDataReadStream
{
public:
virtual ~IDataReadStream() {};
public:
// Destroy object (if dynamically created)
virtual void Delete() = 0;
// Skip given amount of data without reading it
virtual void Skip(const uint32 size) = 0;
// Virtualized read method (for general buffers)
virtual void Read(void* pData, const uint32 size) = 0;
// Virtualized read method for types with size 8 (a little bit faster than general method, supports byte swapping for BE systems)
virtual void Read8(void* pData) = 0;
// Virtualized read method for types with size 4 (a little bit faster than general method, supports byte swapping for BE systems)
virtual void Read4(void* pData) = 0;
// Virtualized read method for types with size 2 (a little bit faster than general method, supports byte swapping for BE systems)
virtual void Read2(void* pData) = 0;
// Virtualized read method for types with size 1 (a little bit faster than general method, supports byte swapping for BE systems)
virtual void Read1(void* pData) = 0;
// Optimization case - get direct pointer to the underlying buffer
virtual const void* GetPointer() = 0;
public:
IDataReadStream& operator<<(uint8& val)
{
Read1(&val);
return *this;
}
IDataReadStream& operator<<(uint16& val)
{
Read2(&val);
return *this;
}
IDataReadStream& operator<<(uint32& val)
{
Read4(&val);
return *this;
}
IDataReadStream& operator<<(uint64& val)
{
Read8(&val);
return *this;
}
IDataReadStream& operator<<(int8& val)
{
Read1(&val);
return *this;
}
IDataReadStream& operator<<(int16& val)
{
Read2(&val);
return *this;
}
IDataReadStream& operator<<(int32& val)
{
Read4(&val);
return *this;
}
IDataReadStream& operator<<(int64& val)
{
Read8(&val);
return *this;
}
IDataReadStream& operator<<(float& val)
{
Read4(&val);
return *this;
}
// Bool is saved by writing an 8 bit value to make it portable
IDataReadStream& operator<<(bool& val)
{
uint8 uVal = 0;
Read1(&uVal);
val = (uVal != 0);
return *this;
}
public:
// Read string from stream
string ReadString();
// Skip string data in a stream without loading the data
void SkipString();
// Read int8 from stream
int8 ReadInt8()
{
int8 val = 0;
Read1(&val);
return val;
}
// Read int16 from stream
int16 ReadInt16()
{
int16 val = 0;
Read2(&val);
return val;
}
// Read int32 from stream
int32 ReadInt32()
{
int32 val = 0;
Read4(&val);
return val;
}
// Read int64 from stream
int64 ReadInt64()
{
int64 val = 0;
Read8(&val);
return val;
}
// Read uint8 from stream
uint8 ReadUint8()
{
uint8 val = 0;
Read1(&val);
return val;
}
// Read uint16 from stream
uint16 ReadUint16()
{
uint16 val = 0;
Read2(&val);
return val;
}
// Read uint32 from stream
uint32 ReadUint32()
{
uint32 val = 0;
Read4(&val);
return val;
}
// Read int64 from stream
uint64 ReadUint64()
{
uint64 val = 0;
Read8(&val);
return val;
}
// Read float from stream
float ReadFloat()
{
float val = 0.0f;
Read4(&val);
return val;
}
};
//-----------------------------------------------------------------------------
/// Remote command class info (simple RTTI)
struct IRemoteCommandClass
{
public:
virtual ~IRemoteCommandClass() {};
// Get class name
virtual const char* GetName() const = 0;
// Create command instance
virtual struct IRemoteCommand* CreateObject() = 0;
};
/// Remote command interface
struct IRemoteCommand
{
protected:
virtual ~IRemoteCommand() {};
public:
// Get command class
virtual IRemoteCommandClass* GetClass() const = 0;
// Save to data stream
virtual void SaveToStream(struct IDataWriteStream& writeStream) const = 0;
// Load from data stream
virtual void LoadFromStream(struct IDataReadStream& readStream) = 0;
// Execute (remote call) = 0;
virtual void Execute() = 0;
// Delete the command object (can be allocated from different heap)
virtual void Delete() = 0;
};
//-----------------------------------------------------------------------------
// This is a implementation of a synchronous listener (limited to the engine tick rate)
// that processes and responds to the raw messages received from clients.
struct IRemoteCommandListenerSync
{
public:
virtual ~IRemoteCommandListenerSync() {};
// Process a raw message and optionally provide an answer to the request, return true if you have processed the message.
// Messages is accessible via the data reader. Response can be written to a data writer.
virtual bool OnRawMessageSync(const class ServiceNetworkAddress& remoteAddress, struct IDataReadStream& msg, struct IDataWriteStream& response) = 0;
};
//-----------------------------------------------------------------------------
// This is a implementation of a asynchronous listener (called from network thread)
// that processes and responds to the raw messages received from clients.
struct IRemoteCommandListenerAsync
{
public:
virtual ~IRemoteCommandListenerAsync() {};
// Process a raw message and optionally provide an answer to the request, return true if you have processed the message.
// Messages is accessible via the data reader. Response can be written to a data writer.
virtual bool OnRawMessageAsync(const class ServiceNetworkAddress& remoteAddress, struct IDataReadStream& msg, struct IDataWriteStream& response) = 0;
};
//-----------------------------------------------------------------------------
/// Remote command server
struct IRemoteCommandServer
{
protected:
virtual ~IRemoteCommandServer() {};
public:
// Execute all of the received pending commands
// This should be called from a safe place (main thread)
virtual void FlushCommandQueue() = 0;
// Suppress command execution
virtual void SuppressCommands() = 0;
// Resume command execution
virtual void ResumeCommands() = 0;
// Register/Unregister synchronous message listener (limited to tick rate)
virtual void RegisterSyncMessageListener(IRemoteCommandListenerSync* pListener) = 0;
virtual void UnregisterSyncMessageListener(IRemoteCommandListenerSync* pListener) = 0;
// Register/Unregister asynchronous message listener (called from network thread)
virtual void RegisterAsyncMessageListener(IRemoteCommandListenerAsync* pListener) = 0;
virtual void UnregisterAsyncMessageListener(IRemoteCommandListenerAsync* pListener) = 0;
// Broadcast a message to all connected clients
virtual void Broadcast(IServiceNetworkMessage* pMessage) = 0;
// Do we have any clients connected ?
virtual bool HasConnectedClients() const = 0;
// Delete the client
virtual void Delete() = 0;
};
//-----------------------------------------------------------------------------
/// Connection to remote command server
struct IRemoteCommandConnection
{
protected:
virtual ~IRemoteCommandConnection() {};
public:
// Are we connected ?
// This returns false when the underlying network connection has failed (sockets error).
// Also, this returns false if the remote connection was closed by remote peer.
virtual bool IsAlive() const = 0;
// Get address of remote command server
// This returns the full address of the endpoint (with valid port)
virtual const ServiceNetworkAddress& GetRemoteAddress() const = 0;
// Send raw message to the other side of this connection.
// Raw messages are not buffer and are sent right away,
// they also have precedence over internal command traffic.
// The idea is that you need some kind of bidirectional signaling
// channel to extend the rather one-directional nature of commands.
// Returns true if message was added to the send queue.
virtual bool SendRawMessage(IServiceNetworkMessage* pMessage) = 0;
// See if there's a raw message waiting for us and if it is, get it
// Be aware that messages are reference counted.
virtual IServiceNetworkMessage* ReceiveRawMessage() = 0;
// Close connection
// - pending commands are not sent
// - pending raw messages are sent or not (depending on the flag)
virtual void Close(bool bFlushQueueBeforeClosing = false) = 0;
// Add internal reference to object (Refcounting interface)
virtual void AddRef() = 0;
// Release internal reference to object (Refcounting interface)
virtual void Release() = 0;
};
//-----------------------------------------------------------------------------
/// Remote command client
struct IRemoteCommandClient
{
protected:
virtual ~IRemoteCommandClient() {};
public:
// Connect to remote server, returns true on success, false on failure
virtual IRemoteCommandConnection* ConnectToServer(const class ServiceNetworkAddress& serverAddress) = 0;
// Schedule command to be executed on the all of the remote servers
virtual bool Schedule(const IRemoteCommand& command) = 0;
// Delete the client object
virtual void Delete() = 0;
};
//-----------------------------------------------------------------------------
/// Remote command manager
struct IRemoteCommandManager
{
public:
virtual ~IRemoteCommandManager() {};
// Set debug message verbose level
virtual void SetVerbosityLevel(const uint32 level) = 0;
// Create local server for executing remote commands on given local port
virtual IRemoteCommandServer* CreateServer(uint16 localPort) = 0;
// Create client interface for executing remote commands on remote servers
virtual IRemoteCommandClient* CreateClient() = 0;
// Register command class (will be accessible by both clients and server)
virtual void RegisterCommandClass(IRemoteCommandClass& commandClass) = 0;
};
//-----------------------------------------------------------------------------
/// Class RTTI wrapper for remote command classes
template< typename T >
class CRemoteCommandClass
: public IRemoteCommandClass
{
private:
const char* m_szName;
public:
CRemoteCommandClass(const char* szName)
: m_szName(szName)
{}
virtual const char* GetName() const
{
return m_szName;
}
virtual struct IRemoteCommand* CreateObject()
{
return new T();
}
};
#define DECLARE_REMOTE_COMMAND(x) \
public: static IRemoteCommandClass& GetStaticClass() { \
static IRemoteCommandClass* theClass = new CRemoteCommandClass<x>(#x); return *theClass; } \
public: virtual IRemoteCommandClass* GetClass() const { return &GetStaticClass(); } \
public: virtual void Delete() { delete this; } \
public: virtual void SaveToStream(IDataWriteStream & writeStream) const { const_cast<x*>(this)->Serialize<IDataWriteStream>(writeStream); } \
public: virtual void LoadFromStream(IDataReadStream & readStream) { Serialize<IDataReadStream>(readStream); }
//-----------------------------------------------------------------------------
/// CryString serialization helper (read)
inline IDataReadStream& operator<<(IDataReadStream& stream, string& outString)
{
const uint32 kMaxTempString = 256;
// read length
uint32 length = 0;
stream << length;
// load string
if (length > 0)
{
if (length < kMaxTempString)
{
// load the string into temporary buffer
char temp[kMaxTempString];
stream.Read(&temp, length);
temp[length] = 0;
// set the string with new value
outString = temp;
}
else
{
// allocate temporary memory and load the string
std::vector<char> temp;
temp.resize(length + 1, 0);
stream.Read(&temp[0], length);
// set the string with new value
outString = &temp[0];
}
}
else
{
// empty string
outString.clear();
}
return stream;
}
/// CryString serialization helper (write)
inline IDataWriteStream& operator<<(IDataWriteStream& stream, const string& str)
{
// write length
const uint32 length = static_cast<uint32>(str.length());
stream << length;
// write string data
if (length > 0)
{
stream.Write(str.c_str(), length);
}
return stream;
}
//------------------------------------------------------------------------
/// Vector serialization helper (reading)
template< class T >
IDataReadStream& operator<<(IDataReadStream& ar, std::vector<T>& outVector)
{
// Load item count
uint32 count = 0;
ar << count;
// Adapt the vector size (exact fit)
outVector.resize(count);
// Load items
for (uint32 i = 0; i < count; ++i)
{
ar << outVector[i];
}
return ar;
}
/// Vector serialization helper (writing)
template< class T >
IDataWriteStream& operator<<(IDataWriteStream& ar, const std::vector<T>& vec)
{
// Save item count
const uint32 count = vec.size();
ar << count;
// Save items
for (uint32 i = 0; i < count; ++i)
{
ar << const_cast<T&>(vec[i]);
}
return ar;
}
//------------------------------------------------------------------------
inline void IDataWriteStream::WriteString(const char* str)
{
string tempString(str);
*this << tempString;
}
inline void IDataWriteStream::WriteString(const string& str)
{
*this << str;
}
inline string IDataReadStream::ReadString()
{
string ret;
*this << ret;
return ret;
}
inline void IDataReadStream::SkipString()
{
// read length
uint32 length = 0;
*this << length;
Skip(length);
}
//------------------------------------------------------------------------
// Helper class for using the data reader and writer classes
// The only major differce betwen auto_ptr is that we call Delete() instead of operator delete
template<class T>
class TAutoDelete
{
public:
T* m_ptr;
public:
TAutoDelete(T* ptr)
: m_ptr(ptr)
{
}
~TAutoDelete()
{
if (NULL != m_ptr)
{
m_ptr->Delete();
m_ptr = NULL;
}
}
operator bool()
{
return (NULL != m_ptr);
}
operator T& ()
{
return *m_ptr;
}
T* operator->()
{
return m_ptr;
}
private:
TAutoDelete(const TAutoDelete& other)
: m_ptr(NULL){};
TAutoDelete& operator=(const TAutoDelete& other) { return *this; }
};
//------------------------------------------------------------------------
#endif // CRYINCLUDE_CRYCOMMON_IREMOTECOMMAND_H