#include "StdAfx.h" #include "DeviceBridge.h" #include "Relay.h" //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// MWR::C3::Core::DeviceBridge::DeviceBridge(std::shared_ptr&& relay, DeviceId did, HashT typeNameHash, std::shared_ptr&& device, bool isNegotiationChannel, bool isSlave, ByteVector args /*= ByteVector()*/) : m_Relay{ relay } , m_Device{ std::move(device) } , m_Did{ did } , m_TypeNameHash(typeNameHash) , m_IsNegotiationChannel(isNegotiationChannel) , m_IsSlave(isSlave) { if (!isNegotiationChannel) return; auto readView = ByteView{ args }; std::tie(m_InputId, m_OutpuId) = readView.Read(); m_NonNegotiatiedArguments = readView; } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void MWR::C3::Core::DeviceBridge::OnAttach() { GetDevice()->OnAttach(shared_from_this()); } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void MWR::C3::Core::DeviceBridge::Detach() { m_IsAlive = false; } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void MWR::C3::Core::DeviceBridge::OnReceive() { GetDevice()->OnReceive(); } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void MWR::C3::Core::DeviceBridge::PassNetworkPacket(ByteView packet) { if (m_IsNegotiationChannel && !m_IsSlave) // negotiation channel does not support chunking. Just pass packet and leave. return GetRelay()->OnPacketReceived(packet, shared_from_this()); m_QoS.PushReceivedChunk(packet); auto nextPacket = m_QoS.GetNextPacket(); if (!nextPacket.empty()) GetRelay()->OnPacketReceived(nextPacket, shared_from_this()); } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void MWR::C3::Core::DeviceBridge::OnPassNetworkPacket(ByteView packet) { auto lock = std::lock_guard{ m_ProtectWriteInConcurrentThreads }; if (m_IsNegotiationChannel) // negotiation channel does not support chunking. Just pass packet and leave. { auto sent = GetDevice()->OnSendToChannelInternal(packet); if (sent != packet.size()) throw std::runtime_error{OBF("Negotiation channel does not support chunking. Packet size: ") + std::to_string(packet.size()) + OBF(" Channel sent: ") + std::to_string(sent)}; return; } auto oryginalSize = static_cast(packet.size()); auto messageId = m_QoS.GetOutgouingPacketId(); uint32_t chunkId = 0u; while (!packet.empty()) { auto data = ByteVector{}.Write(messageId, chunkId, oryginalSize).Concat(packet); auto sent = GetDevice()->OnSendToChannelInternal(data); if (sent >= QualityOfService::s_MinFrameSize || sent == data.size()) // if this condition were not channel must resend data. { chunkId++; packet.remove_prefix(sent - QualityOfService::s_HeaderSize); } } } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void MWR::C3::Core::DeviceBridge::PostCommandToConnector(ByteView packet) { GetRelay()->PostCommandToConnector(packet, shared_from_this()); } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void MWR::C3::Core::DeviceBridge::OnCommandFromConnector(ByteView command) { auto lock = std::lock_guard{ m_ProtectWriteInConcurrentThreads }; GetDevice()->OnCommandFromConnector(command); } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// MWR::ByteVector MWR::C3::Core::DeviceBridge::RunCommand(ByteView command) { return GetDevice()->OnRunCommand(command); } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// MWR::ByteVector MWR::C3::Core::DeviceBridge::WhoAreYou() { return GetDevice()->OnWhoAmI(); } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void MWR::C3::Core::DeviceBridge::Log(LogMessage const& message) { GetRelay()->Log(message, GetDid()); } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// MWR::C3::DeviceId MWR::C3::Core::DeviceBridge::GetDid() const { return m_Did; } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void MWR::C3::Core::DeviceBridge::StartUpdatingInSeparateThread() { std::thread{ [this, self = shared_from_this()]() { WinTools::StructuredExceptionHandling::SehWrapper([&]() { while (m_IsAlive) try { std::this_thread::sleep_for(GetDevice()->GetUpdateDelay()); OnReceive(); } catch (std::exception const& exception) { Log({ OBF_SEC("std::exception while updating: ") + exception.what(), LogMessage::Severity::Error }); } catch (...) { Log({ OBF_SEC("Unknown exception while updating."), LogMessage::Severity::Error }); } }, [this]() { # if defined _DEBUG Log({ "Signal captured, ending thread execution.", LogMessage::Severity::Error }); # endif }); }}.detach(); } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void MWR::C3::Core::DeviceBridge::SetUpdateDelay(std::chrono::milliseconds minUpdateDelayInMs, std::chrono::milliseconds maxUpdateDelayInMs) { GetDevice()->SetUpdateDelay(minUpdateDelayInMs, maxUpdateDelayInMs); } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void MWR::C3::Core::DeviceBridge::SetUpdateDelay(std::chrono::milliseconds frequencyInMs) { GetDevice()->SetUpdateDelay(frequencyInMs); } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// std::shared_ptr MWR::C3::Core::DeviceBridge::GetDevice() const { return m_Device; } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// std::shared_ptr MWR::C3::Core::DeviceBridge::GetRelay() const { return m_Relay; } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// MWR::HashT MWR::C3::Core::DeviceBridge::GetTypeNameHash() const { return m_TypeNameHash; } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool MWR::C3::Core::DeviceBridge::IsChannel() const { auto device = GetDevice(); return device ? device->IsChannel() : false; } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool MWR::C3::Core::DeviceBridge::IsNegotiationChannel() const { return m_IsNegotiationChannel && IsChannel(); } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void MWR::C3::Core::DeviceBridge::SetErrorStatus(std::string_view errorMessage) { m_Error = errorMessage; } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// std::string MWR::C3::Core::DeviceBridge::GetErrorStatus() { return m_Error; }