예제 #1
0
파일: Agent.cpp 프로젝트: problem/hifi
void Agent::run() {
    NodeList::getInstance()->setOwnerType(NODE_TYPE_AGENT);
    NodeList::getInstance()->setNodeTypesOfInterest(&NODE_TYPE_VOXEL_SERVER, 1);
    
    QNetworkAccessManager manager;
    
    // figure out the URL for the script for this agent assignment
    QString scriptURLString("http://%1:8080/assignment/%2");
    scriptURLString = scriptURLString.arg(NodeList::getInstance()->getDomainIP().toString(),
                                         this->getUUIDStringWithoutCurlyBraces());
    QUrl scriptURL(scriptURLString);
    
    qDebug() << "Attemping download of " << scriptURL << "\n";
    
    QNetworkReply* reply = manager.get(QNetworkRequest(scriptURL));
    
    QEventLoop loop;
    QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
    loop.exec();
    
    QString scriptString = QString(reply->readAll());
    
    QScriptEngine engine;
    
    QScriptValue agentValue = engine.newQObject(this);
    engine.globalObject().setProperty("Agent", agentValue);
    
    VoxelScriptingInterface voxelScripter;
    QScriptValue voxelScripterValue =  engine.newQObject(&voxelScripter);
    engine.globalObject().setProperty("Voxels", voxelScripterValue);
    
    qDebug() << "Downloaded script:" << scriptString << "\n";
    qDebug() << "Evaluated script:" << engine.evaluate(scriptString).toString() << "\n";
    
    timeval thisSend;
    timeval lastDomainServerCheckIn = {};
    int numMicrosecondsSleep = 0;
    
    const long long DATA_SEND_INTERVAL_USECS = (1 / 60.0f) * 1000 * 1000;
    
    sockaddr_in senderAddress;
    unsigned char receivedData[MAX_PACKET_SIZE];
    ssize_t receivedBytes;
    
    while (!_shouldStop) {
        // 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);
            NodeList::getInstance()->sendDomainServerCheckIn();
        }
        
        // allow the scripter's call back to setup visual data
        emit preSendCallback();
        // flush the voxel packet queue
        voxelScripter.getVoxelPacketSender()->process();
        
        if (NodeList::getInstance()->getNodeSocket()->receive((sockaddr*) &senderAddress, receivedData, &receivedBytes)) {
            NodeList::getInstance()->processNodeData((sockaddr*) &senderAddress, receivedData, receivedBytes);
        }
        
        // sleep for the correct amount of time to have data send be consistently timed
        if ((numMicrosecondsSleep = DATA_SEND_INTERVAL_USECS - (usecTimestampNow() - usecTimestamp(&thisSend))) > 0) {
            usleep(numMicrosecondsSleep);
        }
    }
    
}
예제 #2
0
파일: Agent.cpp 프로젝트: digi-chris/hifi
void Agent::run() {
    NodeList* nodeList = NodeList::getInstance();
    nodeList->setOwnerType(NODE_TYPE_AGENT);
    
    const char AGENT_NODE_TYPES_OF_INTEREST[2] = { NODE_TYPE_VOXEL_SERVER, NODE_TYPE_AUDIO_MIXER };
    
    nodeList->setNodeTypesOfInterest(AGENT_NODE_TYPES_OF_INTEREST, sizeof(AGENT_NODE_TYPES_OF_INTEREST));

    nodeList->getNodeSocket()->setBlocking(false);
    
    // figure out the URL for the script for this agent assignment
    QString scriptURLString("http://%1:8080/assignment/%2");
    scriptURLString = scriptURLString.arg(NodeList::getInstance()->getDomainIP().toString(),
                                          uuidStringWithoutCurlyBraces(_uuid));
    
    // setup curl for script download
    CURLcode curlResult;
    
    CURL* curlHandle = curl_easy_init();
    
    // tell curl which file to grab
    curl_easy_setopt(curlHandle, CURLOPT_URL, scriptURLString.toStdString().c_str());
    
    // send the data to the WriteMemoryCallback function
    curl_easy_setopt(curlHandle, CURLOPT_WRITEFUNCTION, writeScriptDataToString);
    
    QString scriptContents;
    
    // pass the scriptContents QString to append data to
    curl_easy_setopt(curlHandle, CURLOPT_WRITEDATA, (void *)&scriptContents);
    
    // send a user agent since some servers will require it
    curl_easy_setopt(curlHandle, CURLOPT_USERAGENT, "libcurl-agent/1.0");
    
    // make sure CURL fails on a 400 code
    curl_easy_setopt(curlHandle, CURLOPT_FAILONERROR, true);
    
    qDebug() << "Downloading script at" << scriptURLString << "\n";
    
    // blocking get for JS file
    curlResult = curl_easy_perform(curlHandle);
  
    if (curlResult == CURLE_OK) {
        // cleanup curl
        curl_easy_cleanup(curlHandle);
        curl_global_cleanup();
        
        QScriptEngine engine;
        
        // register meta-type for glm::vec3 conversions
        qScriptRegisterMetaType(&engine, vec3toScriptValue, vec3FromScriptValue);
        
        QScriptValue agentValue = engine.newQObject(this);
        engine.globalObject().setProperty("Agent", agentValue);
        
        VoxelScriptingInterface voxelScripter;
        QScriptValue voxelScripterValue =  engine.newQObject(&voxelScripter);
        engine.globalObject().setProperty("Voxels", voxelScripterValue);
        
        QScriptValue treeScaleValue = engine.newVariant(QVariant(TREE_SCALE));
        engine.globalObject().setProperty("TREE_SCALE", treeScaleValue);

        // let the VoxelPacketSender know how frequently we plan to call it
        voxelScripter.getVoxelPacketSender()->setProcessCallIntervalHint(INJECT_INTERVAL_USECS);
        
        // hook in a constructor for audio injectorss
        AudioInjector scriptedAudioInjector(BUFFER_LENGTH_SAMPLES_PER_CHANNEL);
        QScriptValue audioInjectorValue = engine.newQObject(&scriptedAudioInjector);
        engine.globalObject().setProperty("AudioInjector", audioInjectorValue);
        
        qDebug() << "Downloaded script:" << scriptContents << "\n";
        QScriptValue result = engine.evaluate(scriptContents);
        qDebug() << "Evaluated script.\n";
        
        if (engine.hasUncaughtException()) {
            int line = engine.uncaughtExceptionLineNumber();
            qDebug() << "Uncaught exception at line" << line << ":" << result.toString() << "\n";
        }
        
        timeval startTime;
        gettimeofday(&startTime, NULL);
        
        timeval lastDomainServerCheckIn = {};
        
        sockaddr_in senderAddress;
        unsigned char receivedData[MAX_PACKET_SIZE];
        ssize_t receivedBytes;
        
        int thisFrame = 0;
        
        NodeList::getInstance()->startSilentNodeRemovalThread();
        
        while (!_shouldStop) {
            
            // 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);
                NodeList::getInstance()->sendDomainServerCheckIn();
            }
            
            // find the audio-mixer in the NodeList so we can inject audio at it
            Node* audioMixer = NodeList::getInstance()->soloNodeOfType(NODE_TYPE_AUDIO_MIXER);
            
        
            if (audioMixer && audioMixer->getActiveSocket()) {
                emit willSendAudioDataCallback();
            }
            
            int usecToSleep = usecTimestamp(&startTime) + (thisFrame++ * INJECT_INTERVAL_USECS) - usecTimestampNow();
            if (usecToSleep > 0) {
                usleep(usecToSleep);
            }
            
            if (audioMixer && audioMixer->getActiveSocket() && scriptedAudioInjector.hasSamplesToInject()) {
                // we have an audio mixer and samples to inject, send those off
                scriptedAudioInjector.injectAudio(NodeList::getInstance()->getNodeSocket(), audioMixer->getActiveSocket());
                
                // clear out the audio injector so that it doesn't re-send what we just sent
                scriptedAudioInjector.clear();
            }
        
            if (audioMixer && !audioMixer->getActiveSocket()) {
                // don't have an active socket for the audio-mixer, ping it now
                NodeList::getInstance()->pingPublicAndLocalSocketsForInactiveNode(audioMixer);
            }
            
            if (voxelScripter.getVoxelPacketSender()->voxelServersExist()) {
                // allow the scripter's call back to setup visual data
                emit willSendVisualDataCallback();
                
                // release the queue of edit voxel messages.
                voxelScripter.getVoxelPacketSender()->releaseQueuedMessages();
                
                // since we're in non-threaded mode, call process so that the packets are sent
                voxelScripter.getVoxelPacketSender()->process();

            }            
            
            if (engine.hasUncaughtException()) {
                int line = engine.uncaughtExceptionLineNumber();
                qDebug() << "Uncaught exception at line" << line << ":" << engine.uncaughtException().toString() << "\n";
            }

            while (NodeList::getInstance()->getNodeSocket()->receive((sockaddr*) &senderAddress, receivedData, &receivedBytes)
                   && packetVersionMatch(receivedData)) {
                if (receivedData[0] == PACKET_TYPE_VOXEL_JURISDICTION) {
                    voxelScripter.getJurisdictionListener()->queueReceivedPacket((sockaddr&) senderAddress,
                                                                                 receivedData,
                                                                                 receivedBytes);
                } else {
                    NodeList::getInstance()->processNodeData((sockaddr*) &senderAddress, receivedData, receivedBytes);
                }
            }
        }
    
        NodeList::getInstance()->stopSilentNodeRemovalThread(); 
        
    } else {
        // error in curl_easy_perform
        qDebug() << "curl_easy_perform for JS failed:" << curl_easy_strerror(curlResult) << "\n";
        
        // cleanup curl
        curl_easy_cleanup(curlHandle);
        curl_global_cleanup();
    }
}