diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index d6e82a3889..f7953cdf41 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -33,6 +33,7 @@ #include #include +#include #include #include @@ -349,11 +350,24 @@ void AudioMixer::readPendingDatagrams() { } } +void AudioMixer::sendStatsPacket() { + static QJsonObject statsObject; + statsObject["trailing_sleep"] = _trailingSleepRatio; + statsObject["min_audability_threshold"] = _minAudibilityThreshold; + + NodeList::getInstance()->sendStatsToDomainServer(statsObject); +} + void AudioMixer::run() { commonInit(AUDIO_MIXER_LOGGING_TARGET_NAME, NodeType::AudioMixer); NodeList* nodeList = NodeList::getInstance(); + + // send a stats packet every 1 second + QTimer* statsTimer = new QTimer(this); + connect(statsTimer, SIGNAL(timeout()), this, SLOT(sendStatsPacket())); + statsTimer->start(1000); nodeList->addNodeTypeToInterestSet(NodeType::Agent); diff --git a/assignment-client/src/audio/AudioMixer.h b/assignment-client/src/audio/AudioMixer.h index 9d731a5c9c..0f88701303 100644 --- a/assignment-client/src/audio/AudioMixer.h +++ b/assignment-client/src/audio/AudioMixer.h @@ -28,6 +28,8 @@ public slots: void run(); void readPendingDatagrams(); + + void sendStatsPacket(); private: /// adds one buffer to the mix for a listening node void addBufferToMixForListeningNodeWithBuffer(PositionalAudioRingBuffer* bufferToAdd, diff --git a/domain-server/resources/web/js/tables.js b/domain-server/resources/web/js/tables.js index d0855d7967..e32f78a63e 100644 --- a/domain-server/resources/web/js/tables.js +++ b/domain-server/resources/web/js/tables.js @@ -7,7 +7,7 @@ $(document).ready(function(){ $.each(json.nodes, function (uuid, data) { nodesTableBody += ""; nodesTableBody += "" + data.type + ""; - nodesTableBody += "" + uuid + ""; + nodesTableBody += "" + uuid + ""; nodesTableBody += "" + (data.pool ? data.pool : "") + ""; nodesTableBody += "" + data.public.ip + ":" + data.public.port + ""; nodesTableBody += "" + data.local.ip + ":" + data.local.port + ""; @@ -42,7 +42,7 @@ $(document).ready(function(){ $(document.body).on('click', '.glyphicon-remove', function(){ // fire off a delete for this node $.ajax({ - url: "/node/" + $(this).data('uuid'), + url: "/nodes/" + $(this).data('uuid'), type: 'DELETE', success: function(result) { console.log("Succesful request to delete node."); diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 216d249858..1b867501d2 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -603,6 +603,11 @@ void DomainServer::readAvailableDatagrams() { if (noisyMessage) { lastNoisyMessage = timeNow; } + } else if (requestType == PacketTypeNodeJsonStats) { + SharedNodePointer matchingNode = nodeList->sendingNodeForPacket(receivedPacket); + if (matchingNode) { + reinterpret_cast(matchingNode->getLinkedData())->parseJSONStatsPacket(receivedPacket); + } } } } @@ -650,7 +655,7 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QString& const QString JSON_MIME_TYPE = "application/json"; const QString URI_ASSIGNMENT = "/assignment"; - const QString URI_NODE = "/node"; + const QString URI_NODES = "/nodes"; if (connection->requestOperation() == QNetworkAccessManager::GetOperation) { if (path == "/assignments.json") { @@ -697,7 +702,7 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QString& // we've processed this request return true; - } else if (path == "/nodes.json") { + } else if (path == QString("%1.json").arg(URI_NODES)) { // setup the JSON QJsonObject rootJSON; QJsonObject nodesJSON; @@ -718,14 +723,36 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QString& // send the response connection->respond(HTTPConnection::StatusCode200, nodesDocument.toJson(), qPrintable(JSON_MIME_TYPE)); + + return true; + } else { + const QString NODE_REGEX_STRING = + QString("\\%1\\/([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\\/?$").arg(URI_NODES); + QRegExp nodeShowRegex(NODE_REGEX_STRING); + + if (nodeShowRegex.indexIn(path) != -1) { + QUuid matchingUUID = QUuid(nodeShowRegex.cap(1)); + + // see if we have a node that matches this ID + SharedNodePointer matchingNode = NodeList::getInstance()->nodeWithUUID(matchingUUID); + if (matchingNode) { + // create a QJsonDocument with the stats QJsonObject + QJsonDocument statsDocument(reinterpret_cast(matchingNode->getLinkedData()) + ->getStatsJSONObject()); + + // send the resposne + connection->respond(HTTPConnection::StatusCode200, statsDocument.toJson(), qPrintable(JSON_MIME_TYPE)); + + // tell the caller we processed the request + return true; + } + } } } else if (connection->requestOperation() == QNetworkAccessManager::PostOperation) { if (path == URI_ASSIGNMENT) { // this is a script upload - ask the HTTPConnection to parse the form data QList formData = connection->parseFormData(); - - // check how many instances of this assignment the user wants by checking the ASSIGNMENT-INSTANCES header const QString ASSIGNMENT_INSTANCES_HEADER = "ASSIGNMENT-INSTANCES"; @@ -765,13 +792,15 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QString& // respond with a 200 code for successful upload connection->respond(HTTPConnection::StatusCode200); + + return true; } } else if (connection->requestOperation() == QNetworkAccessManager::DeleteOperation) { - if (path.startsWith(URI_NODE)) { + if (path.startsWith(URI_NODES)) { // this is a request to DELETE a node by UUID // pull the UUID from the url - QUuid deleteUUID = QUuid(path.mid(URI_NODE.size() + sizeof('/'))); + QUuid deleteUUID = QUuid(path.mid(URI_NODES.size() + sizeof('/'))); if (!deleteUUID.isNull()) { SharedNodePointer nodeToKill = NodeList::getInstance()->nodeWithUUID(deleteUUID); diff --git a/domain-server/src/DomainServerNodeData.cpp b/domain-server/src/DomainServerNodeData.cpp index 2e32903712..f1e08e3bc4 100644 --- a/domain-server/src/DomainServerNodeData.cpp +++ b/domain-server/src/DomainServerNodeData.cpp @@ -6,11 +6,43 @@ // Copyright (c) 2014 HighFidelity, Inc. All rights reserved. // +#include +#include +#include + +#include + #include "DomainServerNodeData.h" DomainServerNodeData::DomainServerNodeData() : _sessionSecretHash(), - _staticAssignmentUUID() + _staticAssignmentUUID(), + _statsJSONObject() { +} + +void DomainServerNodeData::parseJSONStatsPacket(const QByteArray& statsPacket) { + // push past the packet header + QDataStream packetStream(statsPacket); + packetStream.skipRawData(numBytesForPacketHeader(statsPacket)); + + QVariantMap unpackedVariantMap; + + packetStream >> unpackedVariantMap; + + QJsonObject unpackedStatsJSON = QJsonObject::fromVariantMap(unpackedVariantMap); + _statsJSONObject = mergeJSONStatsFromNewObject(unpackedStatsJSON, _statsJSONObject); +} + +QJsonObject DomainServerNodeData::mergeJSONStatsFromNewObject(const QJsonObject& newObject, QJsonObject destinationObject) { + foreach(const QString& key, newObject.keys()) { + if (newObject[key].isObject() && destinationObject.contains(key)) { + destinationObject[key] = mergeJSONStatsFromNewObject(newObject[key].toObject(), destinationObject[key].toObject()); + } else { + destinationObject[key] = newObject[key]; + } + } + + return destinationObject; } \ No newline at end of file diff --git a/domain-server/src/DomainServerNodeData.h b/domain-server/src/DomainServerNodeData.h index 6686b9120f..20531839f4 100644 --- a/domain-server/src/DomainServerNodeData.h +++ b/domain-server/src/DomainServerNodeData.h @@ -19,13 +19,20 @@ public: DomainServerNodeData(); int parseData(const QByteArray& packet) { return 0; } + const QJsonObject& getStatsJSONObject() const { return _statsJSONObject; } + + void parseJSONStatsPacket(const QByteArray& statsPacket); + void setStaticAssignmentUUID(const QUuid& staticAssignmentUUID) { _staticAssignmentUUID = staticAssignmentUUID; } const QUuid& getStaticAssignmentUUID() const { return _staticAssignmentUUID; } QHash& getSessionSecretHash() { return _sessionSecretHash; } private: + QJsonObject mergeJSONStatsFromNewObject(const QJsonObject& newObject, QJsonObject destinationObject); + QHash _sessionSecretHash; QUuid _staticAssignmentUUID; + QJsonObject _statsJSONObject; }; #endif /* defined(__hifi__DomainServerNodeData__) */ diff --git a/libraries/shared/src/NodeList.cpp b/libraries/shared/src/NodeList.cpp index 2b131ab7ff..fe1466d5d1 100644 --- a/libraries/shared/src/NodeList.cpp +++ b/libraries/shared/src/NodeList.cpp @@ -193,6 +193,15 @@ qint64 NodeList::writeDatagram(const char* data, qint64 size, const SharedNodePo return writeDatagram(QByteArray(data, size), destinationNode, overridenSockAddr); } +qint64 NodeList::sendStatsToDomainServer(const QJsonObject& statsObject) { + QByteArray statsPacket = byteArrayWithPopulatedHeader(PacketTypeNodeJsonStats); + QDataStream statsPacketStream(&statsPacket, QIODevice::Append); + + statsPacketStream << statsObject.toVariantMap(); + + return writeDatagram(statsPacket, _domainInfo.getSockAddr(), _domainInfo.getConnectionSecret()); +} + void NodeList::timePingReply(const QByteArray& packet, const SharedNodePointer& sendingNode) { QDataStream packetStream(packet); packetStream.skipRawData(numBytesForPacketHeader(packet)); diff --git a/libraries/shared/src/NodeList.h b/libraries/shared/src/NodeList.h index d6328a1303..379db70412 100644 --- a/libraries/shared/src/NodeList.h +++ b/libraries/shared/src/NodeList.h @@ -78,6 +78,7 @@ public: const HifiSockAddr& overridenSockAddr = HifiSockAddr()); qint64 writeDatagram(const char* data, qint64 size, const SharedNodePointer& destinationNode, const HifiSockAddr& overridenSockAddr = HifiSockAddr()); + qint64 sendStatsToDomainServer(const QJsonObject& statsObject); void(*linkedDataCreateCallback)(Node *); diff --git a/libraries/shared/src/PacketHeaders.h b/libraries/shared/src/PacketHeaders.h index c6ce6bdd6b..a9bc5d3763 100644 --- a/libraries/shared/src/PacketHeaders.h +++ b/libraries/shared/src/PacketHeaders.h @@ -58,7 +58,8 @@ enum PacketType { PacketTypeAvatarIdentity, PacketTypeAvatarBillboard, PacketTypeDomainConnectRequest, - PacketTypeDomainServerAuthRequest + PacketTypeDomainServerAuthRequest, + PacketTypeNodeJsonStats }; typedef char PacketVersion;