Esempio n. 1
0
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);
}