Merge branch 'master' into PerformanceUpgrades

dependabot/npm_and_yarn/Src/WebController/UI/websocket-extensions-0.1.4
Pawel Kurowski 2019-09-12 14:25:26 +02:00
commit 89ffafa210
4 changed files with 127 additions and 130 deletions

View File

@ -83,7 +83,6 @@ size_t MWR::C3::Interfaces::Channels::UncShareFile::OnSendToChannel(ByteView dat
}
std::filesystem::rename(tmpFilePath, filePath);
Log({ OBF("OnSend() called for UncShareFile carrying ") + std::to_string(data.size()) + OBF(" bytes"), LogMessage::Severity::DebugInformation });
return data.size();
}
catch (std::exception& exception)

View File

@ -6,7 +6,6 @@
namespace MWR::C3
{
/// Template class handling registration of Interface before main function.
/// @tparam Iface. Interface to be registered.
template <typename Iface, typename AbstractType, HashT clousureConnectorHash = 0>
@ -43,21 +42,7 @@ namespace MWR::C3
template <>
static std::string GetCapability<false>()
{
return R"_(
{
"create":
{
"arguments":
[
{
"type": "binary",
"description": "Blob of data that will be provided to Channel constructor.",
"name": "arguments"
}
]
},
"commands": []
})_";
return "{}";
}
template <>
@ -104,128 +89,131 @@ namespace MWR::C3
constexpr HashT Register<T, T2, u32>::s_InterfaceHash = Hash::Fnv1aType<T>();
#pragma warning( pop )
/// Specialization of Registration mechanism for Channel type Interface.
template <typename Iface>
class Channel : public Register<Iface, AbstractChannel>
namespace Interfaces
{
public:
constexpr static std::chrono::milliseconds s_MinUpdateFrequency = 30ms;
constexpr static std::chrono::milliseconds s_MaxUpdateFrequency = 30ms;
/// Constructor setting default update frequency for channel
Channel()
/// Specialization of Registration mechanism for Channel type Interface.
template <typename Iface>
class Channel : public Register<Iface, AbstractChannel>
{
static_assert(Iface::s_MinUpdateFrequency >= 30ms && Iface::s_MinUpdateFrequency <= Iface::s_MaxUpdateFrequency, "The frequency is set incorrectly");
m_MinUpdateFrequency = Iface::s_MinUpdateFrequency;
m_MaxUpdateFrequency = Iface::s_MaxUpdateFrequency;
}
public:
constexpr static std::chrono::milliseconds s_MinUpdateFrequency = 30ms;
constexpr static std::chrono::milliseconds s_MaxUpdateFrequency = 30ms;
/// Callback that is periodically called for every Device to update itself.
/// This is point where dynamic polymorphisms is replaced by static one with recognition of returned value.
/// Types using Channel CRTP should implement MWR::ByteVector OnReceiveFromChannel(), or std::vector<MWR::ByteVector> OnReceiveFromChannel()
/// @return std::vector<ByteVector> that contains all packets retrieved from Channel.
std::vector<ByteVector> OnReceiveFromChannelInternal() override final
{
static_assert(CanRecive<>::value, "OnReceiveFromChannel is not implemented");
static_assert(std::is_same_v<ReceiveReturnType<Iface>, ByteVector> || std::is_same_v<ReceiveReturnType<Iface>, std::vector<ByteVector>>, "OnReceiveFromChannel should return ByteVector or std::vector<ByteVector>");
return ReceiveWrapper<Iface>();
}
/// Constructor setting default update frequency for channel
Channel()
{
static_assert(Iface::s_MinUpdateFrequency >= 30ms && Iface::s_MinUpdateFrequency <= Iface::s_MaxUpdateFrequency, "The frequency is set incorrectly");
m_MinUpdateFrequency = Iface::s_MinUpdateFrequency;
m_MaxUpdateFrequency = Iface::s_MaxUpdateFrequency;
}
/// Called every time Relay wants to send a packet through this Channel Device.
/// This is point where dynamic polymorphisms is replaced by static one.
/// Types using Channel CRTP should implement size_t OnSendToChannel(ByteView).
/// @param blob buffer containing data to send.
size_t OnSendToChannelInternal(ByteView packet) override final
{
static_assert(CanSend<ByteView>::value, "OnSendToChannel is not implemented");
auto self = static_cast<Iface*>(this);
return self->OnSendToChannel(packet);
}
/// Callback that is periodically called for every Device to update itself.
/// This is point where dynamic polymorphisms is replaced by static one with recognition of returned value.
/// Types using Channel CRTP should implement MWR::ByteVector OnReceiveFromChannel(), or std::vector<MWR::ByteVector> OnReceiveFromChannel()
/// @return std::vector<ByteVector> that contains all packets retrieved from Channel.
std::vector<ByteVector> OnReceiveFromChannelInternal() override final
{
static_assert(CanRecive<>::value, "OnReceiveFromChannel is not implemented");
static_assert(std::is_same_v<ReceiveReturnType<Iface>, ByteVector> || std::is_same_v<ReceiveReturnType<Iface>, std::vector<ByteVector>>, "OnReceiveFromChannel should return ByteVector or std::vector<ByteVector>");
return ReceiveWrapper<Iface>();
}
private:
/// Alias to get result of OnReceiveFromChannel call.
/// Use in form ReceiveReturnType<Iface> to obtain type.
/// Can fail if function is not implemented.
template<class T, class...Ts>
using ReceiveReturnType = decltype(std::declval<T>().OnReceiveFromChannel(std::declval<Ts>()...));
/// Called every time Relay wants to send a packet through this Channel Device.
/// This is point where dynamic polymorphisms is replaced by static one.
/// Types using Channel CRTP should implement size_t OnSendToChannel(ByteView).
/// @param blob buffer containing data to send.
size_t OnSendToChannelInternal(ByteView packet) override final
{
static_assert(CanSend<ByteView>::value, "OnSendToChannel is not implemented");
auto self = static_cast<Iface*>(this);
return self->OnSendToChannel(packet);
}
/// Alias to test if OnReceiveFromChannel is implemented.
/// Use in form CanRecive<Iface>::value to obtain bool value with information.
template<class...Ts>
using CanRecive = MWR::Utils::CanApply<ReceiveReturnType, Iface, Ts...>;
private:
/// Alias to get result of OnReceiveFromChannel call.
/// Use in form ReceiveReturnType<Iface> to obtain type.
/// Can fail if function is not implemented.
template<class T, class...Ts>
using ReceiveReturnType = decltype(std::declval<T>().OnReceiveFromChannel(std::declval<Ts>()...));
/// Alias to get result of OnSendToChannel call.
/// Use in form SendReturnType<Iface, ByteView> to obtain type.
/// Can fail if function is not implemented.
template<class T, class...Ts>
using SendReturnType = decltype(std::declval<T>().OnSendToChannel(std::declval<Ts>()...));
/// Alias to test if OnReceiveFromChannel is implemented.
/// Use in form CanRecive<Iface>::value to obtain bool value with information.
template<class...Ts>
using CanRecive = MWR::Utils::CanApply<ReceiveReturnType, Iface, Ts...>;
/// Alias to test if OnSendToChannel is implemented.
/// Use in form CanSend<Iface>::value to obtain bool value with information.
template<class...Ts>
using CanSend = MWR::Utils::CanApply<SendReturnType, Iface, Ts...>;
/// Alias to get result of OnSendToChannel call.
/// Use in form SendReturnType<Iface, ByteView> to obtain type.
/// Can fail if function is not implemented.
template<class T, class...Ts>
using SendReturnType = decltype(std::declval<T>().OnSendToChannel(std::declval<Ts>()...));
/// Virtual OnSendToChannelInternal cannot be templated.
/// This function will be available for call if OnReceiveFromChannel returns ByteVector.
/// @returns std::vector<ByteVector> one packet pushed on collection if it is not empty..
template <typename T>
std::enable_if_t<std::is_same_v<ReceiveReturnType<T>, ByteVector>, std::vector<ByteVector>> ReceiveWrapper()
{
auto self = static_cast<Iface*>(this);
std::vector<ByteVector> ret;
if (auto packet = self->OnReceiveFromChannel(); !packet.empty())
ret.push_back(std::move(packet));
/// Alias to test if OnSendToChannel is implemented.
/// Use in form CanSend<Iface>::value to obtain bool value with information.
template<class...Ts>
using CanSend = MWR::Utils::CanApply<SendReturnType, Iface, Ts...>;
return ret;
}
/// Virtual OnSendToChannelInternal cannot be templated.
/// This function will be available for call if OnReceiveFromChannel returns ByteVector.
/// @returns std::vector<ByteVector> one packet pushed on collection if it is not empty..
template <typename T>
std::enable_if_t<std::is_same_v<ReceiveReturnType<T>, ByteVector>, std::vector<ByteVector>> ReceiveWrapper()
{
auto self = static_cast<Iface*>(this);
std::vector<ByteVector> ret;
if (auto packet = self->OnReceiveFromChannel(); !packet.empty())
ret.push_back(std::move(packet));
/// Virtual OnSendToChannelInternal cannot be templated.
/// This function will be available for call if OnReceiveFromChannel returns std::vector<ByteVector>.
/// @returns std::vector<ByteVector> many packets that are not empty.
template <typename T>
std::enable_if_t<std::is_same_v<ReceiveReturnType<T>, std::vector<ByteVector>>, std::vector<ByteVector>> ReceiveWrapper()
{
auto self = static_cast<Iface*>(this);
auto ret = self->OnReceiveFromChannel();
static_cast<void>(std::remove_if(ret.begin(), ret.end(), [](auto&& e) { return e.empty(); }));
return ret;
}
};
return ret;
}
/// Virtual OnSendToChannelInternal cannot be templated.
/// This function will be available for call if OnReceiveFromChannel returns std::vector<ByteVector>.
/// @returns std::vector<ByteVector> many packets that are not empty.
template <typename T>
std::enable_if_t<std::is_same_v<ReceiveReturnType<T>, std::vector<ByteVector>>, std::vector<ByteVector>> ReceiveWrapper()
{
auto self = static_cast<Iface*>(this);
auto ret = self->OnReceiveFromChannel();
static_cast<void>(std::remove_if(ret.begin(), ret.end(), [](auto&& e) { return e.empty(); }));
return ret;
}
};
#ifdef C3_IS_GATEWAY
/// Specialization of Registration mechanism for Connector type Interface.
template <typename Iface>
class Connector : public Register<Iface, AbstractConnector>
{
public:
// connector in fact does not need those values. They are here to satisfy template requirements.
constexpr static std::chrono::milliseconds s_MinUpdateFrequency = 0ms;
constexpr static std::chrono::milliseconds s_MaxUpdateFrequency = 0ms;
};
/// Specialization of Registration mechanism for Connector type Interface.
template <typename Iface>
class Connector : public Register<Iface, AbstractConnector>
{
public:
// connector in fact does not need those values. They are here to satisfy template requirements.
constexpr static std::chrono::milliseconds s_MinUpdateFrequency = 0ms;
constexpr static std::chrono::milliseconds s_MaxUpdateFrequency = 0ms;
};
#else
/// Don't register the connectors in node builds
template <typename Iface>
class Connector : public AbstractConnector
{
};
/// Don't register the connectors in node builds
template <typename Iface>
class Connector : public AbstractConnector
{
};
#endif C3_IS_GATEWAY
#pragma warning( push )
#pragma warning( disable : 4307)
/// Specialization of Registration mechanism for Peripheral type Interface.
template <typename Iface, typename Closure>
class Peripheral : public Register<Iface, AbstractPeripheral, Hash::Fnv1aType<Closure>()>
{
public:
constexpr static std::chrono::milliseconds s_MinUpdateFrequency = 30ms;
constexpr static std::chrono::milliseconds s_MaxUpdateFrequency = 30ms;
Peripheral()
/// Specialization of Registration mechanism for Peripheral type Interface.
template <typename Iface, typename Closure>
class Peripheral : public Register<Iface, AbstractPeripheral, Hash::Fnv1aType<Closure>()>
{
static_assert(Iface::s_MinUpdateFrequency >= 30ms && Iface::s_MinUpdateFrequency <= Iface::s_MaxUpdateFrequency, "The frequency is set incorrectly");
m_MinUpdateFrequency = Iface::s_MinUpdateFrequency;
m_MaxUpdateFrequency = Iface::s_MaxUpdateFrequency;
}
};
public:
constexpr static std::chrono::milliseconds s_MinUpdateFrequency = 30ms;
constexpr static std::chrono::milliseconds s_MaxUpdateFrequency = 30ms;
Peripheral()
{
static_assert(Iface::s_MinUpdateFrequency >= 30ms && Iface::s_MinUpdateFrequency <= Iface::s_MaxUpdateFrequency, "The frequency is set incorrectly");
m_MinUpdateFrequency = Iface::s_MinUpdateFrequency;
m_MaxUpdateFrequency = Iface::s_MaxUpdateFrequency;
}
};
#pragma warning( pop )
}
}

