#pragma once #include #include #include #include #include #include "util/name.h" #include "rbx/boost.hpp" #include "rbx/rbxTime.h" #include "Util/contentid.h" #include "Util/HeartbeatInstance.h" #include "Util/LRUCache.h" #include "Util/ThreadPool.h" #include "Util/Http.h" #include "V8Tree/Service.h" LOGGROUP(HttpQueue) namespace RBX { class DataModel; class HttpQueueStatsItem; class AsyncHttpQueue : public boost::enable_shared_from_this , public boost::noncopyable { shared_ptr statsItem; public: typedef enum { Waiting, Succeeded, Failed } RequestResult; typedef enum { AsyncInline, AsyncNone, AsyncRead, AsyncWrite} ResultJob; typedef boost::function response, shared_ptr exception)> RequestCallback; struct CallbackWrapper { RequestCallback callback; ResultJob jobType; CallbackWrapper(RequestCallback callback, ResultJob jobType) :callback(callback) ,jobType(jobType) {} }; void setThreadPool(int count); void setCachePolicy(const HttpCache::Policy policy) { cachePolicy = policy; } bool isRequestQueueEmpty(); bool isUrlBad(const std::string& id); void asyncRequest(const std::string& id, float priority, RequestCallback* callback, ResultJob jobType, bool ignoreBadRequests=false, const std::string& expectedType = ""); bool syncRequest(const std::string& id, const std::string& expectedType = ""); static void dispatchGenericCallback(boost::function theCallback, Instance* instance, ResultJob jobType); static void dispatchCallback(RequestCallback theCallback, Instance* instance, RequestResult result, boost::shared_ptr data, ResultJob jobType, shared_ptr exception); AsyncHttpQueue(Instance* owner,boost::function getLocalFile, int threadCount); virtual ~AsyncHttpQueue(); void onHeartbeat(const Heartbeat& heartbeatEvent); int getRequestQueueSize() const; shared_ptr getFailedUrls(); shared_ptr getRequestQueueUrls(); void resetStatsItem(ServiceProvider* provider); double getAvgTimeInQueue() { return avgTimeInQueue.value(); } double getAvgRequestCompleteTime() { return avgRequestCompleteTime.value(); } int getNumSlowRequests() {return numSlowRequests;} protected: virtual void registerContent(const std::string& url, shared_ptr response, shared_ptr filename) {} struct Request { std::string url; std::vector callbacks; float priority; std::string expectedType; // used in header boost::shared_ptr http; // keep a handle so we can cancel. RBX::Time startTime; // the time when this request was issued bool operator==(const std::string& url) const { return this->url==url; } }; RunningAverage avgTimeInQueue; // in msec RunningAverage avgRequestCompleteTime; // in msec int numSlowRequests; struct FailedUrl { std::string url; RBX::Time expiration; FailedUrl(const char* url); bool expired() const; }; typedef std::list< Request > RequestList; typedef RequestList::iterator RequestHandle; struct AsyncRetryTask { double retryTime; RequestHandle request; AsyncRetryTask(RequestHandle request , double retryTime) :request(request), retryTime(retryTime) {} }; mutable boost::recursive_mutex requestSync; // synchronizes the requestQueue and failedUrls queue, and threadPool // also used to protect modification of the http shared pointer. RequestList requestQueue; // queue of requested URLs std::list< FailedUrl > failedUrls; // List of bad URLs boost::scoped_ptr threadPool; boost::recursive_mutex asyncRetrySync; std::queue asyncRetryTasks; double currentWallTime; static void processRequests(boost::weak_ptr httpQueue, RequestHandle request, boost::shared_ptr lock); void addAsyncRetryTask(RequestHandle request); Instance* owner; boost::function getLocalFile; HttpCache::Policy cachePolicy; }; }