/** * @file llmediadataclient.h * @brief class for queueing up requests to the media service * * $LicenseInfo:firstyear=2007&license=viewergpl$ * * Copyright (c) 2007-2009, Linden Research, Inc. * * Second Life Viewer Source Code * The source code in this file ("Source Code") is provided by Linden Lab * to you under the terms of the GNU General Public License, version 2.0 * ("GPL"), unless you have obtained a separate licensing agreement * ("Other License"), formally executed by you and Linden Lab. Terms of * the GPL can be found in doc/GPL-license.txt in this distribution, or * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 * * There are special exceptions to the terms and conditions of the GPL as * it is applied to this Source Code. View the full text of the exception * in the file doc/FLOSS-exception.txt in this software distribution, or * online at * http://secondlifegrid.net/programs/open_source/licensing/flossexception * * By copying, modifying or distributing this software, you acknowledge * that you have read and understood your obligations described above, * and agree to abide by those obligations. * * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, * COMPLETENESS OR PERFORMANCE. * $/LicenseInfo$ */ #ifndef LL_LLMEDIADATACLIENT_H #define LL_LLMEDIADATACLIENT_H #include "llhttpclient.h" #include <queue> #include "llrefcount.h" #include "llpointer.h" #include "lleventtimer.h" // 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; // 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); // Make the request void request(const LLMediaDataClientObject::ptr_t &object, const LLSD &payload); F32 getRetryTimerDelay() const { return mRetryTimerDelay; } // Returns true iff the queue is empty bool isEmpty() const; // Returns true iff the given object is in the queue bool isInQueue(const LLMediaDataClientObject::ptr_t &object); // Remove the given object from the queue. Returns true iff the given object is removed. bool removeFromQueue(const LLMediaDataClientObject::ptr_t &object); // Called only by the Queue timer and tests (potentially) bool processQueueTimer(); protected: // Destructor virtual ~LLMediaDataClient(); // use unref // Request class Request : public LLRefCount { public: enum Type { GET, UPDATE, NAVIGATE, ANY }; Request(const char *cap_name, const LLSD& sd_payload, LLMediaDataClientObject *obj, LLMediaDataClient *mdc); const char *getCapName() const { return mCapName; } const LLSD &getPayload() const { return mPayload; } LLMediaDataClientObject *getObject() const { return mObject; } U32 getNum() const { return mNum; } U32 getRetryCount() const { return mRetryCount; } void incRetryCount() { mRetryCount++; } // Note: may return empty string! std::string getCapability() const; Type getType() const; const char *getTypeAsString() const; // Re-enqueue thyself void reEnqueue() const; F32 getRetryTimerDelay() const; U32 getMaxNumRetries() const; bool isNew() const { return mObject.notNull() ? mObject->isNew() : false; } void markSent(bool flag); bool isMarkedSent() const { return mMarkedSent; } void updateScore(); F64 getScore() const { return mScore; } public: friend std::ostream& operator<<(std::ostream &s, const Request &q); protected: virtual ~Request(); // use unref(); private: const char *mCapName; LLSD mPayload; LLMediaDataClientObject::ptr_t mObject; // Simple tracking U32 mNum; static U32 sNum; U32 mRetryCount; F64 mScore; bool mMarkedSent; // Back pointer to the MDC...not a ref! LLMediaDataClient *mMDC; }; typedef LLPointer<Request> request_ptr_t; // Responder class Responder : public LLHTTPClient::Responder { public: Responder(const request_ptr_t &request); //If we get back an error (not found, etc...), handle it here virtual void error(U32 status, const std::string& reason); //If we get back a normal response, handle it here. Default just logs it. virtual void result(const LLSD& content); const request_ptr_t &getRequest() const { return mRequest; } protected: virtual ~Responder(); private: class RetryTimer : public LLEventTimer { public: RetryTimer(F32 time, Responder *); virtual ~RetryTimer(); virtual BOOL tick(); private: // back-pointer boost::intrusive_ptr<Responder> mResponder; }; request_ptr_t mRequest; }; protected: // Subclasses must override this factory method to return a new responder virtual Responder *createResponder(const request_ptr_t &request) const = 0; // Subclasses must override to return a cap name virtual const char *getCapabilityName() const = 0; virtual void sortQueue(); virtual void serviceQueue(); private: typedef std::list<request_ptr_t> request_queue_t; void enqueue(const Request*); // Return whether the given object is/was in the queue static LLMediaDataClient::request_ptr_t findOrRemove(request_queue_t &queue, const LLMediaDataClientObject::ptr_t &obj, bool remove, Request::Type type); // Comparator for sorting static bool compareRequests(const request_ptr_t &o1, const request_ptr_t &o2); 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(); protected: virtual ~QueueTimer(); private: // back-pointer LLPointer<LLMediaDataClient> mMDC; }; void startQueueTimer(); void stopQueueTimer(); void setIsRunning(bool val) { mQueueTimerIsRunning = val; } void swapCurrentQueue(); request_queue_t *getCurrentQueue(); const F32 mQueueTimerDelay; const F32 mRetryTimerDelay; const U32 mMaxNumRetries; const U32 mMaxSortedQueueSize; const U32 mMaxRoundRobinQueueSize; bool mQueueTimerIsRunning; request_queue_t mSortedQueue; request_queue_t mRoundRobinQueue; bool mCurrentQueueIsTheSortedQueue; }; // MediaDataClient specific for the ObjectMedia cap class LLObjectMediaDataClient : public LLMediaDataClient { public: 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) {} virtual ~LLObjectMediaDataClient() {} void fetchMedia(LLMediaDataClientObject *object); void updateMedia(LLMediaDataClientObject *object); protected: // Subclasses must override this factory method to return a new responder virtual Responder *createResponder(const request_ptr_t &request) const; // 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 result(const LLSD &content); }; }; // MediaDataClient specific for the ObjectMediaNavigate cap class LLObjectMediaNavigateClient : public LLMediaDataClient { public: // 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) {} virtual ~LLObjectMediaNavigateClient() {} void navigate(LLMediaDataClientObject *object, U8 texture_index, const std::string &url); protected: // Subclasses must override this factory method to return a new responder virtual Responder *createResponder(const request_ptr_t &request) const; // 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 error(U32 status, const std::string& reason); virtual void result(const LLSD &content); private: void mediaNavigateBounceBack(); }; }; #endif // LL_LLMEDIADATACLIENT_H