Dale GlassMany improvements:25755f93 years agoHistory
152 lines · 5.9 KB · C++
RawDownload
////  MessagesMixer.cpp//  assignment-client/src/messages////  Created by Brad hefta-Gaub on 11/16/2015.//  Copyright 2015 High Fidelity, Inc.////  Distributed under the Apache License, Version 2.0.//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html// #include "MessagesMixer.h" #include <QtCore/QCoreApplication>#include <QtCore/QJsonObject>#include <QBuffer>#include <LogHandler.h>#include <MessagesClient.h>#include <NodeList.h>#include <udt/PacketHeaders.h> const QString MESSAGES_MIXER_LOGGING_NAME = "messages-mixer";const int MESSAGES_MIXER_RATE_LIMITER_INTERVAL = 1000; // 1 second MessagesMixer::MessagesMixer(ReceivedMessage& message) : ThreadedAssignment(message){    connect(DependencyManager::get<NodeList>().data(), &NodeList::nodeKilled, this, &MessagesMixer::nodeKilled);    auto& packetReceiver = DependencyManager::get<NodeList>()->getPacketReceiver();    packetReceiver.registerListener(PacketType::MessagesData,        PacketReceiver::makeSourcedListenerReference<MessagesMixer>(this, &MessagesMixer::handleMessages));    packetReceiver.registerListener(PacketType::MessagesSubscribe,        PacketReceiver::makeSourcedListenerReference<MessagesMixer>(this, &MessagesMixer::handleMessagesSubscribe));    packetReceiver.registerListener(PacketType::MessagesUnsubscribe,        PacketReceiver::makeSourcedListenerReference<MessagesMixer>(this, &MessagesMixer::handleMessagesUnsubscribe));} void MessagesMixer::nodeKilled(SharedNodePointer killedNode) {    for (auto& channel : _channelSubscribers) {        channel.remove(killedNode->getUUID());    }} void MessagesMixer::handleMessages(QSharedPointer<ReceivedMessage> receivedMessage, SharedNodePointer senderNode) {    QString channel, message;    QByteArray data;    QUuid senderID;    bool isText;    auto senderUUID = senderNode->getUUID();    MessagesClient::decodeMessagesPacket(receivedMessage, channel, isText, message, data, senderID);     auto nodeList = DependencyManager::get<NodeList>();     auto itr = _allSubscribers.find(senderUUID);    if (itr == _allSubscribers.end()) {        _allSubscribers[senderUUID] = 1;    } else if (*itr >= _maxMessagesPerSecond) {        return;    } else {        *itr += 1;    }     nodeList->eachMatchingNode(        [&](const SharedNodePointer& node)->bool {        return node->getActiveSocket() && _channelSubscribers[channel].contains(node->getUUID());    },        [&](const SharedNodePointer& node) {        auto packetList = isText ? MessagesClient::encodeMessagesPacket(channel, message, senderID) :                                   MessagesClient::encodeMessagesDataPacket(channel, data, senderID);        nodeList->sendPacketList(std::move(packetList), *node);    });} void MessagesMixer::handleMessagesSubscribe(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode) {    auto senderUUID = senderNode->getUUID();    QString channel = QString::fromUtf8(message->getMessage());     _channelSubscribers[channel] << senderUUID;} void MessagesMixer::handleMessagesUnsubscribe(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode) {    auto senderUUID = senderNode->getUUID();    QString channel = QString::fromUtf8(message->getMessage());     if (_channelSubscribers.contains(channel)) {        _channelSubscribers[channel].remove(senderUUID);    }} void MessagesMixer::sendStatsPacket() {    QJsonObject statsObject, messagesMixerObject;     // add stats for each listerner    DependencyManager::get<NodeList>()->eachNode([&](const SharedNodePointer& node) {        QJsonObject clientStats;        clientStats[USERNAME_UUID_REPLACEMENT_STATS_KEY] = uuidStringWithoutCurlyBraces(node->getUUID());        clientStats["outbound_kbps"] = node->getOutboundKbps();        clientStats["inbound_kbps"] = node->getInboundKbps();        messagesMixerObject[uuidStringWithoutCurlyBraces(node->getUUID())] = clientStats;    });     statsObject["messages"] = messagesMixerObject;    ThreadedAssignment::addPacketStatsAndSendStatsPacket(statsObject);} void MessagesMixer::run() {    auto nodeList = DependencyManager::get<NodeList>();    nodeList->addSetOfNodeTypesToNodeInterestSet({ NodeType::Agent, NodeType::EntityScriptServer });    DomainHandler& domainHandler = nodeList->getDomainHandler();    connect(&domainHandler, &DomainHandler::settingsReceived, this, &MessagesMixer::domainSettingsRequestComplete);     ThreadedAssignment::commonInit(MESSAGES_MIXER_LOGGING_NAME, NodeType::MessagesMixer);     startMaxMessagesProcessor();} void MessagesMixer::domainSettingsRequestComplete() {    auto nodeList = DependencyManager::get<NodeList>();     // parse the settings to pull out the values we need    parseDomainServerSettings(nodeList->getDomainHandler().getSettingsObject());} void MessagesMixer::parseDomainServerSettings(const QJsonObject& domainSettings) {    commonParseSettingsObject(domainSettings);     const QString MESSAGES_MIXER_SETTINGS_KEY = "messages_mixer";    QJsonObject messagesMixerGroupObject = domainSettings[MESSAGES_MIXER_SETTINGS_KEY].toObject();     const QString NODE_MESSAGES_PER_SECOND_KEY = "max_node_messages_per_second";    QJsonValue maxMessagesPerSecondValue = messagesMixerGroupObject.value(NODE_MESSAGES_PER_SECOND_KEY);    _maxMessagesPerSecond = maxMessagesPerSecondValue.toInt(DEFAULT_NODE_MESSAGES_PER_SECOND);} void MessagesMixer::processMaxMessagesContainer() {    _allSubscribers.clear();} void MessagesMixer::startMaxMessagesProcessor() {    if (_maxMessagesTimer) {        stopMaxMessagesProcessor();    }     _maxMessagesTimer = new QTimer();    connect(_maxMessagesTimer, &QTimer::timeout, this, &MessagesMixer::processMaxMessagesContainer);    _maxMessagesTimer->start(MESSAGES_MIXER_RATE_LIMITER_INTERVAL); // Clear the container every second.} void MessagesMixer::stopMaxMessagesProcessor() {    _maxMessagesTimer->stop();    _maxMessagesTimer->deleteLater();    _maxMessagesTimer = nullptr;}