From d089991237150838120d8a07b513a798d8468c0d Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 13 Sep 2013 11:14:00 -0700 Subject: [PATCH] add handling of Agent assignments to Assignment, DS, AC --- assignment-client/CMakeLists.txt | 8 +++ .../src/Agent.cpp | 18 +++--- .../avatars => assignment-client}/src/Agent.h | 3 - assignment-client/src/main.cpp | 17 +++++- domain-server/src/main.cpp | 58 ++++++++++++++----- libraries/audio/src/AudioMixer.cpp | 1 + libraries/shared/src/Assignment.cpp | 4 ++ libraries/shared/src/Assignment.h | 1 + 8 files changed, 84 insertions(+), 26 deletions(-) rename {libraries/avatars => assignment-client}/src/Agent.cpp (81%) rename {libraries/avatars => assignment-client}/src/Agent.h (89%) diff --git a/assignment-client/CMakeLists.txt b/assignment-client/CMakeLists.txt index 5f20c86ca9..1315b0ce84 100644 --- a/assignment-client/CMakeLists.txt +++ b/assignment-client/CMakeLists.txt @@ -8,9 +8,17 @@ set(MACRO_DIR ${ROOT_DIR}/cmake/macros) # setup for find modules set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../cmake/modules/") +find_package(Qt5Network REQUIRED) + include(${MACRO_DIR}/SetupHifiProject.cmake) setup_hifi_project(${TARGET_NAME} TRUE) +qt5_use_modules(${TARGET_NAME} Network) + +# include glm +include(${MACRO_DIR}/IncludeGLM.cmake) +include_glm(${TARGET_NAME} ${ROOT_DIR}) + # link in the shared library include(${MACRO_DIR}/LinkHifiLibrary.cmake) link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR}) diff --git a/libraries/avatars/src/Agent.cpp b/assignment-client/src/Agent.cpp similarity index 81% rename from libraries/avatars/src/Agent.cpp rename to assignment-client/src/Agent.cpp index 25a0a21d68..3b56a6b0b7 100644 --- a/libraries/avatars/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -25,11 +25,11 @@ void Agent::run(QUrl scriptURL) { NodeList::getInstance()->setOwnerType(NODE_TYPE_AGENT); NodeList::getInstance()->setNodeTypesOfInterest(&NODE_TYPE_AVATAR_MIXER, 1); - QNetworkAccessManager* manager = new QNetworkAccessManager(); + QNetworkAccessManager manager; - qDebug() << "Attemping download of " << scriptURL; + qDebug() << "Attemping download of " << scriptURL << "\n"; - QNetworkReply* reply = manager->get(QNetworkRequest(scriptURL)); + QNetworkReply* reply = manager.get(QNetworkRequest(scriptURL)); QEventLoop loop; QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit())); @@ -47,15 +47,14 @@ void Agent::run(QUrl scriptURL) { QScriptValue agentValue = engine.newQObject(this); engine.globalObject().setProperty("Agent", agentValue); - qDebug() << "Downloaded script:" << scriptString; - - qDebug() << "Evaluated script:" << engine.evaluate(scriptString).toString(); + qDebug() << "Downloaded script:" << scriptString << "\n"; + qDebug() << "Evaluated script:" << engine.evaluate(scriptString).toString() << "\n"; timeval thisSend; timeval lastDomainServerCheckIn = {}; int numMicrosecondsSleep = 0; - const float DATA_SEND_INTERVAL_USECS = (1 / 60.0f) * 1000 * 1000; + const long long DATA_SEND_INTERVAL_USECS = (1 / 60.0f) * 1000 * 1000; sockaddr_in senderAddress; unsigned char receivedData[MAX_PACKET_SIZE]; @@ -65,6 +64,11 @@ void Agent::run(QUrl scriptURL) { // update the thisSend timeval to the current time gettimeofday(&thisSend, NULL); + // if we're not hearing from the domain-server we should stop running + if (NodeList::getInstance()->getNumNoReplyDomainCheckIns() == MAX_SILENT_DOMAIN_SERVER_CHECK_INS) { + break; + } + // send a check in packet to the domain server if DOMAIN_SERVER_CHECK_IN_USECS has elapsed if (usecTimestampNow() - usecTimestamp(&lastDomainServerCheckIn) >= DOMAIN_SERVER_CHECK_IN_USECS) { gettimeofday(&lastDomainServerCheckIn, NULL); diff --git a/libraries/avatars/src/Agent.h b/assignment-client/src/Agent.h similarity index 89% rename from libraries/avatars/src/Agent.h rename to assignment-client/src/Agent.h index e083abb541..45d0beb650 100644 --- a/libraries/avatars/src/Agent.h +++ b/assignment-client/src/Agent.h @@ -9,9 +9,6 @@ #ifndef __hifi__Agent__ #define __hifi__Agent__ -#include -#include - #include "SharedUtil.h" #include diff --git a/assignment-client/src/main.cpp b/assignment-client/src/main.cpp index 046179ea02..16522a2d87 100644 --- a/assignment-client/src/main.cpp +++ b/assignment-client/src/main.cpp @@ -12,6 +12,9 @@ #include #include +#include + +#include "Agent.h" #include #include #include @@ -92,8 +95,18 @@ void childClient() { if (deployedAssignment.getType() == Assignment::AudioMixerType) { AudioMixer::run(); - } else { + } else if (deployedAssignment.getType() == Assignment::AvatarMixerType) { AvatarMixer::run(); + } else { + // figure out the URL for the script for this agent assignment + QString scriptURLString("http://%1:8080/assignment/%2"); + scriptURLString = scriptURLString.arg(inet_ntoa(domainSocketAddr), + deployedAssignment.getUUIDStringWithoutCurlyBraces()); + + qDebug() << "Starting an Agent assignment-client with script at" << scriptURLString << "\n"; + + Agent scriptAgent; + scriptAgent.run(QUrl(scriptURLString)); } } else { qDebug("Received a bad destination socket for assignment.\n"); @@ -171,6 +184,8 @@ void parentMonitor() { int main(int argc, const char* argv[]) { + QCoreApplication app(argc, (char**) argv); + setvbuf(stdout, NULL, _IOLBF, 0); // use the verbose message handler in Logging diff --git a/domain-server/src/main.cpp b/domain-server/src/main.cpp index 32959139d9..47dfa83aef 100644 --- a/domain-server/src/main.cpp +++ b/domain-server/src/main.cpp @@ -26,6 +26,8 @@ #include #include +#include + #include "Assignment.h" #include "NodeList.h" #include "NodeTypes.h" @@ -40,6 +42,9 @@ unsigned char packetData[MAX_PACKET_SIZE]; const int NODE_COUNT_STAT_INTERVAL_MSECS = 5000; +QMutex assignmentQueueMutex; +std::deque assignmentQueue; + unsigned char* addNodeToBroadcastPacket(unsigned char* currentPosition, Node* nodeToAdd) { *currentPosition++ = nodeToAdd->getType(); @@ -70,18 +75,25 @@ static int mongooseRequestHandler(struct mg_connection *conn) { const char ASSIGNMENT_SCRIPT_HOST_LOCATION[] = "web/assignment"; static void mongooseUploadHandler(struct mg_connection *conn, const char *path) { - // create an assignment for this saved script - Assignment scriptAssignment(Assignment::CreateCommand, Assignment::AgentType); + // create an assignment for this saved script, for now make it local only + Assignment *scriptAssignment = new Assignment(Assignment::CreateCommand, Assignment::AgentType, Assignment::LocalLocation); QString newPath(ASSIGNMENT_SCRIPT_HOST_LOCATION); newPath += "/"; // append the UUID for this script as the new filename, remove the curly braces - newPath += scriptAssignment.getUUID().toString().mid(1, scriptAssignment.getUUID().toString().length() - 2); + newPath += scriptAssignment->getUUIDStringWithoutCurlyBraces(); // rename the saved script to the GUID of the assignment and move it to the script host locaiton rename(path, newPath.toStdString().c_str()); qDebug("Saved a script for assignment at %s\n", newPath.toStdString().c_str()); + + // 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(); + } int main(int argc, const char* argv[]) { @@ -121,9 +133,6 @@ int main(int argc, const char* argv[]) { const long long GLOBAL_ASSIGNMENT_REQUEST_INTERVAL_USECS = 1 * 1000 * 1000; timeval lastGlobalAssignmentRequest = {}; - // setup the assignment queue - std::deque assignmentQueue; - // as a domain-server we will always want an audio mixer and avatar mixer // setup the create assignments for those Assignment audioMixerAssignment(Assignment::CreateCommand, @@ -156,19 +165,21 @@ int main(int argc, const char* argv[]) { while (true) { + ::assignmentQueueMutex.lock(); // check if our audio-mixer or avatar-mixer are dead and we don't have existing assignments in the queue // so we can add those assignments back to the front of the queue since they are high-priority if (!nodeList->soloNodeOfType(NODE_TYPE_AVATAR_MIXER) && - std::find(assignmentQueue.begin(), assignmentQueue.end(), &avatarMixerAssignment) == assignmentQueue.end()) { + std::find(::assignmentQueue.begin(), assignmentQueue.end(), &avatarMixerAssignment) == ::assignmentQueue.end()) { qDebug("Missing an avatar mixer and assignment not in queue. Adding.\n"); - assignmentQueue.push_front(&avatarMixerAssignment); + ::assignmentQueue.push_front(&avatarMixerAssignment); } if (!nodeList->soloNodeOfType(NODE_TYPE_AUDIO_MIXER) && - std::find(assignmentQueue.begin(), assignmentQueue.end(), &audioMixerAssignment) == assignmentQueue.end()) { + std::find(::assignmentQueue.begin(), ::assignmentQueue.end(), &audioMixerAssignment) == ::assignmentQueue.end()) { qDebug("Missing an audio mixer and assignment not in queue. Adding.\n"); - assignmentQueue.push_front(&audioMixerAssignment); + ::assignmentQueue.push_front(&audioMixerAssignment); } + ::assignmentQueueMutex.unlock(); while (nodeList->getNodeSocket()->receive((sockaddr *)&nodePublicAddress, packetData, &receivedBytes) && packetVersionMatch(packetData)) { @@ -269,11 +280,13 @@ int main(int argc, const char* argv[]) { qDebug("Received a request for assignment.\n"); + ::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(); + std::deque::iterator assignment = ::assignmentQueue.begin(); - while (assignment != assignmentQueue.end()) { + while (assignment != ::assignmentQueue.end()) { // give this assignment out, no conditions stop us from giving it to the local assignment client int numHeaderBytes = populateTypeAndVersion(broadcastPacket, PACKET_TYPE_CREATE_ASSIGNMENT); @@ -284,11 +297,18 @@ int main(int argc, const char* argv[]) { numHeaderBytes + numAssignmentBytes); // remove the assignment from the queue - assignmentQueue.erase(assignment); + ::assignmentQueue.erase(assignment); + + if ((*assignment)->getType() == Assignment::AgentType) { + // if this is a script assignment we need to delete it to avoid a memory leak + delete *assignment; + } // stop looping, we've handed out an assignment break; } + + ::assignmentQueueMutex.unlock(); } } @@ -296,8 +316,10 @@ int main(int argc, const char* argv[]) { if (usecTimestampNow() - usecTimestamp(&lastGlobalAssignmentRequest) >= GLOBAL_ASSIGNMENT_REQUEST_INTERVAL_USECS) { gettimeofday(&lastGlobalAssignmentRequest, NULL); + ::assignmentQueueMutex.lock(); + // go through our queue and see if there are any assignments to send to the global assignment server - std::deque::iterator assignment = assignmentQueue.begin(); + std::deque::iterator assignment = ::assignmentQueue.begin(); while (assignment != assignmentQueue.end()) { @@ -308,7 +330,12 @@ int main(int argc, const char* argv[]) { nodeList->sendAssignment(*(*assignment)); // remove the assignment from the queue - assignmentQueue.erase(assignment); + ::assignmentQueue.erase(assignment); + + if ((*assignment)->getType() == Assignment::AgentType) { + // if this is a script assignment we need to delete it to avoid a memory leak + delete *assignment; + } // stop looping, we've handed out an assignment break; @@ -318,6 +345,7 @@ int main(int argc, const char* argv[]) { } } + ::assignmentQueueMutex.unlock(); } if (Logging::shouldSendStats()) { diff --git a/libraries/audio/src/AudioMixer.cpp b/libraries/audio/src/AudioMixer.cpp index d4b6097134..d4959dfa8f 100644 --- a/libraries/audio/src/AudioMixer.cpp +++ b/libraries/audio/src/AudioMixer.cpp @@ -1,3 +1,4 @@ + // // AudioMixer.cpp // hifi diff --git a/libraries/shared/src/Assignment.cpp b/libraries/shared/src/Assignment.cpp index c0e1f3af09..8f6d20db9e 100644 --- a/libraries/shared/src/Assignment.cpp +++ b/libraries/shared/src/Assignment.cpp @@ -89,6 +89,10 @@ Assignment::~Assignment() { delete _attachedLocalSocket; } +QString Assignment::getUUIDStringWithoutCurlyBraces() const { + return _uuid.toString().mid(1, _uuid.toString().length() - 2); +} + void Assignment::setAttachedPublicSocket(const sockaddr* attachedPublicSocket) { if (_attachedPublicSocket) { // delete the old socket if it exists diff --git a/libraries/shared/src/Assignment.h b/libraries/shared/src/Assignment.h index d34c436a6c..6985f21535 100644 --- a/libraries/shared/src/Assignment.h +++ b/libraries/shared/src/Assignment.h @@ -49,6 +49,7 @@ public: ~Assignment(); const QUuid& getUUID() const { return _uuid; } + QString getUUIDStringWithoutCurlyBraces() const; Assignment::Command getCommand() const { return _command; } Assignment::Type getType() const { return _type; } Assignment::Location getLocation() const { return _location; }