C3/Src/Core/GateRelay.h

176 lines
9.4 KiB
C++

#pragma once
#include "Relay.h"
#include "Common/MWR/C3/Internals/BackendCommons.h"
#include "Common/MWR/Sockets/Sockets.hpp"
#include "Common/json/json.hpp"
namespace MWR::C3::Core
{
// Forward declarations.
struct Profiler;
struct ConnectorBridge;
/// Relay class specialization that implements a "server" Relay.
struct GateRelay : Relay, ProceduresG2X::RequestHandler
{
// Friendships.
friend struct Profiler;
/// Factory method.
/// @param callbackOnLog callback fired whenever a new Log entry is being added.
/// @param interfaceFactory reference to interface factory.
/// @param apiBridgeIp IP address to set up API bridge on.
/// @param apiBridgePort port to set up API bridge on.
/// @param signatures a pair of signature keys used to authenticate as Network's Gateway and decrypt authenticated messages from Nodes.
/// @param broadcastKey Network's symmetric key.
/// @param buildId Build identifier.
/// @param snapshotPath path to json file with current state of network. Used in case of gateway restart.
/// @param agentId Agent identifier.
/// @param name optional name provided for gateway.
static std::shared_ptr<GateRelay> CreateAndRun(LoggerCallback callbackOnLog, InterfaceFactory& interfaceFactory, std::string_view apiBridgeIp,
std::uint16_t apiBrigdePort, MWR::Crypto::SignatureKeys const& signatures, MWR::Crypto::SymmetricKey const& broadcastKey, MWR::C3::BuildId buildId, std::filesystem::path snapshotPath,
MWR::C3::AgentId agentId = MWR::C3::AgentId::GenerateRandom(), std::string name = "");
/// Turns on specified Connector.
/// @param connectorNameHash hash value of Connector's name.
/// @param commandLine buffer containing Connector's construction parameters.
/// @throws std::runtime_error if couldn't find factory for specified Connector name hash or if factory was unable to process provided command-line. Throws std::invalid_argument if specified Connector is already turned on.
virtual void TurnOnConnector(HashT connectorNameHash, ByteView commandLine);
/// Turns off specified Connector.
/// @param connectorNameHash hash value of Connector's name.
/// @throw std::invalid_argument on an attempt of turning off a non-existent Connector.
virtual void TurnOffConnector(HashT connectorNameHash);
/// Gets Connector if it's turned on.
/// @param connectorNameHash hash value of Connector's name.
/// @return Connector pointer if found or null.
std::shared_ptr<MWR::C3::Core::ConnectorBridge> GetConnector(HashT connectorNameHash);
/// Called whenever an attached Binder Connector wants to send a Command to its Peripheral Binder.
/// @param command full Command with arguments.
/// @param routeId address to peripheral.
virtual void PostCommandToPeripheral(ByteView command, RouteId routeId);
protected:
/// Protected ctor.
/// @param callbackOnLog callback fired whenever a new Log entry is being added.
/// @param interfaceFactory reference to interface factory.
/// @param abiBridgeIp IP address to set up API bridge on.
/// @param apiBridgePort port to set up API bridge on.
/// @param signatures a pair of signature keys used to authenticate as Network's Gateway and decrypt authenticated messages from Nodes.
/// @param broadcastKey Network's symmetric key.
/// @param buildId Build identifier.
/// @param snapshotPath path to json file with current state of network. Used in case of gateway restart.
/// @param agentId Agent identifier.
GateRelay(LoggerCallback callbackOnLog, InterfaceFactory& interfaceFactory, std::string_view abiBridgeIp, std::uint16_t apiBrigdePort,
MWR::Crypto::SignatureKeys const& signatures, MWR::Crypto::SymmetricKey const& broadcastKey, MWR::C3::BuildId buildId, std::filesystem::path snapshotPath, MWR::C3::AgentId agentId = MWR::C3::AgentId::GenerateRandom());
/// Close Gateway.
void Close() override;
/// Add a new Device.
/// @param iid preferred Identifier.
/// @param DeviceNameHash hash value of Device's name.
/// @param isNegotiationChannel true if channel will support negotiation procedure.
/// @param commandLine buffer containing Device's construction parameters.
/// @param negotiationClient true if channel will support negotiation procedure, and should start it.
/// @return newly created Device.
/// @throws std::runtime_error if couldn't find factory for specified Device name hash or other exceptions if factory was unable to process provided command-line.
std::shared_ptr<DeviceBridge> CreateAndAttachDevice(DeviceId iid, HashT deviceNameHash, bool isNegotiationChannel, ByteView commandLine, bool negotiationClient = false) override;
/// Checks whether particular Agent is banned.
/// @param agentId ID of the Agent to check.
bool IsAgentBanned(AgentId agentId) override;
/// Fired when a S2G protocol packet arrives.
/// @param packet0 a buffer that contains whole packet.
/// @param sender a Channel that provided the packet.
void OnProtocolS2G(ByteView packet0, std::shared_ptr<DeviceBridge> sender) override;
/// Fired when a G2A protocol packet arrives.
/// @param packet0 a buffer that contains whole packet.
/// @param sender a Channel that provided the packet.
void OnProtocolG2A(ByteView packet0, std::shared_ptr<DeviceBridge> sender) override;
/// Fired when a G2R protocol packet arrives.
/// @param packet0 a buffer that contains whole packet.
/// @param sender a Channel that provided the packet.
void OnProtocolG2R(ByteView packet0, std::shared_ptr<DeviceBridge> sender) override;
/// Called whenever an attached Binder Peripheral wants to send a Command to its Connector Binder.
/// @param command full Command with arguments.
/// @param senderPeripheral Interface that is sending the Command.
void PostCommandToConnector(ByteView command, std::shared_ptr<DeviceBridge> senderPeripheral) override;
/// Handler fired when a N2N::InitializeRoute Procedure Query arrives.
/// @param query object representing the Query.
void On(ProceduresN2N::InitializeRouteQuery&& query) override;
/// Handler fired when a S2G::InitializeRoute Procedure Query arrives.
/// @param query object representing the Query.
void On(ProceduresS2G::InitializeRouteQuery&& query) override;
/// Handler fired when a N2N::ChannelIdExchangeStep1 Procedure Query arrives.
/// Gateway opens a new channel and sends parameters to relay.
/// @param query object representing the Query.
void On(ProceduresN2N::ChannelIdExchangeStep1) override;
/// Handler fired when a N2N::ChannelIdExchangeStep Procedure Query arrives.
/// @param query object representing the Query.
/// @emarks Gateway should never receive the second step message of channel Id negotiation.
void On(ProceduresN2N::ChannelIdExchangeStep2) override;
/// Handler fired when a S2G::AddDeviceResponse Procedure Query arrives.
/// @param query object representing the Query.
void On(ProceduresS2G::AddDeviceResponse response) override;
/// Handler fired when a S2G::DeliverToBinder Procedure Query arrives.
/// @param query object representing the Query.
void On(ProceduresS2G::DeliverToBinder query) override;
/// Handler fired when a S2G::NewNegotiatedChannelNotification Procedure Query arrives.
/// @param query object representing the Query.
void On(ProceduresS2G::NewNegotiatedChannelNotification query) override;
/// Handler fired when a S2G::Notification Procedure Query arrives.
/// @param query object representing the Query.
/// @remarks Current implementation supports only timestamp. Notification can be extended to send variety of data about relay state.
void On(ProceduresS2G::Notification query) override;
/// Detaches an Device. This operation leads to (delayed) destruction of the Device.
/// @param iidOfDeviceToDetach ID of the Device to detach.
/// @throw std::invalid_argument on an attempt of removal of a non-existent Device.
void DetachDevice(DeviceId const& iidOfDeviceToDetach) override;
/// Operation removing every interface (Connectors and Devices) from GateRelay.
/// Interfaces are not guaranteed to be closed after this function returns.
/// Threads associated with interfaces are scheduled to end, but must end current tasks.
void CloseDevicesAndConnectors();
/// Removes routes and closes interfaces @see CloseDevicesAndConnectors().
void Reset();
private:
/// Run API bridge
/// @param apiBridgeIp IP address to set up API bridge on.
/// @param apiBridgePort port to set up API bridge on.
void RunApiBrige(std::string_view apiBrigdeIp, std::uint16_t apiBrigdePort) noexcept;
/// Called when new message from Controller is received.
/// Unpacks and schedules actions from message.
nlohmann::json HandleMessage(nlohmann::json const& message);
SafeSmartPointerContainer<std::shared_ptr<ConnectorBridge>> m_Connectors; ///< Container for Connectors that are currently turned on.
Crypto::PublicKey m_AuthenticationKey; ///< Gateway's pubic key. Used to decrypt authenticated messages.
Crypto::PrivateSignature m_Signature; ///< Used to authenticate as Network's Gateway.
Crypto::SessionKeys m_SessionKeys; ///< Used for communication with controller.
MWR::InitializeSockets m_InitializeSockets; ///< Sockets initializer object used by API bridge.
bool m_IsAlive = true; ///< Equals false if Controller sent the exit Command.
std::shared_ptr<Profiler> m_Profiler; ///< Virtual shape of the network.
};
}