static u_result startMonitoring( const u_participant participant, const u_waitset waitset, const struct builtin_datareader_set *drset) { c_iter events, topics; u_waitsetEvent event; c_time timeout; os_uint32 reportInterval; v_gid participantGid, publicationGid, subscriptionGid, gid; u_result result; u_dataReader dataReader; u_topic topic; c_iter vgroups; v_group vgroup; v_duration duration; c_long participantOffset, publicationOffset, subscriptionOffset; os_threadAttr attr; os_result osr; /*Resolve unique identifications of readers*/ participantGid = u_entityGid((u_entity)drset->participant_dr); publicationGid = u_entityGid((u_entity)drset->publication_dr); subscriptionGid = u_entityGid((u_entity)drset->subscription_dr); /*Resolve topics to find offsets in the data. The offsets are used later on*/ duration.seconds = 0; duration.nanoseconds = 0; topics = u_participantFindTopic(participant, V_PARTICIPANTINFO_NAME, duration); topic = c_iterTakeFirst(topics); if(topic){ result = u_entityAction(u_entity(topic), resolveOffset, &participantOffset); } else { result = U_RESULT_INTERNAL_ERROR; in_printf(IN_LEVEL_SEVERE, "Could not resolve participant info offset.\n"); } c_iterFree(topics); if(result == U_RESULT_OK){ topics = u_participantFindTopic(participant, V_PUBLICATIONINFO_NAME, duration); topic = c_iterTakeFirst(topics); if(topic){ result = u_entityAction(u_entity(topic), resolveOffset, &publicationOffset); } else { result = U_RESULT_INTERNAL_ERROR; in_printf(IN_LEVEL_SEVERE, "Could not resolve publication info offset.\n"); } c_iterFree(topics); } if(result == U_RESULT_OK){ topics = u_participantFindTopic(participant, V_SUBSCRIPTIONINFO_NAME, duration); topic = c_iterTakeFirst(topics); if(topic){ result = u_entityAction(u_entity(topic), resolveOffset, &subscriptionOffset); } else { result = U_RESULT_INTERNAL_ERROR; in_printf(IN_LEVEL_SEVERE, "Could not resolve subscription info offset.\n"); } c_iterFree(topics); } if(result == U_RESULT_OK){ timeout.seconds = 0; timeout.nanoseconds = 100 * 1000 * 1000; /*100 ms*/ in_printf(IN_LEVEL_FINE, "Collecting initial entities...\n"); result = handleParticipant(drset->participant_dr, participantOffset); if(result == U_RESULT_OK){ result = handlePublication(drset->publication_dr, publicationOffset, drset->participant_dr, participantOffset); if(result == U_RESULT_OK){ result = handleSubscription(drset->subscription_dr, subscriptionOffset, drset->participant_dr, participantOffset); if(result == U_RESULT_OK){ vgroups = v_serviceTakeNewGroups(service); vgroup = (v_group)c_iterTakeFirst(vgroups); while(vgroup && result == U_RESULT_OK){ result = handleGroup(service, vgroup); c_free(vgroup); vgroup = (v_group)c_iterTakeFirst(vgroups); } c_iterFree(vgroups); if(result == U_RESULT_OK){ in_printf(IN_LEVEL_FINE, "Waiting for entities to be created/deleted...\n"); } else { in_printf(IN_LEVEL_SEVERE, "Could not collect initial groups...\n"); } } else { in_printf(IN_LEVEL_SEVERE, "Could not collect initial subscriptions...\n"); } } else { in_printf(IN_LEVEL_SEVERE, "Could not collect initial publications...\n"); } } else { in_printf(IN_LEVEL_SEVERE, "Could not collect initial participants...\n"); } } osr = os_threadAttrInit(&attr); if(osr == os_resultSuccess){ osr = os_threadCreate(&clientWriterThread, "clientWriterMonitor", &attr, in_discoveryClientWriterMonitor, NULL); if(osr != os_resultSuccess){ result = U_RESULT_INTERNAL_ERROR; } } else { result = U_RESULT_INTERNAL_ERROR; } reportInterval = 0; while(result == U_RESULT_OK && !terminate){ events = NULL; /*Wait for events to occur*/ result = u_waitsetTimedWaitEvents(waitset, timeout, &events); if(result == U_RESULT_OK){ event = (u_waitsetEvent)(c_iterTakeFirst(events)); while(event){ if(((event->events) & V_EVENT_DATA_AVAILABLE) == V_EVENT_DATA_AVAILABLE) { if(event->entity){ dataReader = (u_dataReader)event->entity; gid = u_entityGid(event->entity); if(v_gidCompare(gid, participantGid) == C_EQ){ result = handleParticipant( drset->participant_dr, participantOffset); } else if(v_gidCompare(gid, subscriptionGid) == C_EQ){ result = handleSubscription( drset->subscription_dr, subscriptionOffset, drset->participant_dr, participantOffset); } else if(v_gidCompare(gid, publicationGid) == C_EQ){ result = handlePublication( drset->publication_dr, publicationOffset, drset->participant_dr, participantOffset); } else { in_printf(IN_LEVEL_SEVERE, "This is impossible...at least in my understanding of the world.\n"); result = U_RESULT_INTERNAL_ERROR; } } else { in_printf(IN_LEVEL_WARNING, "DATA_AVAILABLE (%d) but no entity.\n", event->events); } } else if(((event->events) & V_EVENT_NEW_GROUP) == V_EVENT_NEW_GROUP) { vgroups = v_serviceTakeNewGroups(service); vgroup = (v_group)c_iterTakeFirst(vgroups); while(vgroup && result == U_RESULT_OK){ result = handleGroup(service, vgroup); c_free(vgroup); vgroup = (v_group)c_iterTakeFirst(vgroups); } c_iterFree(vgroups); } else { in_printf(IN_LEVEL_SEVERE, "Received unexpected event %d.\n", event->events); result = U_RESULT_INTERNAL_ERROR; } u_waitsetEventFree(event); event = (u_waitsetEvent)(c_iterTakeFirst(events)); } } else if(result == U_RESULT_DETACHING){ in_printf(IN_LEVEL_INFO, "Starting termination now...\n"); } else if(result == U_RESULT_TIMEOUT){ result = U_RESULT_OK; } else { in_printf(IN_LEVEL_SEVERE, "Waitset wait failed.\n"); } if(events){/* events may be null if waitset was deleted */ c_iterFree(events); } reportInterval++; if(reportInterval >= 5){ /*reportEntities();*/ reportInterval = 0; } } return result; }
void RemoteComponent::handleCommand(QHttpRequest* request, QHttpResponse* response) { QVariantMap queryMap = QueryToMap(request->url()); QVariantMap headerMap = HeaderToMap(request->headers()); QString identifier = headerMap["x-plex-client-identifier"].toString(); response->addHeader("Access-Control-Allow-Origin", "*"); response->addHeader("X-Plex-Client-Identifier", SettingsComponent::Get().value(SETTINGS_SECTION_WEBCLIENT, "clientID").toByteArray()); // handle CORS requests here if ((request->method() == qhttp::EHTTP_OPTIONS) && headerMap.contains("access-control-request-method")) { response->addHeader("Content-Type", "text/plain"); response->addHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, PUT, HEAD"); response->addHeader("Access-Control-Max-Age", "1209600"); response->addHeader("Connection", "close"); if (headerMap.contains("access-control-request-headers")) { response->addHeader("Access-Control-Allow-Headers", headerMap.value("access-control-request-headers").toByteArray()); } response->setStatusCode(qhttp::ESTATUS_OK); response->end(); return; } // we want to handle the subscription events in the host // since we are going to handle the updating later. // if (request->url().path() == "/player/timeline/subscribe") { handleSubscription(request, response, false); return; } else if (request->url().path() == "/player/timeline/unsubscribe") { subscriberRemove(request->headers()["x-plex-client-identifier"]); response->setStatusCode(qhttp::ESTATUS_OK); response->end(); return; } else if ((request->url().path() == "/player/timeline/poll")) { QMutexLocker lk(&m_subscriberLock); if (!m_subscriberMap.contains(identifier)) { lk.unlock(); handleSubscription(request, response, true); lk.relock(); } RemotePollSubscriber *subscriber = (RemotePollSubscriber *)m_subscriberMap[identifier]; if (subscriber) { subscriber->reSubscribe(); subscriber->setHTTPResponse(response); // if we don't have to wait, just ship the update right away // otherwise, this will wait until next update if (! (queryMap.contains("wait") && (queryMap["wait"].toList()[0].toInt() == 1))) { subscriber->sendUpdate(); } } return; } // handle commandID if (!headerMap.contains("x-plex-client-identifier") || !queryMap.contains("commandID")) { QLOG_WARN() << "Can't find a X-Plex-Client-Identifier header"; response->setStatusCode(qhttp::ESTATUS_NOT_ACCEPTABLE); response->end(); return; } quint64 commandId = 0; { QMutexLocker lk(&m_responseLock); commandId = ++m_commandId; m_responseMap[commandId] = response; connect(response, &QHttpResponse::done, this, &RemoteComponent::responseDone); } { QMutexLocker lk(&m_subscriberLock); if (!m_subscriberMap.contains(identifier)) { QLOG_WARN() << "Failed to lock up subscriber" << identifier; response->setStatusCode(qhttp::ESTATUS_NOT_ACCEPTABLE); response->end(); return; } RemoteSubscriber* subscriber = m_subscriberMap[identifier]; subscriber->setCommandId(m_commandId, queryMap["commandID"].toList()[0].toInt()); } QVariantMap arg = { { "method", request->methodString() }, { "headers", headerMap }, { "path", request->url().path() }, { "query", queryMap }, { "commandID", m_commandId} }; emit commandReceived(arg); }