From 15ba5f7ab1cc15204b8a17f5aa48c49f9e7acf32 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 29 Jan 2014 13:48:31 -0800 Subject: [PATCH 01/10] correct OctreeServer config parsing --- libraries/octree-server/src/OctreeServer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/octree-server/src/OctreeServer.cpp b/libraries/octree-server/src/OctreeServer.cpp index 73522565f9..6e58a0a987 100644 --- a/libraries/octree-server/src/OctreeServer.cpp +++ b/libraries/octree-server/src/OctreeServer.cpp @@ -433,7 +433,7 @@ void OctreeServer::setArguments(int argc, char** argv) { void OctreeServer::parsePayload() { if (getPayload().size() > 0) { - QString config((const char*) _payload); + QString config(_payload); // Now, parse the config QStringList configList = config.split(" "); From 7d278300647a66805e510dfb20c1498fdf72a6ba Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 29 Jan 2014 14:23:39 -0800 Subject: [PATCH 02/10] domain-server patches while looking for payload/pool errors --- domain-server/src/DomainServer.cpp | 8 ++++---- libraries/shared/src/Assignment.cpp | 8 +------- libraries/shared/src/Assignment.h | 3 +-- 3 files changed, 6 insertions(+), 13 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 6e4a4cdff4..b4ec326d37 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -575,7 +575,7 @@ void DomainServer::prepopulateStaticAssignmentFile() { Assignment voxelServerAssignment(Assignment::CreateCommand, Assignment::VoxelServerType, - (assignmentPool.isEmpty() ? NULL : assignmentPool.toLocal8Bit().constData())); + assignmentPool); voxelServerAssignment.setPayload(config.toUtf8()); @@ -615,8 +615,8 @@ void DomainServer::prepopulateStaticAssignmentFile() { } Assignment particleServerAssignment(Assignment::CreateCommand, - Assignment::ParticleServerType, - (assignmentPool.isEmpty() ? NULL : assignmentPool.toLocal8Bit().constData())); + Assignment::ParticleServerType, + assignmentPool); particleServerAssignment.setPayload(config.toLocal8Bit()); @@ -689,7 +689,7 @@ Assignment* DomainServer::deployableAssignmentForRequest(Assignment& requestAssi bool assignmentTypesMatch = (*assignment)->getType() == requestAssignment.getType(); bool nietherHasPool = (*assignment)->getPool().isEmpty() && requestAssignment.getPool().isEmpty(); bool assignmentPoolsMatch = (*assignment)->getPool() == requestAssignment.getPool(); - + if ((requestIsAllTypes || assignmentTypesMatch) && (nietherHasPool || assignmentPoolsMatch)) { Assignment* deployableAssignment = *assignment; diff --git a/libraries/shared/src/Assignment.cpp b/libraries/shared/src/Assignment.cpp index 2bff4ddcd0..76ee4b04cf 100644 --- a/libraries/shared/src/Assignment.cpp +++ b/libraries/shared/src/Assignment.cpp @@ -14,9 +14,6 @@ #include "Assignment.h" -const char IPv4_ADDRESS_DESIGNATOR = 4; -const char IPv6_ADDRESS_DESIGNATOR = 6; - Assignment::Type Assignment::typeForNodeType(NodeType_t nodeType) { switch (nodeType) { case NodeType::AudioMixer: @@ -95,10 +92,7 @@ Assignment::Assignment(const QByteArray& packet) : } packetStream >> _pool; - - if (!packetStream.atEnd()) { - _payload = packet.mid(packetStream.device()->pos()); - } + packetStream >> _payload; } #ifdef WIN32 diff --git a/libraries/shared/src/Assignment.h b/libraries/shared/src/Assignment.h index 418ea7fe09..fb69271db3 100644 --- a/libraries/shared/src/Assignment.h +++ b/libraries/shared/src/Assignment.h @@ -20,7 +20,6 @@ #include "NodeList.h" const int MAX_PAYLOAD_BYTES = 1024; -const int MAX_ASSIGNMENT_POOL_BYTES = 64 + sizeof('\0'); const QString emptyPool = QString(); @@ -76,7 +75,7 @@ public: Assignment::Location getLocation() const { return _location; } const QByteArray& getPayload() const { return _payload; } - void setPayload(const QByteArray& payload) { _payload = payload; } + void setPayload(const QByteArray& payload) { _payload = payload.left(MAX_PAYLOAD_BYTES); } void setPool(const QString& pool) { _pool = pool; }; const QString& getPool() const { return _pool; } From dbecb96a58b65895249fcfbbdd9d196722a315e7 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 29 Jan 2014 15:08:50 -0800 Subject: [PATCH 03/10] remove assignmentQueueMutex now that DS concurrency is gone --- domain-server/src/DomainServer.cpp | 27 ++++----------------------- domain-server/src/DomainServer.h | 1 - 2 files changed, 4 insertions(+), 24 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index b4ec326d37..a124af4b40 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -38,7 +38,6 @@ const quint16 DOMAIN_SERVER_HTTP_PORT = 8080; DomainServer::DomainServer(int argc, char* argv[]) : QCoreApplication(argc, argv), _HTTPManager(DOMAIN_SERVER_HTTP_PORT, QString("%1/resources/web/").arg(QCoreApplication::applicationDirPath()), this), - _assignmentQueueMutex(), _assignmentQueue(), _staticAssignmentFile(QString("%1/config.ds").arg(QCoreApplication::applicationDirPath())), _staticAssignmentFileData(NULL), @@ -467,9 +466,7 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QString& // add the script assigment to the assignment queue // lock the assignment queue mutex since we're operating on a different thread than DS main - _assignmentQueueMutex.lock(); _assignmentQueue.push_back(scriptAssignment); - _assignmentQueueMutex.unlock(); } } else if (connection->requestOperation() == QNetworkAccessManager::DeleteOperation) { if (path.startsWith(URI_NODE)) { @@ -514,9 +511,7 @@ void DomainServer::addReleasedAssignmentBackToQueue(Assignment* releasedAssignme _staticAssignments[i].resetUUID(); // put this assignment back in the queue so it goes out - _assignmentQueueMutex.lock(); _assignmentQueue.push_back(&_staticAssignments[i]); - _assignmentQueueMutex.unlock(); } else if (_staticAssignments[i].getUUID().isNull()) { // we are at the blank part of the static assignments - break out @@ -646,22 +641,18 @@ Assignment* DomainServer::matchingStaticAssignmentForCheckIn(const QUuid& checkI // pull the UUID passed with the check in if (_hasCompletedRestartHold) { - _assignmentQueueMutex.lock(); - // iterate the assignment queue to check for a match std::deque::iterator assignment = _assignmentQueue.begin(); while (assignment != _assignmentQueue.end()) { if ((*assignment)->getUUID() == checkInUUID) { // return the matched assignment - _assignmentQueueMutex.unlock(); return *assignment; } else { // no match, push deque iterator forwards assignment++; } } - - _assignmentQueueMutex.unlock(); + } else { for (int i = 0; i < MAX_STATIC_ASSIGNMENT_FILE_ASSIGNMENTS; i++) { if (_staticAssignments[i].getUUID() == checkInUUID) { @@ -678,8 +669,6 @@ Assignment* DomainServer::matchingStaticAssignmentForCheckIn(const QUuid& checkI } Assignment* DomainServer::deployableAssignmentForRequest(Assignment& requestAssignment) { - _assignmentQueueMutex.lock(); - // this is an unassigned client talking to us directly for an assignment // go through our queue and see if there are any assignments to give out std::deque::iterator assignment = _assignmentQueue.begin(); @@ -713,22 +702,18 @@ Assignment* DomainServer::deployableAssignmentForRequest(Assignment& requestAssi } // stop looping, we've handed out an assignment - _assignmentQueueMutex.unlock(); return deployableAssignment; } else { // push forward the iterator to check the next assignment assignment++; } } - - _assignmentQueueMutex.unlock(); + return NULL; } void DomainServer::removeAssignmentFromQueue(Assignment* removableAssignment) { - _assignmentQueueMutex.lock(); - std::deque::iterator assignment = _assignmentQueue.begin(); while (assignment != _assignmentQueue.end()) { @@ -740,8 +725,6 @@ void DomainServer::removeAssignmentFromQueue(Assignment* removableAssignment) { assignment++; } } - - _assignmentQueueMutex.unlock(); } bool DomainServer::checkInWithUUIDMatchesExistingNode(const HifiSockAddr& nodePublicSocket, @@ -796,10 +779,8 @@ void DomainServer::addStaticAssignmentsBackToQueueAfterRestart() { _staticAssignments[i].resetUUID(); qDebug() << "Adding static assignment to queue -" << _staticAssignments[i]; - - _assignmentQueueMutex.lock(); - _assignmentQueue.push_back(&_staticAssignments[i]); - _assignmentQueueMutex.unlock(); + + _assignmentQueue.push_back(&_staticAssignments[i]);gs } } } diff --git a/domain-server/src/DomainServer.h b/domain-server/src/DomainServer.h index 26cdc765ba..ca83436c35 100644 --- a/domain-server/src/DomainServer.h +++ b/domain-server/src/DomainServer.h @@ -49,7 +49,6 @@ private: HTTPManager _HTTPManager; - QMutex _assignmentQueueMutex; std::deque _assignmentQueue; QFile _staticAssignmentFile; From d6431a3e7a5596fedf88e7be4bccd7212107d561 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 29 Jan 2014 15:09:46 -0800 Subject: [PATCH 04/10] remove an extra gs --- domain-server/src/DomainServer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index a124af4b40..603041be54 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -780,7 +780,7 @@ void DomainServer::addStaticAssignmentsBackToQueueAfterRestart() { qDebug() << "Adding static assignment to queue -" << _staticAssignments[i]; - _assignmentQueue.push_back(&_staticAssignments[i]);gs + _assignmentQueue.push_back(&_staticAssignments[i]); } } } From fe192ca2dece38dc8435f8c4feba79142a674d30 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 29 Jan 2014 14:23:39 -0800 Subject: [PATCH 05/10] domain-server patches while looking for payload/pool errors From 740d11027ccfb5605258731ff0adb9c128099b14 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 29 Jan 2014 17:20:32 -0800 Subject: [PATCH 06/10] add QDataStream >> operator to Assignment --- libraries/shared/src/Assignment.cpp | 32 ++++++++++++----------------- libraries/shared/src/Assignment.h | 1 + 2 files changed, 14 insertions(+), 19 deletions(-) diff --git a/libraries/shared/src/Assignment.cpp b/libraries/shared/src/Assignment.cpp index 76ee4b04cf..f8dcf3edca 100644 --- a/libraries/shared/src/Assignment.cpp +++ b/libraries/shared/src/Assignment.cpp @@ -52,6 +52,7 @@ Assignment::Assignment() : } Assignment::Assignment(Assignment::Command command, Assignment::Type type, const QString& pool, Assignment::Location location) : + _uuid(), _command(command), _type(type), _pool(pool), @@ -82,17 +83,7 @@ Assignment::Assignment(const QByteArray& packet) : QDataStream packetStream(packet); packetStream.skipRawData(numBytesForPacketHeader(packet)); - uchar assignmentType; - packetStream >> assignmentType; - _type = (Assignment::Type) assignmentType; - - if (_command != Assignment::RequestCommand) { - // read the GUID for this assignment - packetStream >> _uuid; - } - - packetStream >> _pool; - packetStream >> _payload; + packetStream >> *this; } #ifdef WIN32 @@ -157,14 +148,17 @@ QDebug operator<<(QDebug debug, const Assignment &assignment) { } QDataStream& operator<<(QDataStream &out, const Assignment& assignment) { - out << (quint8) assignment._type; - - // pack the UUID for this assignment, if this is an assignment create or deploy - if (assignment._command != Assignment::RequestCommand) { - out << assignment._uuid; - } - - out << assignment._pool << assignment._payload; + out << (quint8) assignment._type << assignment._uuid << assignment._pool << assignment._payload; return out; } + +QDataStream& operator>>(QDataStream &in, Assignment& assignment) { + quint8 packedType; + in >> packedType; + assignment._type = (Assignment::Type) packedType; + + in >> assignment._uuid >> assignment._pool >> assignment._payload; + + return in; +} diff --git a/libraries/shared/src/Assignment.h b/libraries/shared/src/Assignment.h index fb69271db3..dd34751b57 100644 --- a/libraries/shared/src/Assignment.h +++ b/libraries/shared/src/Assignment.h @@ -91,6 +91,7 @@ public: friend QDebug operator<<(QDebug debug, const Assignment& assignment); friend QDataStream& operator<<(QDataStream &out, const Assignment& assignment); + friend QDataStream& operator>>(QDataStream &in, Assignment& assignment); protected: QUuid _uuid; /// the 16 byte UUID for this assignment From 356222ba15dd17b3a3d01b14f1e791cebcdd5778 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 30 Jan 2014 14:33:36 -0800 Subject: [PATCH 07/10] removal of persistence in DS for static assignments --- domain-server/src/DomainServer.cpp | 590 +++++++++++----------------- domain-server/src/DomainServer.h | 41 +- libraries/shared/src/Assignment.cpp | 2 +- 3 files changed, 252 insertions(+), 381 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 603041be54..f191fdd3ac 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -8,9 +8,11 @@ #include +#include #include #include #include +#include #include #include @@ -27,64 +29,37 @@ const char* VOXEL_SERVER_CONFIG = "voxelServerConfig"; const char* PARTICLE_SERVER_CONFIG = "particleServerConfig"; const char* METAVOXEL_SERVER_CONFIG = "metavoxelServerConfig"; -void signalhandler(int sig){ - if (sig == SIGINT) { - qApp->quit(); - } -} - const quint16 DOMAIN_SERVER_HTTP_PORT = 8080; DomainServer::DomainServer(int argc, char* argv[]) : QCoreApplication(argc, argv), _HTTPManager(DOMAIN_SERVER_HTTP_PORT, QString("%1/resources/web/").arg(QCoreApplication::applicationDirPath()), this), + _staticAssignmentHash(), _assignmentQueue(), - _staticAssignmentFile(QString("%1/config.ds").arg(QCoreApplication::applicationDirPath())), - _staticAssignmentFileData(NULL), - _voxelServerConfig(NULL), - _metavoxelServerConfig(NULL), _hasCompletedRestartHold(false) { - signal(SIGINT, signalhandler); - const char CUSTOM_PORT_OPTION[] = "-p"; const char* customPortString = getCmdOption(argc, (const char**) argv, CUSTOM_PORT_OPTION); unsigned short domainServerPort = customPortString ? atoi(customPortString) : DEFAULT_DOMAIN_SERVER_PORT; - - const char CONFIG_FILE_OPTION[] = "-c"; - const char* configFilePath = getCmdOption(argc, (const char**) argv, CONFIG_FILE_OPTION); - - if (!readConfigFile(configFilePath)) { - QByteArray voxelConfigOption = QString("--%1").arg(VOXEL_SERVER_CONFIG).toLocal8Bit(); - _voxelServerConfig = getCmdOption(argc, (const char**) argv, voxelConfigOption.constData()); - - QByteArray particleConfigOption = QString("--%1").arg(PARTICLE_SERVER_CONFIG).toLocal8Bit(); - _particleServerConfig = getCmdOption(argc, (const char**) argv, particleConfigOption.constData()); - - QByteArray metavoxelConfigOption = QString("--%1").arg(METAVOXEL_SERVER_CONFIG).toLocal8Bit(); - _metavoxelServerConfig = getCmdOption(argc, (const char**) argv, metavoxelConfigOption.constData()); + + QStringList argumentList = arguments(); + int argumentIndex = 0; + + QSet parsedTypes(QSet() << Assignment::AgentType); + parseCommandLineTypeConfigs(argumentList, parsedTypes); + + const QString CONFIG_FILE_OPTION = "--configFile"; + if ((argumentIndex = argumentList.indexOf(CONFIG_FILE_OPTION)) != -1) { + QString configFilePath = argumentList.value(argumentIndex + 1); + readConfigFile(configFilePath, parsedTypes); } + + populateDefaultStaticAssignmentsExcludingTypes(parsedTypes); NodeList* nodeList = NodeList::createInstance(NodeType::DomainServer, domainServerPort); connect(nodeList, SIGNAL(nodeKilled(SharedNodePointer)), this, SLOT(nodeKilled(SharedNodePointer))); - if (!_staticAssignmentFile.exists() || _voxelServerConfig) { - - if (_voxelServerConfig) { - // we have a new VS config, clear the existing file to start fresh - _staticAssignmentFile.remove(); - } - - prepopulateStaticAssignmentFile(); - } - - _staticAssignmentFile.open(QIODevice::ReadWrite); - - _staticAssignmentFileData = _staticAssignmentFile.map(0, _staticAssignmentFile.size()); - - _staticAssignments = (Assignment*) _staticAssignmentFileData; - QTimer* silentNodeTimer = new QTimer(this); connect(silentNodeTimer, SIGNAL(timeout()), nodeList, SLOT(removeSilentNodes())); silentNodeTimer->start(NODE_SILENCE_THRESHOLD_USECS / 1000); @@ -93,8 +68,145 @@ DomainServer::DomainServer(int argc, char* argv[]) : // fire a single shot timer to add static assignments back into the queue after a restart QTimer::singleShot(RESTART_HOLD_TIME_MSECS, this, SLOT(addStaticAssignmentsBackToQueueAfterRestart())); +} - connect(this, SIGNAL(aboutToQuit()), SLOT(cleanup())); +void DomainServer::parseCommandLineTypeConfigs(const QStringList& argumentList, QSet& excludedTypes) { + // check for configs from the command line, these take precedence + const QString CONFIG_TYPE_OPTION = "--configType"; + int clConfigIndex = argumentList.indexOf(CONFIG_TYPE_OPTION); + + // enumerate all CL config overrides and parse them to files + while (clConfigIndex != -1) { + int clConfigType = argumentList.value(clConfigIndex + 1).toInt(); + if (clConfigType < Assignment::AllTypes && !excludedTypes.contains((Assignment::Type) clConfigIndex)) { + Assignment::Type assignmentType = (Assignment::Type) clConfigType; + createStaticAssignmentsForTypeGivenConfigString((Assignment::Type) assignmentType, + argumentList.value(clConfigIndex + 2)); + + excludedTypes.insert(assignmentType); + } + + clConfigIndex = argumentList.indexOf(CONFIG_TYPE_OPTION, clConfigIndex); + } +} + +// Attempts to read configuration from specified path +// returns true on success, false otherwise +void DomainServer::readConfigFile(const QString& path, QSet& excludedTypes) { + if (path.isEmpty()) { + // config file not specified + return; + } + + if (!QFile::exists(path)) { + qWarning("Specified configuration file does not exist!"); + return; + } + + QFile configFile(path); + if (!configFile.open(QIODevice::ReadOnly | QIODevice::Text)) { + qWarning("Can't open specified configuration file!"); + return; + } else { + qDebug() << "Reading configuration from" << path; + } + + QTextStream configStream(&configFile); + QByteArray configStringByteArray = configStream.readAll().toUtf8(); + QJsonObject configDocObject = QJsonDocument::fromJson(configStringByteArray).object(); + configFile.close(); + + QSet appendedExcludedTypes = excludedTypes; + + foreach (const QString& rootStringValue, configDocObject.keys()) { + int possibleConfigType = rootStringValue.toInt(); + + if (possibleConfigType < Assignment::AllTypes + && !excludedTypes.contains((Assignment::Type) possibleConfigType)) { + // this is an appropriate config type and isn't already in our excluded types + // we are good to parse it + Assignment::Type assignmentType = (Assignment::Type) possibleConfigType; + QString configString = readServerAssignmentConfig(configDocObject, rootStringValue); + createStaticAssignmentsForTypeGivenConfigString(assignmentType, configString); + + excludedTypes.insert(assignmentType); + } + } +} + +// find assignment configurations on the specified node name and json object +// returns a string in the form of its equivalent cmd line params +QString DomainServer::readServerAssignmentConfig(const QJsonObject& jsonObject, const QString& nodeName) { + QJsonArray nodeArray = jsonObject[nodeName].toArray(); + + QStringList serverConfig; + foreach (const QJsonValue& childValue, nodeArray) { + QString cmdParams; + QJsonObject childObject = childValue.toObject(); + QStringList keys = childObject.keys(); + for (int i = 0; i < keys.size(); i++) { + QString key = keys[i]; + QString value = childObject[key].toString(); + // both cmd line params and json keys are the same + cmdParams += QString("--%1 %2 ").arg(key, value); + } + serverConfig << cmdParams; + } + + // according to split() calls from DomainServer::prepopulateStaticAssignmentFile + // we shold simply join them with semicolons + return serverConfig.join(';'); +} + +void DomainServer::addStaticAssignmentToAssignmentHash(Assignment* newAssignment) { + qDebug() << "Inserting assignment" << *newAssignment << "to static assignment hash."; + _staticAssignmentHash.insert(newAssignment->getUUID(), SharedAssignmentPointer(newAssignment)); +} + +void DomainServer::createStaticAssignmentsForTypeGivenConfigString(Assignment::Type type, const QString& configString) { + // we have a string for config for this type + qDebug() << "Parsing command line config for assignment type" << type; + + QString multiConfig(configString); + QStringList multiConfigList = multiConfig.split(";"); + + // read each config to a payload for this type of assignment + for (int i = 0; i < multiConfigList.size(); i++) { + QString config = multiConfigList.at(i); + + qDebug("type %d config[%d] = %s", type, i, config.toLocal8Bit().constData()); + + // Now, parse the config to check for a pool + const QString ASSIGNMENT_CONFIG_POOL_OPTION = "--pool"; + QString assignmentPool; + + int poolIndex = config.indexOf(ASSIGNMENT_CONFIG_POOL_OPTION); + + if (poolIndex >= 0) { + int spaceBeforePoolIndex = config.indexOf(' ', poolIndex); + int spaceAfterPoolIndex = config.indexOf(' ', spaceBeforePoolIndex); + + assignmentPool = config.mid(spaceBeforePoolIndex + 1, spaceAfterPoolIndex); + } + + Assignment* configAssignment = new Assignment(Assignment::CreateCommand, type, assignmentPool); + + configAssignment->setPayload(config.toUtf8()); + + addStaticAssignmentToAssignmentHash(configAssignment); + } +} + +void DomainServer::populateDefaultStaticAssignmentsExcludingTypes(const QSet& excludedTypes) { + // enumerate over all assignment types and see if we've already excluded it + for (Assignment::Type defaultedType = Assignment::AudioMixerType; defaultedType != Assignment::AllTypes; defaultedType++) { + if (!excludedTypes.contains(defaultedType)) { + // type has not been set from a command line or config file config, use the default + // by clearing whatever exists and writing a single default assignment with no payload + Assignment* newAssignment = new Assignment(Assignment::CreateCommand, defaultedType); + addStaticAssignmentToAssignmentHash(newAssignment); + } + } } void DomainServer::readAvailableDatagrams() { @@ -147,13 +259,11 @@ void DomainServer::readAvailableDatagrams() { << NodeType::AvatarMixer << NodeType::VoxelServer << NodeType::ParticleServer << NodeType::MetavoxelServer; - Assignment* matchingStaticAssignment = NULL; + SharedAssignmentPointer matchingStaticAssignment; if (!STATICALLY_ASSIGNED_NODES.contains(nodeType) - || ((matchingStaticAssignment = matchingStaticAssignmentForCheckIn(nodeUUID, nodeType)) - || checkInWithUUIDMatchesExistingNode(nodePublicAddress, - nodeLocalAddress, - nodeUUID))) + || (matchingStaticAssignment = matchingStaticAssignmentForCheckIn(nodeUUID, nodeType)) + || checkInWithUUIDMatchesExistingNode(nodePublicAddress, nodeLocalAddress, nodeUUID)) { SharedNodePointer checkInNode = nodeList->addOrUpdateNode(nodeUUID, nodeType, @@ -166,19 +276,13 @@ void DomainServer::readAvailableDatagrams() { if (matchingStaticAssignment) { // this was a newly added node with a matching static assignment + // remove the matching assignment from the assignment queue so we don't take the next check in + // (if it exists) if (_hasCompletedRestartHold) { - // remove the matching assignment from the assignment queue so we don't take the next check in - removeAssignmentFromQueue(matchingStaticAssignment); + removeMatchingAssignmentFromQueue(matchingStaticAssignment); } - - // set the linked data for this node to a copy of the matching assignment - // so we can re-queue it should the node die - Assignment* nodeCopyOfMatchingAssignment = new Assignment(*matchingStaticAssignment); - - checkInNode->setLinkedData(nodeCopyOfMatchingAssignment); } - quint8 numInterestTypes = 0; packetStream >> numInterestTypes; @@ -216,7 +320,7 @@ void DomainServer::readAvailableDatagrams() { qDebug("Received a request for assignment type %i from %s.", requestAssignment.getType(), qPrintable(senderSockAddr.getAddress().toString())); - Assignment* assignmentToDeploy = deployableAssignmentForRequest(requestAssignment); + SharedAssignmentPointer assignmentToDeploy = deployableAssignmentForRequest(requestAssignment); if (assignmentToDeploy) { // give this assignment out, either the type matches or the requestor said they will take any @@ -224,15 +328,10 @@ void DomainServer::readAvailableDatagrams() { QDataStream assignmentStream(&assignmentPacket, QIODevice::Append); - assignmentStream << *assignmentToDeploy; + assignmentStream << assignmentToDeploy; nodeList->getNodeSocket().writeDatagram(assignmentPacket, senderSockAddr.getAddress(), senderSockAddr.getPort()); - - if (assignmentToDeploy->getNumberOfInstances() == 0) { - // there are no more instances of this script to send out, delete it - delete assignmentToDeploy; - } } } else { @@ -280,70 +379,6 @@ QJsonObject jsonObjectForNode(Node* node) { return nodeJson; } -// Attempts to read configuration from specified path -// returns true on success, false otherwise -bool DomainServer::readConfigFile(const char* path) { - if (!path) { - // config file not specified - return false; - } - - if (!QFile::exists(path)) { - qWarning("Specified configuration file does not exist!\n"); - return false; - } - - QFile configFile(path); - if (!configFile.open(QIODevice::ReadOnly | QIODevice::Text)) { - qWarning("Can't open specified configuration file!\n"); - return false; - } else { - qDebug("Reading configuration from %s\n", path); - } - QTextStream configStream(&configFile); - QByteArray configStringByteArray = configStream.readAll().toUtf8(); - QJsonObject configDocObject = QJsonDocument::fromJson(configStringByteArray).object(); - configFile.close(); - - QString voxelServerConfig = readServerAssignmentConfig(configDocObject, VOXEL_SERVER_CONFIG); - _voxelServerConfig = new char[strlen(voxelServerConfig.toLocal8Bit().constData()) +1]; - _voxelServerConfig = strcpy((char *) _voxelServerConfig, voxelServerConfig.toLocal8Bit().constData() + '\0'); - - QString particleServerConfig = readServerAssignmentConfig(configDocObject, PARTICLE_SERVER_CONFIG); - _particleServerConfig = new char[strlen(particleServerConfig.toLocal8Bit().constData()) +1]; - _particleServerConfig = strcpy((char *) _particleServerConfig, particleServerConfig.toLocal8Bit().constData() + '\0'); - - QString metavoxelServerConfig = readServerAssignmentConfig(configDocObject, METAVOXEL_SERVER_CONFIG); - _metavoxelServerConfig = new char[strlen(metavoxelServerConfig.toLocal8Bit().constData()) +1]; - _metavoxelServerConfig = strcpy((char *) _metavoxelServerConfig, metavoxelServerConfig.toLocal8Bit().constData() + '\0'); - - return true; -} - -// find assignment configurations on the specified node name and json object -// returns a string in the form of its equivalent cmd line params -QString DomainServer::readServerAssignmentConfig(QJsonObject jsonObject, const char* nodeName) { - QJsonArray nodeArray = jsonObject[nodeName].toArray(); - - QStringList serverConfig; - foreach (const QJsonValue & childValue, nodeArray) { - QString cmdParams; - QJsonObject childObject = childValue.toObject(); - QStringList keys = childObject.keys(); - for (int i = 0; i < keys.size(); i++) { - QString key = keys[i]; - QString value = childObject[key].toString(); - // both cmd line params and json keys are the same - cmdParams += QString("--%1 %2 ").arg(key, value); - } - serverConfig << cmdParams; - } - - // according to split() calls from DomainServer::prepopulateStaticAssignmentFile - // we shold simply join them with semicolons - return serverConfig.join(';'); -} - bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QString& path) { const QString JSON_MIME_TYPE = "application/json"; @@ -372,24 +407,19 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QString& QJsonObject queuedAssignmentsJSON; // add the queued but unfilled assignments to the json - std::deque::iterator assignment = _assignmentQueue.begin(); - - while (assignment != _assignmentQueue.end()) { + foreach(const SharedAssignmentPointer& assignment, _assignmentQueue) { QJsonObject queuedAssignmentJSON; - QString uuidString = uuidStringWithoutCurlyBraces((*assignment)->getUUID()); - queuedAssignmentJSON[JSON_KEY_TYPE] = QString((*assignment)->getTypeName()); + QString uuidString = uuidStringWithoutCurlyBraces(assignment->getUUID()); + queuedAssignmentJSON[JSON_KEY_TYPE] = QString(assignment->getTypeName()); // if the assignment has a pool, add it - if (!(*assignment)->getPool().isEmpty()) { - queuedAssignmentJSON[JSON_KEY_POOL] = (*assignment)->getPool(); + if (!assignment->getPool().isEmpty()) { + queuedAssignmentJSON[JSON_KEY_POOL] = assignment->getPool(); } // add this queued assignment to the JSON queuedAssignmentsJSON[uuidString] = queuedAssignmentJSON; - - // push forward the iterator to check the next assignment - assignment++; } assignmentJSON["queued"] = queuedAssignmentsJSON; @@ -427,11 +457,8 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QString& // this is a script upload - ask the HTTPConnection to parse the form data QList formData = connection->parseFormData(); - // create an assignment for this saved script, for now make it local only - Assignment* scriptAssignment = new Assignment(Assignment::CreateCommand, - Assignment::AgentType, - NULL, - Assignment::LocalLocation); + // create an assignment for this saved script + Assignment* scriptAssignment = new Assignment(Assignment::CreateCommand, Assignment::AgentType); // check how many instances of this assignment the user wants by checking the ASSIGNMENT-INSTANCES header const QString ASSIGNMENT_INSTANCES_HEADER = "ASSIGNMENT-INSTANCES"; @@ -465,8 +492,7 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QString& connection->respond(HTTPConnection::StatusCode200); // add the script assigment to the assignment queue - // lock the assignment queue mutex since we're operating on a different thread than DS main - _assignmentQueue.push_back(scriptAssignment); + _assignmentQueue.enqueue(SharedAssignmentPointer(scriptAssignment)); } } else if (connection->requestOperation() == QNetworkAccessManager::DeleteOperation) { if (path.startsWith(URI_NODE)) { @@ -501,228 +527,99 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QString& return false; } -void DomainServer::addReleasedAssignmentBackToQueue(Assignment* releasedAssignment) { - qDebug() << "Adding assignment" << *releasedAssignment << " back to queue."; - - // find this assignment in the static file - for (int i = 0; i < MAX_STATIC_ASSIGNMENT_FILE_ASSIGNMENTS; i++) { - if (_staticAssignments[i].getUUID() == releasedAssignment->getUUID()) { - // reset the UUID on the static assignment - _staticAssignments[i].resetUUID(); - - // put this assignment back in the queue so it goes out - _assignmentQueue.push_back(&_staticAssignments[i]); - - } else if (_staticAssignments[i].getUUID().isNull()) { - // we are at the blank part of the static assignments - break out - break; - } - } +void DomainServer::refreshStaticAssignmentAndAddToQueue(SharedAssignmentPointer& assignment) { + QUuid oldUUID = assignment->getUUID(); + assignment->resetUUID(); + + qDebug() << "Reset UUID for assignment -" << *assignment.data() << "- and added to queue. Old UUID was" + << uuidStringWithoutCurlyBraces( oldUUID); + _assignmentQueue.enqueue(assignment); } void DomainServer::nodeKilled(SharedNodePointer node) { - // if this node has linked data it was from an assignment - if (node->getLinkedData()) { - Assignment* nodeAssignment = (Assignment*) node->getLinkedData(); - - addReleasedAssignmentBackToQueue(nodeAssignment); + // if this node's UUID matches a static assignment we need to throw it back in the assignment queue + SharedAssignmentPointer matchedAssignment = _staticAssignmentHash.value(node->getUUID()); + if (matchedAssignment) { + refreshStaticAssignmentAndAddToQueue(matchedAssignment); } } -void DomainServer::prepopulateStaticAssignmentFile() { - int numFreshStaticAssignments = 0; - - // write a fresh static assignment array to file - - Assignment freshStaticAssignments[MAX_STATIC_ASSIGNMENT_FILE_ASSIGNMENTS]; - - // pre-populate the first static assignment list with assignments for root AuM, AvM, VS - freshStaticAssignments[numFreshStaticAssignments++] = Assignment(Assignment::CreateCommand, Assignment::AudioMixerType); - freshStaticAssignments[numFreshStaticAssignments++] = Assignment(Assignment::CreateCommand, Assignment::AvatarMixerType); - - // Handle Domain/Voxel Server configuration command line arguments - if (_voxelServerConfig) { - qDebug("Reading Voxel Server Configuration."); - qDebug() << "config: " << _voxelServerConfig; - - QString multiConfig((const char*) _voxelServerConfig); - QStringList multiConfigList = multiConfig.split(";"); - - // read each config to a payload for a VS assignment - for (int i = 0; i < multiConfigList.size(); i++) { - QString config = multiConfigList.at(i); - - qDebug("config[%d]=%s", i, config.toLocal8Bit().constData()); - - // Now, parse the config to check for a pool - const char ASSIGNMENT_CONFIG_POOL_OPTION[] = "--pool"; - QString assignmentPool; - - int poolIndex = config.indexOf(ASSIGNMENT_CONFIG_POOL_OPTION); - - if (poolIndex >= 0) { - int spaceBeforePoolIndex = config.indexOf(' ', poolIndex); - int spaceAfterPoolIndex = config.indexOf(' ', spaceBeforePoolIndex); - - assignmentPool = config.mid(spaceBeforePoolIndex + 1, spaceAfterPoolIndex); - qDebug() << "The pool for this voxel-assignment is" << assignmentPool; - } - - Assignment voxelServerAssignment(Assignment::CreateCommand, - Assignment::VoxelServerType, - assignmentPool); - - voxelServerAssignment.setPayload(config.toUtf8()); - - freshStaticAssignments[numFreshStaticAssignments++] = voxelServerAssignment; - } - } else { - Assignment rootVoxelServerAssignment(Assignment::CreateCommand, Assignment::VoxelServerType); - freshStaticAssignments[numFreshStaticAssignments++] = rootVoxelServerAssignment; - } - - // Handle Domain/Particle Server configuration command line arguments - if (_particleServerConfig) { - qDebug("Reading Particle Server Configuration."); - qDebug() << "config: " << _particleServerConfig; - - QString multiConfig((const char*) _particleServerConfig); - QStringList multiConfigList = multiConfig.split(";"); - - // read each config to a payload for a VS assignment - for (int i = 0; i < multiConfigList.size(); i++) { - QString config = multiConfigList.at(i); - - qDebug("config[%d]=%s", i, config.toLocal8Bit().constData()); - - // Now, parse the config to check for a pool - const char ASSIGNMENT_CONFIG_POOL_OPTION[] = "--pool"; - QString assignmentPool; - - int poolIndex = config.indexOf(ASSIGNMENT_CONFIG_POOL_OPTION); - - if (poolIndex >= 0) { - int spaceBeforePoolIndex = config.indexOf(' ', poolIndex); - int spaceAfterPoolIndex = config.indexOf(' ', spaceBeforePoolIndex); - - assignmentPool = config.mid(spaceBeforePoolIndex + 1, spaceAfterPoolIndex); - qDebug() << "The pool for this particle-assignment is" << assignmentPool; - } - - Assignment particleServerAssignment(Assignment::CreateCommand, - Assignment::ParticleServerType, - assignmentPool); - - particleServerAssignment.setPayload(config.toLocal8Bit()); - - freshStaticAssignments[numFreshStaticAssignments++] = particleServerAssignment; - } - } else { - Assignment rootParticleServerAssignment(Assignment::CreateCommand, Assignment::ParticleServerType); - freshStaticAssignments[numFreshStaticAssignments++] = rootParticleServerAssignment; - } - - // handle metavoxel configuration command line argument - Assignment& metavoxelAssignment = (freshStaticAssignments[numFreshStaticAssignments++] = - Assignment(Assignment::CreateCommand, Assignment::MetavoxelServerType)); - if (_metavoxelServerConfig) { - metavoxelAssignment.setPayload(QByteArray(_metavoxelServerConfig)); - } - - qDebug() << "Adding" << numFreshStaticAssignments << "static assignments to fresh file."; - - _staticAssignmentFile.open(QIODevice::WriteOnly); - _staticAssignmentFile.write((char*) &freshStaticAssignments, sizeof(freshStaticAssignments)); - _staticAssignmentFile.resize(MAX_STATIC_ASSIGNMENT_FILE_ASSIGNMENTS * sizeof(Assignment)); - _staticAssignmentFile.close(); -} - -Assignment* DomainServer::matchingStaticAssignmentForCheckIn(const QUuid& checkInUUID, NodeType_t nodeType) { - // pull the UUID passed with the check in - +SharedAssignmentPointer DomainServer::matchingStaticAssignmentForCheckIn(const QUuid& checkInUUID, NodeType_t nodeType) { if (_hasCompletedRestartHold) { - // iterate the assignment queue to check for a match - std::deque::iterator assignment = _assignmentQueue.begin(); - while (assignment != _assignmentQueue.end()) { - if ((*assignment)->getUUID() == checkInUUID) { - // return the matched assignment - return *assignment; - } else { - // no match, push deque iterator forwards - assignment++; + // look for a match in the assignment hash + + QQueue::iterator i = _assignmentQueue.begin(); + + while (i != _assignmentQueue.end()) { + if (i->data()->getType() == nodeType && i->data()->getUUID() == checkInUUID) { + return _assignmentQueue.takeAt(i - _assignmentQueue.begin()); } } - } else { - for (int i = 0; i < MAX_STATIC_ASSIGNMENT_FILE_ASSIGNMENTS; i++) { - if (_staticAssignments[i].getUUID() == checkInUUID) { - // return matched assignment - return &_staticAssignments[i]; - } else if (_staticAssignments[i].getUUID().isNull()) { - // end of static assignments, no match - return NULL - return NULL; - } + SharedAssignmentPointer matchingStaticAssignment = _staticAssignmentHash.value(checkInUUID); + if (matchingStaticAssignment && matchingStaticAssignment->getType() == nodeType) { + return matchingStaticAssignment; } } - return NULL; + return SharedAssignmentPointer(); } -Assignment* DomainServer::deployableAssignmentForRequest(Assignment& requestAssignment) { +SharedAssignmentPointer DomainServer::deployableAssignmentForRequest(const Assignment& requestAssignment) { // this is an unassigned client talking to us directly for an assignment // go through our queue and see if there are any assignments to give out - std::deque::iterator assignment = _assignmentQueue.begin(); + QQueue::iterator sharedAssignment = _assignmentQueue.begin(); - while (assignment != _assignmentQueue.end()) { + while (sharedAssignment != _assignmentQueue.end()) { + Assignment* assignment = sharedAssignment->data(); bool requestIsAllTypes = requestAssignment.getType() == Assignment::AllTypes; - bool assignmentTypesMatch = (*assignment)->getType() == requestAssignment.getType(); - bool nietherHasPool = (*assignment)->getPool().isEmpty() && requestAssignment.getPool().isEmpty(); - bool assignmentPoolsMatch = (*assignment)->getPool() == requestAssignment.getPool(); + bool assignmentTypesMatch = assignment->getType() == requestAssignment.getType(); + bool nietherHasPool = assignment->getPool().isEmpty() && requestAssignment.getPool().isEmpty(); + bool assignmentPoolsMatch = assignment->getPool() == requestAssignment.getPool(); if ((requestIsAllTypes || assignmentTypesMatch) && (nietherHasPool || assignmentPoolsMatch)) { - Assignment* deployableAssignment = *assignment; - - if ((*assignment)->getType() == Assignment::AgentType) { + if (assignment->getType() == Assignment::AgentType) { // if there is more than one instance to send out, simply decrease the number of instances - if ((*assignment)->getNumberOfInstances() == 1) { - _assignmentQueue.erase(assignment); + if (assignment->getNumberOfInstances() == 1) { + return _assignmentQueue.takeAt(sharedAssignment - _assignmentQueue.begin()); + } else { + assignment->decrementNumberOfInstances(); + return *sharedAssignment; } - deployableAssignment->decrementNumberOfInstances(); - } else { // remove the assignment from the queue - _assignmentQueue.erase(assignment); + SharedAssignmentPointer deployableAssignment = _assignmentQueue.takeAt(sharedAssignment + - _assignmentQueue.begin()); // until we get a check-in from that GUID // put assignment back in queue but stick it at the back so the others have a chance to go out - _assignmentQueue.push_back(deployableAssignment); + _assignmentQueue.enqueue(deployableAssignment); + + // stop looping, we've handed out an assignment + return deployableAssignment; } - - // stop looping, we've handed out an assignment - return deployableAssignment; } else { // push forward the iterator to check the next assignment - assignment++; + ++sharedAssignment; } } - return NULL; + return SharedAssignmentPointer(); } -void DomainServer::removeAssignmentFromQueue(Assignment* removableAssignment) { - - std::deque::iterator assignment = _assignmentQueue.begin(); - - while (assignment != _assignmentQueue.end()) { - if ((*assignment)->getUUID() == removableAssignment->getUUID()) { - _assignmentQueue.erase(assignment); +void DomainServer::removeMatchingAssignmentFromQueue(const SharedAssignmentPointer& removableAssignment) { + QQueue::iterator potentialMatchingAssignment = _assignmentQueue.begin(); + while (potentialMatchingAssignment != _assignmentQueue.end()) { + if (potentialMatchingAssignment->data()->getUUID() == removableAssignment->getUUID()) { + _assignmentQueue.erase(potentialMatchingAssignment); + + // we matched and removed an assignment, bail out break; } else { - // push forward the iterator to check the next assignment - assignment++; + ++potentialMatchingAssignment; } } } @@ -749,43 +646,24 @@ void DomainServer::addStaticAssignmentsBackToQueueAfterRestart() { _hasCompletedRestartHold = true; // if the domain-server has just restarted, - // check if there are static assignments in the file that we need to - // throw into the assignment queue - - // pull anything in the static assignment file that isn't spoken for and add to the assignment queue - for (int i = 0; i < MAX_STATIC_ASSIGNMENT_FILE_ASSIGNMENTS; i++) { - if (_staticAssignments[i].getUUID().isNull()) { - // reached the end of static assignments, bail - break; - } - + // check if there are static assignments that we need to throw into the assignment queue + QHash::iterator staticAssignment = _staticAssignmentHash.begin(); + while (staticAssignment != _staticAssignmentHash.end()) { + // add any of the un-matched static assignments to the queue bool foundMatchingAssignment = false; - - NodeList* nodeList = NodeList::getInstance(); - + // enumerate the nodes and check if there is one with an attached assignment with matching UUID - foreach (const SharedNodePointer& node, nodeList->getNodeHash()) { - if (node->getLinkedData()) { - Assignment* linkedAssignment = (Assignment*) node->getLinkedData(); - if (linkedAssignment->getUUID() == _staticAssignments[i].getUUID()) { - foundMatchingAssignment = true; - break; - } + foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) { + if (node->getUUID() == staticAssignment->data()->getUUID()) { + foundMatchingAssignment = true; } } - + if (!foundMatchingAssignment) { // this assignment has not been fulfilled - reset the UUID and add it to the assignment queue - _staticAssignments[i].resetUUID(); - - qDebug() << "Adding static assignment to queue -" << _staticAssignments[i]; - - _assignmentQueue.push_back(&_staticAssignments[i]); + refreshStaticAssignmentAndAddToQueue(*staticAssignment); } + + ++staticAssignment; } } - -void DomainServer::cleanup() { - _staticAssignmentFile.unmap(_staticAssignmentFileData); - _staticAssignmentFile.close(); -} diff --git a/domain-server/src/DomainServer.h b/domain-server/src/DomainServer.h index ca83436c35..06ae3c2d0e 100644 --- a/domain-server/src/DomainServer.h +++ b/domain-server/src/DomainServer.h @@ -9,17 +9,16 @@ #ifndef __hifi__DomainServer__ #define __hifi__DomainServer__ -#include - #include -#include -#include +#include +#include +#include #include #include #include -const int MAX_STATIC_ASSIGNMENT_FILE_ASSIGNMENTS = 1000; +typedef QSharedPointer SharedAssignmentPointer; class DomainServer : public QCoreApplication, public HTTPRequestHandler { Q_OBJECT @@ -35,36 +34,30 @@ public slots: void nodeKilled(SharedNodePointer node); private: - bool readConfigFile(const char* path); - QString readServerAssignmentConfig(QJsonObject jsonObj, const char* nodeName); - - void prepopulateStaticAssignmentFile(); - Assignment* matchingStaticAssignmentForCheckIn(const QUuid& checkInUUID, NodeType_t nodeType); - Assignment* deployableAssignmentForRequest(Assignment& requestAssignment); - void removeAssignmentFromQueue(Assignment* removableAssignment); + void parseCommandLineTypeConfigs(const QStringList& argumentList, QSet& excludedTypes); + void readConfigFile(const QString& path, QSet& excludedTypes); + QString readServerAssignmentConfig(const QJsonObject& jsonObject, const QString& nodeName); + void addStaticAssignmentToAssignmentHash(Assignment* newAssignment); + void createStaticAssignmentsForTypeGivenConfigString(Assignment::Type type, const QString& configString); + void populateDefaultStaticAssignmentsExcludingTypes(const QSet& excludedTypes); + + SharedAssignmentPointer matchingStaticAssignmentForCheckIn(const QUuid& checkInUUID, NodeType_t nodeType); + SharedAssignmentPointer deployableAssignmentForRequest(const Assignment& requestAssignment); + void removeMatchingAssignmentFromQueue(const SharedAssignmentPointer& removableAssignment); bool checkInWithUUIDMatchesExistingNode(const HifiSockAddr& nodePublicSocket, const HifiSockAddr& nodeLocalSocket, const QUuid& checkInUUI); - void addReleasedAssignmentBackToQueue(Assignment* releasedAssignment); + void refreshStaticAssignmentAndAddToQueue(SharedAssignmentPointer& assignment); HTTPManager _HTTPManager; - std::deque _assignmentQueue; - - QFile _staticAssignmentFile; - uchar* _staticAssignmentFileData; - - Assignment* _staticAssignments; - - const char* _voxelServerConfig; - const char* _particleServerConfig; - const char* _metavoxelServerConfig; + QHash _staticAssignmentHash; + QQueue _assignmentQueue; bool _hasCompletedRestartHold; private slots: void readAvailableDatagrams(); void addStaticAssignmentsBackToQueueAfterRestart(); - void cleanup(); }; #endif /* defined(__hifi__DomainServer__) */ diff --git a/libraries/shared/src/Assignment.cpp b/libraries/shared/src/Assignment.cpp index f8dcf3edca..a7dd5c36f8 100644 --- a/libraries/shared/src/Assignment.cpp +++ b/libraries/shared/src/Assignment.cpp @@ -144,7 +144,7 @@ const char* Assignment::getTypeName() const { QDebug operator<<(QDebug debug, const Assignment &assignment) { debug.nospace() << "UUID: " << qPrintable(assignment.getUUID().toString()) << ", Type: " << assignment.getType(); - return debug.nospace(); + return debug.space(); } QDataStream& operator<<(QDataStream &out, const Assignment& assignment) { From 55049eeb6b358925ca95c36e54cf4a67b2fc7af1 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 30 Jan 2014 14:54:52 -0800 Subject: [PATCH 08/10] fix assignment packing and unpacking from DS to AC --- assignment-client/src/AssignmentFactory.cpp | 7 ++- domain-server/src/DomainServer.cpp | 62 ++++++++------------- domain-server/src/DomainServer.h | 3 - 3 files changed, 28 insertions(+), 44 deletions(-) diff --git a/assignment-client/src/AssignmentFactory.cpp b/assignment-client/src/AssignmentFactory.cpp index ef587c9b6d..5bf0417f22 100644 --- a/assignment-client/src/AssignmentFactory.cpp +++ b/assignment-client/src/AssignmentFactory.cpp @@ -19,10 +19,11 @@ #include "metavoxels/MetavoxelServer.h" ThreadedAssignment* AssignmentFactory::unpackAssignment(const QByteArray& packet) { - int headerBytes = numBytesForPacketHeader(packet); - + QDataStream packetStream(packet); + packetStream.skipRawData(numBytesForPacketHeader(packet)); + quint8 packedType; - memcpy(&packedType, packet.data() + headerBytes, sizeof(packedType)); + packetStream >> packedType; Assignment::Type unpackedType = (Assignment::Type) packedType; diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index f191fdd3ac..0ab75c0088 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -261,9 +261,11 @@ void DomainServer::readAvailableDatagrams() { SharedAssignmentPointer matchingStaticAssignment; + // check if this is a non-statically assigned node, a node that is assigned and checking in for the first time + // or a node that has already checked in and is continuing to report for duty if (!STATICALLY_ASSIGNED_NODES.contains(nodeType) || (matchingStaticAssignment = matchingStaticAssignmentForCheckIn(nodeUUID, nodeType)) - || checkInWithUUIDMatchesExistingNode(nodePublicAddress, nodeLocalAddress, nodeUUID)) + || nodeList->getInstance()->nodeWithUUID(nodeUUID)) { SharedNodePointer checkInNode = nodeList->addOrUpdateNode(nodeUUID, nodeType, @@ -313,29 +315,29 @@ void DomainServer::readAvailableDatagrams() { } } else if (requestType == PacketTypeRequestAssignment) { - if (_assignmentQueue.size() > 0) { - // construct the requested assignment from the packet data - Assignment requestAssignment(receivedPacket); + // construct the requested assignment from the packet data + Assignment requestAssignment(receivedPacket); + + qDebug() << "Received a request for assignment type" << requestAssignment.getType() + << "from" << senderSockAddr; + + SharedAssignmentPointer assignmentToDeploy = deployableAssignmentForRequest(requestAssignment); + + if (assignmentToDeploy) { + qDebug() << "Deploying assignment -" << *assignmentToDeploy.data() << "- to" << senderSockAddr; - qDebug("Received a request for assignment type %i from %s.", - requestAssignment.getType(), qPrintable(senderSockAddr.getAddress().toString())); + // give this assignment out, either the type matches or the requestor said they will take any + assignmentPacket.resize(numAssignmentPacketHeaderBytes); - SharedAssignmentPointer assignmentToDeploy = deployableAssignmentForRequest(requestAssignment); + QDataStream assignmentStream(&assignmentPacket, QIODevice::Append); - if (assignmentToDeploy) { - // give this assignment out, either the type matches or the requestor said they will take any - assignmentPacket.resize(numAssignmentPacketHeaderBytes); - - QDataStream assignmentStream(&assignmentPacket, QIODevice::Append); - - assignmentStream << assignmentToDeploy; - - nodeList->getNodeSocket().writeDatagram(assignmentPacket, - senderSockAddr.getAddress(), senderSockAddr.getPort()); - } + assignmentStream << *assignmentToDeploy.data(); + nodeList->getNodeSocket().writeDatagram(assignmentPacket, + senderSockAddr.getAddress(), senderSockAddr.getPort()); } else { - qDebug() << "Received an invalid assignment request from" << senderSockAddr.getAddress(); + qDebug() << "Unable to fulfill assignment request of type" << requestAssignment.getType() + << "from" << senderSockAddr; } } } @@ -551,8 +553,10 @@ SharedAssignmentPointer DomainServer::matchingStaticAssignmentForCheckIn(const Q QQueue::iterator i = _assignmentQueue.begin(); while (i != _assignmentQueue.end()) { - if (i->data()->getType() == nodeType && i->data()->getUUID() == checkInUUID) { + if (i->data()->getType() == Assignment::typeForNodeType(nodeType) && i->data()->getUUID() == checkInUUID) { return _assignmentQueue.takeAt(i - _assignmentQueue.begin()); + } else { + ++i; } } } else { @@ -624,24 +628,6 @@ void DomainServer::removeMatchingAssignmentFromQueue(const SharedAssignmentPoint } } -bool DomainServer::checkInWithUUIDMatchesExistingNode(const HifiSockAddr& nodePublicSocket, - const HifiSockAddr& nodeLocalSocket, - const QUuid& checkInUUID) { - NodeList* nodeList = NodeList::getInstance(); - - foreach (const SharedNodePointer& node, nodeList->getNodeHash()) { - if (node->getLinkedData() - && nodePublicSocket == node->getPublicSocket() - && nodeLocalSocket == node->getLocalSocket() - && node->getUUID() == checkInUUID) { - // this is a matching existing node if the public socket, local socket, and UUID match - return true; - } - } - - return false; -} - void DomainServer::addStaticAssignmentsBackToQueueAfterRestart() { _hasCompletedRestartHold = true; diff --git a/domain-server/src/DomainServer.h b/domain-server/src/DomainServer.h index 06ae3c2d0e..60251b3bb4 100644 --- a/domain-server/src/DomainServer.h +++ b/domain-server/src/DomainServer.h @@ -44,9 +44,6 @@ private: SharedAssignmentPointer matchingStaticAssignmentForCheckIn(const QUuid& checkInUUID, NodeType_t nodeType); SharedAssignmentPointer deployableAssignmentForRequest(const Assignment& requestAssignment); void removeMatchingAssignmentFromQueue(const SharedAssignmentPointer& removableAssignment); - bool checkInWithUUIDMatchesExistingNode(const HifiSockAddr& nodePublicSocket, - const HifiSockAddr& nodeLocalSocket, - const QUuid& checkInUUI); void refreshStaticAssignmentAndAddToQueue(SharedAssignmentPointer& assignment); HTTPManager _HTTPManager; From 984fb1a5df0674acb9bf51548d662634159e1982 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 30 Jan 2014 15:22:03 -0800 Subject: [PATCH 09/10] fix config parsing from command line and json --- domain-server/src/DomainServer.cpp | 26 +++++++++++++------------- libraries/shared/src/Assignment.cpp | 5 +++++ 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 0ab75c0088..2c1cb55d2e 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -82,11 +82,10 @@ void DomainServer::parseCommandLineTypeConfigs(const QStringList& argumentList, Assignment::Type assignmentType = (Assignment::Type) clConfigType; createStaticAssignmentsForTypeGivenConfigString((Assignment::Type) assignmentType, argumentList.value(clConfigIndex + 2)); - excludedTypes.insert(assignmentType); } - clConfigIndex = argumentList.indexOf(CONFIG_TYPE_OPTION, clConfigIndex); + clConfigIndex = argumentList.indexOf(CONFIG_TYPE_OPTION, clConfigIndex + 1); } } @@ -167,28 +166,29 @@ void DomainServer::createStaticAssignmentsForTypeGivenConfigString(Assignment::T // we have a string for config for this type qDebug() << "Parsing command line config for assignment type" << type; - QString multiConfig(configString); - QStringList multiConfigList = multiConfig.split(";"); + QStringList multiConfigList = configString.split(";", QString::SkipEmptyParts); + + const QString ASSIGNMENT_CONFIG_POOL_REGEX = "--pool\\s*(\\w+)"; + QRegExp poolRegex(ASSIGNMENT_CONFIG_POOL_REGEX); // read each config to a payload for this type of assignment for (int i = 0; i < multiConfigList.size(); i++) { QString config = multiConfigList.at(i); - qDebug("type %d config[%d] = %s", type, i, config.toLocal8Bit().constData()); - - // Now, parse the config to check for a pool - const QString ASSIGNMENT_CONFIG_POOL_OPTION = "--pool"; + // check the config string for a pool QString assignmentPool; - int poolIndex = config.indexOf(ASSIGNMENT_CONFIG_POOL_OPTION); + int poolIndex = poolRegex.indexIn(config); - if (poolIndex >= 0) { - int spaceBeforePoolIndex = config.indexOf(' ', poolIndex); - int spaceAfterPoolIndex = config.indexOf(' ', spaceBeforePoolIndex); + if (poolIndex != -1) { + assignmentPool = poolRegex.cap(1); - assignmentPool = config.mid(spaceBeforePoolIndex + 1, spaceAfterPoolIndex); + // remove the pool from the config string, the assigned node doesn't need it + config.remove(poolIndex, poolRegex.matchedLength()); } + qDebug("Type %d config[%d] = %s", type, i, config.toLocal8Bit().constData()); + Assignment* configAssignment = new Assignment(Assignment::CreateCommand, type, assignmentPool); configAssignment->setPayload(config.toUtf8()); diff --git a/libraries/shared/src/Assignment.cpp b/libraries/shared/src/Assignment.cpp index a7dd5c36f8..83296991f3 100644 --- a/libraries/shared/src/Assignment.cpp +++ b/libraries/shared/src/Assignment.cpp @@ -144,6 +144,11 @@ const char* Assignment::getTypeName() const { QDebug operator<<(QDebug debug, const Assignment &assignment) { debug.nospace() << "UUID: " << qPrintable(assignment.getUUID().toString()) << ", Type: " << assignment.getType(); + + if (!assignment.getPool().isEmpty()) { + debug << ", Pool: " << assignment.getPool(); + } + return debug.space(); } From f853e34ab19b27f1734f7985bf39fde0c3b53ed3 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 30 Jan 2014 15:49:05 -0800 Subject: [PATCH 10/10] fix unix complaint for no postfix for enum --- domain-server/src/DomainServer.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 2c1cb55d2e..715e750391 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -199,11 +199,11 @@ void DomainServer::createStaticAssignmentsForTypeGivenConfigString(Assignment::T void DomainServer::populateDefaultStaticAssignmentsExcludingTypes(const QSet& excludedTypes) { // enumerate over all assignment types and see if we've already excluded it - for (Assignment::Type defaultedType = Assignment::AudioMixerType; defaultedType != Assignment::AllTypes; defaultedType++) { - if (!excludedTypes.contains(defaultedType)) { + for (int defaultedType = Assignment::AudioMixerType; defaultedType != Assignment::AllTypes; defaultedType++) { + if (!excludedTypes.contains((Assignment::Type) defaultedType)) { // type has not been set from a command line or config file config, use the default // by clearing whatever exists and writing a single default assignment with no payload - Assignment* newAssignment = new Assignment(Assignment::CreateCommand, defaultedType); + Assignment* newAssignment = new Assignment(Assignment::CreateCommand, (Assignment::Type) defaultedType); addStaticAssignmentToAssignmentHash(newAssignment); } }