From 349eb393bc0666e323feff3b3a7eacab4f9bba84 Mon Sep 17 00:00:00 2001 From: Rick Pasetto Date: Mon, 5 Oct 2009 17:21:08 +0000 Subject: DEV-40650: Refactor llmediadataresponder and llmediadatafetcher into a single reusable class CC Review #7 (monroe) LLMediaDataResponder and LLMediaDataFetcher were helpful classes that interacted with each other, but they were not general enough to cleanly be used for all media service interaction. This change refactors these classes into one (in fact, it is closer to a complete rewrite): LLMediaDataClient. This class has the following design points: - You subclass from it when you want to specialize the responder, and then subclass from LLMediaDataClient::Responder if desired - It has a few inner classes: - LLMediaDataClient::Request, which now holds all of the data pertaining to a request, including retry counts - LLMediaDataClient::Responder, which is now the LLHTTPClient::Responder - LLMediaDataClient::PriorityQueue, which is now a STL priority_queue of Request objects. - LLMediaDataClient::QueueTimer, which is the timer that fires to peel off queue items - LLMediaDataClient::Responder::RetryTimer, which is the timer that is used when 503 errors are received. The encapsulation of these inner classes is a lot cleaner and better reflects the scope of their responsibilities. By and large, the logic hasn't really changed much. However, now there are two subclasses of LLMediaDataClient: one for the ObjectMedia cap and the other for the ObjectMediaNavigate cap. (I decided it was overkill to make three subclasses, one each for GET, UPDATE, and NAVIGATE, but we could still do that). LLVOVolume now instantiates both of these classes as statics (and destroys them on shutdown). They now have very simple API: - LLObjectMediaDataClient::fetchMedia(LLVOVolume*) fetches the media for the given object - LLObjectMediaDataClient::updateMedia(LLVOVolume*) sends an UPDATE of the media from the given object - LLObjectMediaNavigateClient::navigate(LLVOVolume*, U8 texture_index, const std::string &url) navigates the given face (texture_index) on the given object to the given url. --- indra/newview/llmediadataclient.h | 263 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 263 insertions(+) create mode 100755 indra/newview/llmediadataclient.h (limited to 'indra/newview/llmediadataclient.h') diff --git a/indra/newview/llmediadataclient.h b/indra/newview/llmediadataclient.h new file mode 100755 index 0000000000..59c4334251 --- /dev/null +++ b/indra/newview/llmediadataclient.h @@ -0,0 +1,263 @@ +/** + * @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 +#include "llrefcount.h" +#include "lltimer.h" + +// Forward decls +class LLVOVolume; + +typedef LLPointer ll_vo_volume_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 int QUEUE_TIMER_DELAY = 1; // seconds(s) + const static int MAX_RETRIES = 4; + + // Constructor + LLMediaDataClient(); + + // Make the request + void request(LLVOVolume *object, const LLSD &payload); + +protected: + // Destructor + virtual ~LLMediaDataClient(); // use unref + + // Request + class Request : public LLRefCount + { + public: + enum Type { + GET, + UPDATE, + NAVIGATE + }; + + Request(const std::string &cap_name, const LLSD& sd_payload, LLVOVolume *obj, LLMediaDataClient *mdc); + const std::string &getCapName() const { return mCapName; } + const LLSD &getPayload() const { return mPayload; } + LLVOVolume *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; + + public: + friend std::ostream& operator<<(std::ostream &s, const Request &q); + + protected: + virtual ~Request(); // use unref(); + + private: + std::string mCapName; + LLSD mPayload; + ll_vo_volume_ptr_t mObject; + // Simple tracking + const U32 mNum; + static U32 sNum; + U32 mRetryCount; + + // Back pointer to the MDC...not a ref! + LLMediaDataClient *mMDC; + }; + typedef LLPointer request_ptr_t; + + // Responder + class Responder : public LLHTTPClient::Responder + { + static const int UNAVAILABLE_RETRY_TIMER_DELAY = 5; // secs + + 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 mResponder; + }; + + request_ptr_t mRequest; + }; + +protected: + + void enqueue(const Request*); + + // 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; + +private: + + // Comparator for PriorityQueue + class Comparator + { + public: + bool operator() (const request_ptr_t &o1, const request_ptr_t &o2) const; + private: + static F64 getObjectScore(const ll_vo_volume_ptr_t &obj); + }; + + class PriorityQueue : public std::priority_queue< + request_ptr_t, + std::vector, + Comparator > + { + public: + friend std::ostream& operator<<(std::ostream &s, const PriorityQueue &q); + }; + + friend std::ostream& operator<<(std::ostream &s, const Request &q); + friend std::ostream& operator<<(std::ostream &s, const PriorityQueue &q); + + class QueueTimer : public LLEventTimer + { + public: + QueueTimer(F32 time, LLMediaDataClient *mdc); + virtual BOOL tick(); + protected: + virtual ~QueueTimer(); + private: + // back-pointer + LLPointer mMDC; + }; + + void startQueueTimer(); + void stopQueueTimer(); + void setIsRunning(bool val) { mQueueTimerIsRunning = val; } + + bool mQueueTimerIsRunning; + + PriorityQueue *pRequestQueue; +}; + + +// MediaDataResponder specific for the ObjectMedia cap +class LLObjectMediaDataClient : public LLMediaDataClient +{ +public: + LLObjectMediaDataClient() {} + ~LLObjectMediaDataClient() {} + + void fetchMedia(LLVOVolume *object); + void updateMedia(LLVOVolume *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); + }; +}; + + +// MediaDataResponder specific for the ObjectMediaNavigate cap +class LLObjectMediaNavigateClient : public LLMediaDataClient +{ + // NOTE: from llmediaservice.h + static const int ERROR_PERMISSION_DENIED_CODE = 8002; + +public: + LLObjectMediaNavigateClient() {} + ~LLObjectMediaNavigateClient() {} + + void navigate(LLVOVolume *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 bounceBack(); + }; + +}; + + +#endif // LL_LLMEDIADATACLIENT_H -- cgit v1.2.3