View File

@ -23,9 +23,6 @@ std::string MWR::C3::InterfaceFactory::GetCapability()
{
json entry;
entry["type"] = e.first;
if (e.second.m_Capability.empty() || e.second.m_Name.empty())
continue;
entry["name"] = e.second.m_Name;
auto pin = json::parse(e.second.m_Capability);
for (const auto& j : pin.items())

View File

@ -117,7 +117,7 @@ MWR::ByteVector MWR::C3::Core::Profiler::TranslateArguments(json const& argument
if (!argument.is_array())
translate(argument);
else
for (auto subargument : argument)
for (auto const subargument : argument)
translate(subargument);
}
@ -821,6 +821,20 @@ json MWR::C3::Core::Profiler::Gateway::GetCapability()
// Construct the InitialPacket.
json initialPacket = json::parse(gateway->m_InterfaceFactory.GetCapability());
for (auto& interface : initialPacket["channels"])
if (!interface.contains("create"))
interface["create"] = json::parse(R"(
{
"arguments" :
[
{
"type": "binary",
"description": "Blob of data that will be provided to Channel constructor.",
"name": "arguments"
}
]
})");
// Create method in interface is constructor. It must be a relay/gateway command.
// initialPacket is copied to original to prevent iterator invalidation.
// last 256 commands will be reserved for common commands.
@ -829,14 +843,13 @@ json MWR::C3::Core::Profiler::Gateway::GetCapability()
auto idToErase = 0;
std::vector<std::unordered_map<std::string, std::vector<json>>> buffer;
buffer.resize(prefix.size());
for (auto&& e : oryginal[interfaceType])
for (auto&& element : oryginal[interfaceType])
{
try
{
for (auto i = 0u; i < prefix.size(); ++i)
{
auto arguments = e.at("create").at("arguments");
auto arguments = element.at("create").at("arguments");
if (i) // NegotiationChannel command
{
if (arguments.empty() || arguments[0].size() != 2)
@ -846,7 +859,7 @@ json MWR::C3::Core::Profiler::Gateway::GetCapability()
}
for (auto&& relayType : relayTypes)
buffer[i][relayType].push_back(json{ {"name", prefix[i] + e["name"].get<std::string>()}, {"arguments", arguments}, {"id", id} });
buffer[i][relayType].push_back(json{ {"name", prefix[i] + element["name"].get<std::string>()}, {"arguments", arguments}, {"id", id} });
m_CreateCommands.push_back({ id, initialPacket[interfaceType][idToErase]["type"].get<uint32_t>(), isDevice, !!i }); // store command id and hash.
--id;
@ -856,7 +869,7 @@ json MWR::C3::Core::Profiler::Gateway::GetCapability()
initialPacket[interfaceType][idToErase].erase("create");
initialPacket[interfaceType][idToErase]["commands"].push_back(json{ {"name", isDevice ? "Close" : "TurnOff"}, {"id", static_cast<std::underlying_type_t<NodeRelay::Command>>(NodeRelay::Command::Close) }, {"arguments", json::array()} });
if (isDevice)
initialPacket[interfaceType][idToErase]["commands"].push_back(json{ {"name", "UpdateDelayJitter"}, {"description", "Set delay between receiving function calls."}, {"id", static_cast<std::underlying_type_t<NodeRelay::Command>>(NodeRelay::Command::UpdateJitter) },
initialPacket[interfaceType][idToErase]["commands"].push_back(json{ {"name", "Set UpdateDelayJitter"}, {"description", "Set delay between receiving function calls."}, {"id", static_cast<std::underlying_type_t<NodeRelay::Command>>(NodeRelay::Command::UpdateJitter) },
{"arguments", {
{{"type", "float"}, {"name", "Min"}, {"description", "Minimal delay in seconds"}, {"min", 0.03}},
{{"type", "float"}, {"name", "Max"}, {"description", "Maximal delay in seconds. "}, {"min", 0.03}}