This adds mStatus, mReason and mContent to ResponderBase and fills those in instead of passing it to member functions. The added danger here is that now code can accidently try to access these variables while they didn't already get a correct value. Affected members of ResponderBase (that now have less arguments): decode_llsd_body, decode_raw_body, completedHeaders, completed -> httpCompleted, result -> httpSuccess, errorWithContent and error -> httpFailure. New API: ResponderBase::setResult ResponderBase::getStatus() ResponderBase::getReason() ResponderBase::getContent() ResponderBase::getResponseHeaders() (returns AIHTTPReceivedHeaders though, not LLSD) ResponderBase::dumpResponse() ResponderWithCompleted::completeResult ResponderWithResult::failureResult (previously pubErrorWithContent) ResponderWithResult::successResult (previously pubResult) Not implemented: getHTTPMethod() - use getName() instead which returns the class name of the responder. completedHeaders() is still called as usual, although you can ignore it (not implement in a derived responder) and call getResponseHeaders() instead, provided you implement needsHeaders() and have it return true. However, classes derived from ResponderHeadersOnly do not have completedHeaders(), so they still must implement completedHeaders(), and then call getResponseHeaders() or just access mReceivedHeaders directly, as usual.
417 lines
13 KiB
C++
417 lines
13 KiB
C++
/**
|
|
* @file llmediadataclient.h
|
|
* @brief class for queueing up requests to the media service
|
|
*
|
|
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
|
|
* Second Life Viewer Source Code
|
|
* Copyright (C) 2010, Linden Research, Inc.
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation;
|
|
* version 2.1 of the License only.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*
|
|
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
|
* $/LicenseInfo$
|
|
*/
|
|
|
|
#ifndef LL_LLMEDIADATACLIENT_H
|
|
#define LL_LLMEDIADATACLIENT_H
|
|
|
|
#include "llhttpclient.h"
|
|
#include <set>
|
|
#include "llrefcount.h"
|
|
#include "llpointer.h"
|
|
#include "lleventtimer.h"
|
|
|
|
extern AIHTTPTimeoutPolicy mediaDataClientResponder_timeout;
|
|
|
|
// Link seam for LLVOVolume
|
|
class LLMediaDataClientObject : public LLRefCount
|
|
{
|
|
public:
|
|
// Get the number of media data items
|
|
virtual U8 getMediaDataCount() const = 0;
|
|
// Get the media data at index, as an LLSD
|
|
virtual LLSD getMediaDataLLSD(U8 index) const = 0;
|
|
// Return true if the current URL for the face in the media data matches the specified URL.
|
|
virtual bool isCurrentMediaUrl(U8 index, const std::string &url) const = 0;
|
|
// Get this object's UUID
|
|
virtual LLUUID getID() const = 0;
|
|
// Navigate back to previous URL
|
|
virtual void mediaNavigateBounceBack(U8 index) = 0;
|
|
// Does this object have media?
|
|
virtual bool hasMedia() const = 0;
|
|
// Update the object's media data to the given array
|
|
virtual void updateObjectMediaData(LLSD const &media_data_array, const std::string &version_string) = 0;
|
|
// Return the total "interest" of the media (on-screen area)
|
|
virtual F64 getMediaInterest() const = 0;
|
|
// Return the given cap url
|
|
virtual std::string getCapabilityUrl(const std::string &name) const = 0;
|
|
// Return whether the object has been marked dead
|
|
virtual bool isDead() const = 0;
|
|
// Returns a media version number for the object
|
|
virtual U32 getMediaVersion() const = 0;
|
|
// Returns whether the object is "interesting enough" to fetch
|
|
virtual bool isInterestingEnough() const = 0;
|
|
// Returns whether we've seen this object yet or not
|
|
virtual bool isNew() const = 0;
|
|
|
|
// smart pointer
|
|
typedef LLPointer<LLMediaDataClientObject> ptr_t;
|
|
};
|
|
|
|
|
|
// This object creates a priority queue for requests.
|
|
// Abstracts the Cap URL, the request, and the responder
|
|
class LLMediaDataClient : public LLRefCount
|
|
{
|
|
public:
|
|
LOG_CLASS(LLMediaDataClient);
|
|
|
|
const static F32 QUEUE_TIMER_DELAY;// = 1.0; // seconds(s)
|
|
const static F32 UNAVAILABLE_RETRY_TIMER_DELAY;// = 5.0; // secs
|
|
const static U32 MAX_RETRIES;// = 4;
|
|
const static U32 MAX_SORTED_QUEUE_SIZE;// = 10000;
|
|
const static U32 MAX_ROUND_ROBIN_QUEUE_SIZE;// = 10000;
|
|
|
|
// Constructor
|
|
LLMediaDataClient(F32 queue_timer_delay = QUEUE_TIMER_DELAY,
|
|
F32 retry_timer_delay = UNAVAILABLE_RETRY_TIMER_DELAY,
|
|
U32 max_retries = MAX_RETRIES,
|
|
U32 max_sorted_queue_size = MAX_SORTED_QUEUE_SIZE,
|
|
U32 max_round_robin_queue_size = MAX_ROUND_ROBIN_QUEUE_SIZE);
|
|
|
|
F32 getRetryTimerDelay() const { return mRetryTimerDelay; }
|
|
|
|
// Returns true iff the queue is empty
|
|
virtual bool isEmpty() const;
|
|
|
|
// Returns true iff the given object is in the queue
|
|
virtual bool isInQueue(const LLMediaDataClientObject::ptr_t &object);
|
|
|
|
// Remove the given object from the queue. Returns true iff the given object is removed.
|
|
virtual void removeFromQueue(const LLMediaDataClientObject::ptr_t &object);
|
|
|
|
// Called only by the Queue timer and tests (potentially)
|
|
virtual bool processQueueTimer();
|
|
|
|
protected:
|
|
// Destructor
|
|
virtual ~LLMediaDataClient(); // use unref
|
|
|
|
class Responder;
|
|
|
|
// Request (pure virtual base class for requests in the queue)
|
|
class Request : public LLRefCount
|
|
{
|
|
public:
|
|
// Subclasses must implement this to build a payload for their request type.
|
|
virtual LLSD getPayload() const = 0;
|
|
// and must create the correct type of responder.
|
|
virtual Responder *createResponder() = 0;
|
|
|
|
virtual std::string getURL() { return ""; }
|
|
|
|
enum Type {
|
|
GET,
|
|
UPDATE,
|
|
NAVIGATE,
|
|
ANY
|
|
};
|
|
|
|
protected:
|
|
// The only way to create one of these is through a subclass.
|
|
Request(Type in_type, LLMediaDataClientObject *obj, LLMediaDataClient *mdc, S32 face = -1);
|
|
public:
|
|
LLMediaDataClientObject *getObject() const { return mObject; }
|
|
|
|
U32 getNum() const { return mNum; }
|
|
U32 getRetryCount() const { return mRetryCount; }
|
|
void incRetryCount() { mRetryCount++; }
|
|
Type getType() const { return mType; }
|
|
F64 getScore() const { return mScore; }
|
|
|
|
// Note: may return empty string!
|
|
std::string getCapability() const;
|
|
const char *getCapName() const;
|
|
const char *getTypeAsString() const;
|
|
|
|
// Re-enqueue thyself
|
|
void reEnqueue();
|
|
|
|
F32 getRetryTimerDelay() const;
|
|
U32 getMaxNumRetries() const;
|
|
|
|
bool isObjectValid() const { return mObject.notNull() && (!mObject->isDead()); }
|
|
bool isNew() const { return isObjectValid() && mObject->isNew(); }
|
|
void updateScore();
|
|
|
|
void markDead();
|
|
bool isDead();
|
|
void startTracking();
|
|
void stopTracking();
|
|
|
|
friend std::ostream& operator<<(std::ostream &s, const Request &q);
|
|
|
|
const LLUUID &getID() const { return mObjectID; }
|
|
S32 getFace() const { return mFace; }
|
|
|
|
bool isMatch (const Request* other, Type match_type = ANY) const
|
|
{
|
|
return ((match_type == ANY) || (mType == other->mType)) &&
|
|
(mFace == other->mFace) &&
|
|
(mObjectID == other->mObjectID);
|
|
}
|
|
protected:
|
|
LLMediaDataClientObject::ptr_t mObject;
|
|
private:
|
|
Type mType;
|
|
// Simple tracking
|
|
U32 mNum;
|
|
static U32 sNum;
|
|
U32 mRetryCount;
|
|
F64 mScore;
|
|
|
|
LLUUID mObjectID;
|
|
S32 mFace;
|
|
|
|
// Back pointer to the MDC...not a ref!
|
|
LLMediaDataClient *mMDC;
|
|
};
|
|
typedef LLPointer<Request> request_ptr_t;
|
|
|
|
// Responder
|
|
class Responder : public LLHTTPClient::ResponderWithResult
|
|
{
|
|
public:
|
|
|
|
Responder(const request_ptr_t &request);
|
|
//If we get back an error (not found, etc...), handle it here
|
|
virtual void httpFailure(void);
|
|
//If we get back a normal response, handle it here. Default just logs it.
|
|
virtual void httpSuccess(void);
|
|
/*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return mediaDataClientResponder_timeout; }
|
|
/*virtual*/ char const* getName(void) const { return "LLMediaDataClientResponder"; }
|
|
|
|
request_ptr_t &getRequest() { return mRequest; }
|
|
|
|
private:
|
|
request_ptr_t mRequest;
|
|
};
|
|
|
|
class RetryTimer : public LLEventTimer
|
|
{
|
|
public:
|
|
RetryTimer(F32 time, request_ptr_t);
|
|
virtual BOOL tick();
|
|
private:
|
|
// back-pointer
|
|
request_ptr_t mRequest;
|
|
};
|
|
|
|
|
|
protected:
|
|
typedef std::list<request_ptr_t> request_queue_t;
|
|
typedef std::set<request_ptr_t> request_set_t;
|
|
|
|
// Subclasses must override to return a cap name
|
|
virtual const char *getCapabilityName() const = 0;
|
|
|
|
// Puts the request into a queue, appropriately handling duplicates, etc.
|
|
virtual void enqueue(Request*) = 0;
|
|
|
|
virtual void serviceQueue();
|
|
|
|
virtual request_queue_t *getQueue() { return &mQueue; };
|
|
|
|
// Gets the next request, removing it from the queue
|
|
virtual request_ptr_t dequeue();
|
|
|
|
virtual bool canServiceRequest(request_ptr_t request) { return true; };
|
|
|
|
// Returns a request to the head of the queue (should only be used for requests that came from dequeue
|
|
virtual void pushBack(request_ptr_t request);
|
|
|
|
void trackRequest(request_ptr_t request);
|
|
void stopTrackingRequest(request_ptr_t request);
|
|
|
|
request_queue_t mQueue;
|
|
|
|
const F32 mQueueTimerDelay;
|
|
const F32 mRetryTimerDelay;
|
|
const U32 mMaxNumRetries;
|
|
const U32 mMaxSortedQueueSize;
|
|
const U32 mMaxRoundRobinQueueSize;
|
|
|
|
// Set for keeping track of requests that aren't in either queue. This includes:
|
|
// Requests that have been sent and are awaiting a response (pointer held by the Responder)
|
|
// Requests that are waiting for their retry timers to fire (pointer held by the retry timer)
|
|
request_set_t mUnQueuedRequests;
|
|
|
|
void startQueueTimer();
|
|
void stopQueueTimer();
|
|
|
|
private:
|
|
|
|
static F64 getObjectScore(const LLMediaDataClientObject::ptr_t &obj);
|
|
|
|
friend std::ostream& operator<<(std::ostream &s, const Request &q);
|
|
friend std::ostream& operator<<(std::ostream &s, const request_queue_t &q);
|
|
|
|
class QueueTimer : public LLEventTimer
|
|
{
|
|
public:
|
|
QueueTimer(F32 time, LLMediaDataClient *mdc);
|
|
virtual BOOL tick();
|
|
private:
|
|
// back-pointer
|
|
LLPointer<LLMediaDataClient> mMDC;
|
|
};
|
|
|
|
void setIsRunning(bool val) { mQueueTimerIsRunning = val; }
|
|
|
|
bool mQueueTimerIsRunning;
|
|
|
|
template <typename T> friend typename T::iterator find_matching_request(T &c, const LLMediaDataClient::Request *request, LLMediaDataClient::Request::Type match_type);
|
|
template <typename T> friend typename T::iterator find_matching_request(T &c, const LLUUID &id, LLMediaDataClient::Request::Type match_type);
|
|
template <typename T> friend void remove_matching_requests(T &c, const LLUUID &id, LLMediaDataClient::Request::Type match_type);
|
|
|
|
};
|
|
|
|
// MediaDataClient specific for the ObjectMedia cap
|
|
class LLObjectMediaDataClient : public LLMediaDataClient
|
|
{
|
|
public:
|
|
LOG_CLASS(LLObjectMediaDataClient);
|
|
LLObjectMediaDataClient(F32 queue_timer_delay = QUEUE_TIMER_DELAY,
|
|
F32 retry_timer_delay = UNAVAILABLE_RETRY_TIMER_DELAY,
|
|
U32 max_retries = MAX_RETRIES,
|
|
U32 max_sorted_queue_size = MAX_SORTED_QUEUE_SIZE,
|
|
U32 max_round_robin_queue_size = MAX_ROUND_ROBIN_QUEUE_SIZE)
|
|
: LLMediaDataClient(queue_timer_delay, retry_timer_delay, max_retries),
|
|
mCurrentQueueIsTheSortedQueue(true)
|
|
{}
|
|
|
|
void fetchMedia(LLMediaDataClientObject *object);
|
|
void updateMedia(LLMediaDataClientObject *object);
|
|
|
|
class RequestGet: public Request
|
|
{
|
|
public:
|
|
RequestGet(LLMediaDataClientObject *obj, LLMediaDataClient *mdc);
|
|
/*virtual*/ LLSD getPayload() const;
|
|
/*virtual*/ Responder *createResponder();
|
|
};
|
|
|
|
class RequestUpdate: public Request
|
|
{
|
|
public:
|
|
RequestUpdate(LLMediaDataClientObject *obj, LLMediaDataClient *mdc);
|
|
/*virtual*/ LLSD getPayload() const;
|
|
/*virtual*/ Responder *createResponder();
|
|
};
|
|
|
|
// Returns true iff the queue is empty
|
|
virtual bool isEmpty() const;
|
|
|
|
// Returns true iff the given object is in the queue
|
|
virtual bool isInQueue(const LLMediaDataClientObject::ptr_t &object);
|
|
|
|
// Remove the given object from the queue. Returns true iff the given object is removed.
|
|
virtual void removeFromQueue(const LLMediaDataClientObject::ptr_t &object);
|
|
|
|
virtual bool processQueueTimer();
|
|
|
|
virtual bool canServiceRequest(request_ptr_t request);
|
|
|
|
protected:
|
|
// Subclasses must override to return a cap name
|
|
virtual const char *getCapabilityName() const;
|
|
|
|
virtual request_queue_t *getQueue();
|
|
|
|
// Puts the request into the appropriate queue
|
|
virtual void enqueue(Request*);
|
|
|
|
class Responder : public LLMediaDataClient::Responder
|
|
{
|
|
public:
|
|
Responder(const request_ptr_t &request)
|
|
: LLMediaDataClient::Responder(request) {}
|
|
virtual void httpSuccess(void);
|
|
};
|
|
private:
|
|
// The Get/Update data client needs a second queue to avoid object updates starving load-ins.
|
|
void swapCurrentQueue();
|
|
|
|
request_queue_t mRoundRobinQueue;
|
|
bool mCurrentQueueIsTheSortedQueue;
|
|
|
|
// Comparator for sorting
|
|
static bool compareRequestScores(const request_ptr_t &o1, const request_ptr_t &o2);
|
|
void sortQueue();
|
|
};
|
|
|
|
|
|
// MediaDataClient specific for the ObjectMediaNavigate cap
|
|
class LLObjectMediaNavigateClient : public LLMediaDataClient
|
|
{
|
|
public:
|
|
LOG_CLASS(LLObjectMediaNavigateClient);
|
|
// NOTE: from llmediaservice.h
|
|
static const int ERROR_PERMISSION_DENIED_CODE = 8002;
|
|
|
|
LLObjectMediaNavigateClient(F32 queue_timer_delay = QUEUE_TIMER_DELAY,
|
|
F32 retry_timer_delay = UNAVAILABLE_RETRY_TIMER_DELAY,
|
|
U32 max_retries = MAX_RETRIES,
|
|
U32 max_sorted_queue_size = MAX_SORTED_QUEUE_SIZE,
|
|
U32 max_round_robin_queue_size = MAX_ROUND_ROBIN_QUEUE_SIZE)
|
|
: LLMediaDataClient(queue_timer_delay, retry_timer_delay, max_retries)
|
|
{}
|
|
|
|
void navigate(LLMediaDataClientObject *object, U8 texture_index, const std::string &url);
|
|
|
|
// Puts the request into the appropriate queue
|
|
virtual void enqueue(Request*);
|
|
|
|
class RequestNavigate: public Request
|
|
{
|
|
public:
|
|
RequestNavigate(LLMediaDataClientObject *obj, LLMediaDataClient *mdc, U8 texture_index, const std::string &url);
|
|
/*virtual*/ LLSD getPayload() const;
|
|
/*virtual*/ Responder *createResponder();
|
|
/*virtual*/ std::string getURL() { return mURL; }
|
|
private:
|
|
std::string mURL;
|
|
};
|
|
|
|
protected:
|
|
// Subclasses must override to return a cap name
|
|
virtual const char *getCapabilityName() const;
|
|
|
|
class Responder : public LLMediaDataClient::Responder
|
|
{
|
|
public:
|
|
Responder(const request_ptr_t &request)
|
|
: LLMediaDataClient::Responder(request) {}
|
|
virtual void httpFailure(void);
|
|
virtual void httpSuccess(void);
|
|
private:
|
|
void mediaNavigateBounceBack();
|
|
};
|
|
|
|
};
|
|
|
|
|
|
#endif // LL_LLMEDIADATACLIENT_H
|