llmediadataclient.cpp
上传用户:king477883
上传日期:2021-03-01
资源大小:9553k
文件大小:25k
源码类别:

游戏引擎

开发平台:

C++ Builder

  1. /** 
  2.  * @file llmediadataclient.cpp
  3.  * @brief class for queueing up requests for media data
  4.  *
  5.  * $LicenseInfo:firstyear=2001&license=viewergpl$
  6.  * 
  7.  * Copyright (c) 2001-2010, Linden Research, Inc.
  8.  * 
  9.  * Second Life Viewer Source Code
  10.  * The source code in this file ("Source Code") is provided by Linden Lab
  11.  * to you under the terms of the GNU General Public License, version 2.0
  12.  * ("GPL"), unless you have obtained a separate licensing agreement
  13.  * ("Other License"), formally executed by you and Linden Lab.  Terms of
  14.  * the GPL can be found in doc/GPL-license.txt in this distribution, or
  15.  * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  16.  * 
  17.  * There are special exceptions to the terms and conditions of the GPL as
  18.  * it is applied to this Source Code. View the full text of the exception
  19.  * in the file doc/FLOSS-exception.txt in this software distribution, or
  20.  * online at
  21.  * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  22.  * 
  23.  * By copying, modifying or distributing this software, you acknowledge
  24.  * that you have read and understood your obligations described above,
  25.  * and agree to abide by those obligations.
  26.  * 
  27.  * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  28.  * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  29.  * COMPLETENESS OR PERFORMANCE.
  30.  * $/LicenseInfo$
  31.  */
  32. #include "llviewerprecompiledheaders.h"
  33. #include "llmediadataclient.h"
  34. #if LL_MSVC
  35. // disable boost::lexical_cast warning
  36. #pragma warning (disable:4702)
  37. #endif
  38. #include <boost/lexical_cast.hpp>
  39. #include "llhttpstatuscodes.h"
  40. #include "llsdutil.h"
  41. #include "llmediaentry.h"
  42. #include "lltextureentry.h"
  43. #include "llviewerregion.h"
  44. //
  45. // When making a request
  46. // - obtain the "overall interest score" of the object.  
  47. //  This would be the sum of the impls' interest scores.
  48. // - put the request onto a queue sorted by this score 
  49. //  (highest score at the front of the queue)
  50. // - On a timer, once a second, pull off the head of the queue and send 
  51. //  the request.
  52. // - Any request that gets a 503 still goes through the retry logic
  53. //
  54. //
  55. // Forward decls
  56. //
  57. const F32 LLMediaDataClient::QUEUE_TIMER_DELAY = 1.0; // seconds(s)
  58. const F32 LLMediaDataClient::UNAVAILABLE_RETRY_TIMER_DELAY = 5.0; // secs
  59. const U32 LLMediaDataClient::MAX_RETRIES = 4;
  60. const U32 LLMediaDataClient::MAX_SORTED_QUEUE_SIZE = 10000;
  61. const U32 LLMediaDataClient::MAX_ROUND_ROBIN_QUEUE_SIZE = 10000;
  62. // << operators
  63. std::ostream& operator<<(std::ostream &s, const LLMediaDataClient::request_queue_t &q);
  64. std::ostream& operator<<(std::ostream &s, const LLMediaDataClient::Request &q);
  65. //////////////////////////////////////////////////////////////////////////////////////
  66. //
  67. // LLMediaDataClient
  68. //
  69. //////////////////////////////////////////////////////////////////////////////////////
  70. LLMediaDataClient::LLMediaDataClient(F32 queue_timer_delay,
  71.  F32 retry_timer_delay,
  72.  U32 max_retries,
  73.  U32 max_sorted_queue_size,
  74.  U32 max_round_robin_queue_size)
  75. : mQueueTimerDelay(queue_timer_delay),
  76.   mRetryTimerDelay(retry_timer_delay),
  77.   mMaxNumRetries(max_retries),
  78.   mMaxSortedQueueSize(max_sorted_queue_size),
  79.   mMaxRoundRobinQueueSize(max_round_robin_queue_size),
  80.   mQueueTimerIsRunning(false),
  81.   mCurrentQueueIsTheSortedQueue(true)
  82. {
  83. }
  84. LLMediaDataClient::~LLMediaDataClient()
  85. {
  86. stopQueueTimer();
  87. // This should clear the queue, and hopefully call all the destructors.
  88. LL_DEBUGS("LLMediaDataClient") << "~LLMediaDataClient destructor: queue: " << 
  89. (isEmpty() ? "<empty> " : "<not empty> ") << LL_ENDL;
  90. mSortedQueue.clear();
  91. mRoundRobinQueue.clear();
  92. }
  93. bool LLMediaDataClient::isEmpty() const
  94. {
  95. return mSortedQueue.empty() && mRoundRobinQueue.empty();
  96. }
  97. bool LLMediaDataClient::isInQueue(const LLMediaDataClientObject::ptr_t &object)
  98. {
  99. return (LLMediaDataClient::findOrRemove(mSortedQueue, object, false/*remove*/, LLMediaDataClient::Request::ANY).notNull()
  100. || (LLMediaDataClient::findOrRemove(mRoundRobinQueue, object, false/*remove*/, LLMediaDataClient::Request::ANY).notNull()));
  101. }
  102. bool LLMediaDataClient::removeFromQueue(const LLMediaDataClientObject::ptr_t &object)
  103. {
  104. bool removedFromSortedQueue = LLMediaDataClient::findOrRemove(mSortedQueue, object, true/*remove*/, LLMediaDataClient::Request::ANY).notNull();
  105. bool removedFromRoundRobinQueue = LLMediaDataClient::findOrRemove(mRoundRobinQueue, object, true/*remove*/, LLMediaDataClient::Request::ANY).notNull();
  106. return removedFromSortedQueue || removedFromRoundRobinQueue;
  107. }
  108. //static
  109. LLMediaDataClient::request_ptr_t LLMediaDataClient::findOrRemove(request_queue_t &queue, const LLMediaDataClientObject::ptr_t &obj, bool remove, LLMediaDataClient::Request::Type type)
  110. {
  111. request_ptr_t result;
  112. request_queue_t::iterator iter = queue.begin();
  113. request_queue_t::iterator end = queue.end();
  114. while (iter != end)
  115. {
  116. if (obj->getID() == (*iter)->getObject()->getID() && (type == LLMediaDataClient::Request::ANY || type == (*iter)->getType()))
  117. {
  118. result = *iter;
  119. if (remove) queue.erase(iter);
  120. break;
  121. }
  122. iter++;
  123. }
  124. return result;
  125. }
  126. void LLMediaDataClient::request(const LLMediaDataClientObject::ptr_t &object, const LLSD &payload)
  127. {
  128. if (object.isNull() || ! object->hasMedia()) return; 
  129. // Push the object on the queue
  130. enqueue(new Request(getCapabilityName(), payload, object, this));
  131. }
  132. void LLMediaDataClient::enqueue(const Request *request)
  133. {
  134. if (request->isNew())
  135. {
  136. // Add to sorted queue
  137. if (LLMediaDataClient::findOrRemove(mSortedQueue, request->getObject(), true/*remove*/, request->getType()).notNull())
  138. {
  139. LL_DEBUGS("LLMediaDataClient") << "REMOVING OLD request for " << *request << " ALREADY THERE!" << LL_ENDL;
  140. }
  141. LL_DEBUGS("LLMediaDataClient") << "Queuing SORTED request for " << *request << LL_ENDL;
  142. // Sadly, we have to const-cast because items put into the queue are not const
  143. mSortedQueue.push_back(const_cast<LLMediaDataClient::Request*>(request));
  144. LL_DEBUGS("LLMediaDataClientQueue") << "SORTED queue:" << mSortedQueue << LL_ENDL;
  145. }
  146. else {
  147. if (mRoundRobinQueue.size() > mMaxRoundRobinQueueSize) 
  148. {
  149. LL_INFOS_ONCE("LLMediaDataClient") << "RR QUEUE MAXED OUT!!!" << LL_ENDL;
  150. LL_DEBUGS("LLMediaDataClient") << "Not queuing " << *request << LL_ENDL;
  151. return;
  152. }
  153. // ROUND ROBIN: if it is there, and it is a GET request, leave it.  If not, put at front!
  154. request_ptr_t existing_request;
  155. if (request->getType() == Request::GET)
  156. {
  157. existing_request = LLMediaDataClient::findOrRemove(mRoundRobinQueue, request->getObject(), false/*remove*/, request->getType());
  158. }
  159. if (existing_request.isNull())
  160. {
  161. LL_DEBUGS("LLMediaDataClient") << "Queuing RR request for " << *request << LL_ENDL;
  162. // Push the request on the pending queue
  163. // Sadly, we have to const-cast because items put into the queue are not const
  164. mRoundRobinQueue.push_front(const_cast<LLMediaDataClient::Request*>(request));
  165. LL_DEBUGS("LLMediaDataClientQueue") << "RR queue:" << mRoundRobinQueue << LL_ENDL;
  166. }
  167. else
  168. {
  169. LL_DEBUGS("LLMediaDataClient") << "ALREADY THERE: NOT Queuing request for " << *request << LL_ENDL;
  170. existing_request->markSent(false);
  171. }
  172. }
  173. // Start the timer if not already running
  174. startQueueTimer();
  175. }
  176. void LLMediaDataClient::startQueueTimer() 
  177. {
  178. if (! mQueueTimerIsRunning)
  179. {
  180. LL_DEBUGS("LLMediaDataClient") << "starting queue timer (delay=" << mQueueTimerDelay << " seconds)" << LL_ENDL;
  181. // LLEventTimer automagically takes care of the lifetime of this object
  182. new QueueTimer(mQueueTimerDelay, this);
  183. }
  184. else { 
  185. LL_DEBUGS("LLMediaDataClient") << "not starting queue timer (it's already running, right???)" << LL_ENDL;
  186. }
  187. }
  188. void LLMediaDataClient::stopQueueTimer()
  189. {
  190. mQueueTimerIsRunning = false;
  191. }
  192. bool LLMediaDataClient::processQueueTimer()
  193. {
  194. sortQueue();
  195. if(!isEmpty())
  196. {
  197. LL_DEBUGS("LLMediaDataClient") << "QueueTimer::tick() started, SORTED queue size is:   " << mSortedQueue.size() 
  198. << ", RR queue size is:   " << mRoundRobinQueue.size() << LL_ENDL;
  199. LL_DEBUGS("LLMediaDataClientQueue") << "QueueTimer::tick() started, SORTED queue is:   " << mSortedQueue << LL_ENDL;
  200. LL_DEBUGS("LLMediaDataClientQueue") << "QueueTimer::tick() started, RR queue is:   " << mRoundRobinQueue << LL_ENDL;
  201. }
  202. serviceQueue();
  203. LL_DEBUGS("LLMediaDataClient") << "QueueTimer::tick() finished, SORTED queue size is:   " << mSortedQueue.size() 
  204. << ", RR queue size is:   " << mRoundRobinQueue.size() << LL_ENDL;
  205. LL_DEBUGS("LLMediaDataClientQueue") << "QueueTimer::tick() finished, SORTED queue is:   " << mSortedQueue << LL_ENDL;
  206. LL_DEBUGS("LLMediaDataClientQueue") << "QueueTimer::tick() finished, RR queue is:   " << mRoundRobinQueue << LL_ENDL;
  207. return isEmpty();
  208. }
  209. void LLMediaDataClient::sortQueue()
  210. {
  211. if(!mSortedQueue.empty())
  212. {
  213. // Score all items first
  214. request_queue_t::iterator iter = mSortedQueue.begin();
  215. request_queue_t::iterator end = mSortedQueue.end();
  216. while (iter != end)
  217. {
  218. (*iter)->updateScore();
  219. iter++;
  220. }
  221. // Re-sort the list...
  222. // NOTE: should this be a stable_sort?  If so we need to change to using a vector.
  223. mSortedQueue.sort(LLMediaDataClient::compareRequests);
  224. // ...then cull items over the max
  225. U32 size = mSortedQueue.size();
  226. if (size > mMaxSortedQueueSize) 
  227. {
  228. U32 num_to_cull = (size - mMaxSortedQueueSize);
  229. LL_INFOS_ONCE("LLMediaDataClient") << "sorted queue MAXED OUT!  Culling " 
  230. << num_to_cull << " items" << LL_ENDL;
  231. while (num_to_cull-- > 0)
  232. {
  233. mSortedQueue.pop_back();
  234. }
  235. }
  236. }
  237. }
  238. // static
  239. bool LLMediaDataClient::compareRequests(const request_ptr_t &o1, const request_ptr_t &o2)
  240. {
  241. if (o2.isNull()) return true;
  242. if (o1.isNull()) return false;
  243. return ( o1->getScore() > o2->getScore() );
  244. }
  245. void LLMediaDataClient::serviceQueue()
  246. {
  247. request_queue_t *queue_p = getCurrentQueue();
  248. // quick retry loop for cases where we shouldn't wait for the next timer tick
  249. while(true)
  250. {
  251. if (queue_p->empty())
  252. {
  253. LL_DEBUGS("LLMediaDataClient") << "queue empty: " << (*queue_p) << LL_ENDL;
  254. break;
  255. }
  256. // Peel one off of the items from the queue, and execute request
  257. request_ptr_t request = queue_p->front();
  258. llassert(!request.isNull());
  259. const LLMediaDataClientObject *object = (request.isNull()) ? NULL : request->getObject();
  260. llassert(NULL != object);
  261. // Check for conditions that would make us just pop and rapidly loop through
  262. // the queue.
  263. if(request.isNull() ||
  264.    request->isMarkedSent() ||
  265.    NULL == object ||
  266.    object->isDead() ||
  267.    !object->hasMedia())
  268. {
  269. if (request.isNull()) 
  270. {
  271. LL_WARNS("LLMediaDataClient") << "Skipping NULL request" << LL_ENDL;
  272. }
  273. else {
  274. LL_INFOS("LLMediaDataClient") << "Skipping : " << *request << " " 
  275. << ((request->isMarkedSent()) ? " request is marked sent" :
  276. ((NULL == object) ? " object is NULL " :
  277.  ((object->isDead()) ? "object is dead" : 
  278.   ((!object->hasMedia()) ? "object has no media!" : "BADNESS!")))) << LL_ENDL;
  279. }
  280. queue_p->pop_front();
  281. continue; // jump back to the start of the quick retry loop
  282. }
  283. // Next, ask if this is "interesting enough" to fetch.  If not, just stop
  284. // and wait for the next timer go-round.  Only do this for the sorted 
  285. // queue.
  286. if (mCurrentQueueIsTheSortedQueue && !object->isInterestingEnough())
  287. {
  288. LL_DEBUGS("LLMediaDataClient") << "Not fetching " << *request << ": not interesting enough" << LL_ENDL;
  289. break;
  290. }
  291. // Finally, try to send the HTTP message to the cap url
  292. std::string url = request->getCapability();
  293. bool maybe_retry = false;
  294. if (!url.empty())
  295. {
  296. const LLSD &sd_payload = request->getPayload();
  297. LL_INFOS("LLMediaDataClient") << "Sending request for " << *request << LL_ENDL;
  298. // Call the subclass for creating the responder
  299. LLHTTPClient::post(url, sd_payload, createResponder(request));
  300. }
  301. else {
  302. LL_INFOS("LLMediaDataClient") << "NOT Sending request for " << *request << ": empty cap url!" << LL_ENDL;
  303. maybe_retry = true;
  304. }
  305. bool exceeded_retries = request->getRetryCount() > mMaxNumRetries;
  306. if (maybe_retry && ! exceeded_retries) // Try N times before giving up 
  307. {
  308. // We got an empty cap, but in that case we will retry again next
  309. // timer fire.
  310. request->incRetryCount();
  311. }
  312. else {
  313. if (exceeded_retries)
  314. {
  315. LL_WARNS("LLMediaDataClient") << "Could not send request " << *request << " for " 
  316. << mMaxNumRetries << " tries...popping object id " << object->getID() << LL_ENDL; 
  317. // XXX Should we bring up a warning dialog??
  318. }
  319. queue_p->pop_front();
  320. if (! mCurrentQueueIsTheSortedQueue) {
  321. // Round robin
  322. request->markSent(true);
  323. mRoundRobinQueue.push_back(request);
  324. }
  325. }
  326.   // end of quick loop -- any cases where we want to loop will use 'continue' to jump back to the start.
  327.   break;
  328. }
  329. swapCurrentQueue();
  330. }
  331. void LLMediaDataClient::swapCurrentQueue()
  332. {
  333. // Swap
  334. mCurrentQueueIsTheSortedQueue = !mCurrentQueueIsTheSortedQueue;
  335. // If its empty, swap back
  336. if (getCurrentQueue()->empty()) 
  337. {
  338. mCurrentQueueIsTheSortedQueue = !mCurrentQueueIsTheSortedQueue;
  339. }
  340. }
  341. LLMediaDataClient::request_queue_t *LLMediaDataClient::getCurrentQueue()
  342. {
  343. return (mCurrentQueueIsTheSortedQueue) ? &mSortedQueue : &mRoundRobinQueue;
  344. }
  345. // dump the queue
  346. std::ostream& operator<<(std::ostream &s, const LLMediaDataClient::request_queue_t &q)
  347. {
  348. int i = 0;
  349. LLMediaDataClient::request_queue_t::const_iterator iter = q.begin();
  350. LLMediaDataClient::request_queue_t::const_iterator end = q.end();
  351. while (iter != end)
  352. {
  353. s << "t" << i << "]: " << (*iter)->getObject()->getID().asString() << "(" << (*iter)->getObject()->getMediaInterest() << ")";
  354. iter++;
  355. i++;
  356. }
  357. return s;
  358. }
  359. //////////////////////////////////////////////////////////////////////////////////////
  360. //
  361. // LLMediaDataClient::QueueTimer
  362. // Queue of LLMediaDataClientObject smart pointers to request media for.
  363. //
  364. //////////////////////////////////////////////////////////////////////////////////////
  365. LLMediaDataClient::QueueTimer::QueueTimer(F32 time, LLMediaDataClient *mdc)
  366. : LLEventTimer(time), mMDC(mdc)
  367. {
  368. mMDC->setIsRunning(true);
  369. }
  370. LLMediaDataClient::QueueTimer::~QueueTimer()
  371. {
  372. LL_DEBUGS("LLMediaDataClient") << "~QueueTimer" << LL_ENDL;
  373. mMDC->setIsRunning(false);
  374. mMDC = NULL;
  375. }
  376. // virtual
  377. BOOL LLMediaDataClient::QueueTimer::tick()
  378. {
  379. if (mMDC.isNull()) return TRUE;
  380. return mMDC->processQueueTimer();
  381. }
  382. //////////////////////////////////////////////////////////////////////////////////////
  383. //
  384. // LLMediaDataClient::Responder::RetryTimer
  385. //
  386. //////////////////////////////////////////////////////////////////////////////////////
  387. LLMediaDataClient::Responder::RetryTimer::RetryTimer(F32 time, Responder *mdr)
  388. : LLEventTimer(time), mResponder(mdr)
  389. {
  390. }
  391. // virtual 
  392. LLMediaDataClient::Responder::RetryTimer::~RetryTimer() 
  393. {
  394. LL_DEBUGS("LLMediaDataClient") << "~RetryTimer" << *(mResponder->getRequest()) << LL_ENDL;
  395. // XXX This is weird: Instead of doing the work in tick()  (which re-schedules
  396. // a timer, which might be risky), do it here, in the destructor.  Yes, it is very odd.
  397. // Instead of retrying, we just put the request back onto the queue
  398. LL_INFOS("LLMediaDataClient") << "RetryTimer fired for: " << *(mResponder->getRequest()) << " retrying" << LL_ENDL;
  399. mResponder->getRequest()->reEnqueue();
  400. // Release the ref to the responder.
  401. mResponder = NULL;
  402. }
  403. // virtual
  404. BOOL LLMediaDataClient::Responder::RetryTimer::tick()
  405. {
  406. // Don't fire again
  407. return TRUE;
  408. }
  409. //////////////////////////////////////////////////////////////////////////////////////
  410. //
  411. // LLMediaDataClient::Request
  412. //
  413. //////////////////////////////////////////////////////////////////////////////////////
  414. /*static*/U32 LLMediaDataClient::Request::sNum = 0;
  415. LLMediaDataClient::Request::Request(const char *cap_name, 
  416. const LLSD& sd_payload,
  417. LLMediaDataClientObject *obj, 
  418. LLMediaDataClient *mdc)
  419. : mCapName(cap_name), 
  420.   mPayload(sd_payload), 
  421.   mObject(obj),
  422.   mNum(++sNum), 
  423.   mRetryCount(0),
  424.   mMDC(mdc),
  425.   mMarkedSent(false),
  426.   mScore((F64)0.0)
  427. {
  428. }
  429. LLMediaDataClient::Request::~Request()
  430. {
  431. LL_DEBUGS("LLMediaDataClient") << "~Request" << (*this) << LL_ENDL;
  432. mMDC = NULL;
  433. mObject = NULL;
  434. }
  435. std::string LLMediaDataClient::Request::getCapability() const
  436. {
  437. return getObject()->getCapabilityUrl(getCapName());
  438. }
  439. // Helper function to get the "type" of request, which just pokes around to
  440. // discover it.
  441. LLMediaDataClient::Request::Type LLMediaDataClient::Request::getType() const
  442. {
  443. if (0 == strcmp(mCapName, "ObjectMediaNavigate"))
  444. {
  445. return NAVIGATE;
  446. }
  447. else if (0 == strcmp(mCapName, "ObjectMedia"))
  448. {
  449. const std::string &verb = mPayload["verb"];
  450. if (verb == "GET")
  451. {
  452. return GET;
  453. }
  454. else if (verb == "UPDATE")
  455. {
  456. return UPDATE;
  457. }
  458. }
  459. llassert(false);
  460. return GET;
  461. }
  462. const char *LLMediaDataClient::Request::getTypeAsString() const
  463. {
  464. Type t = getType();
  465. switch (t)
  466. {
  467. case GET:
  468. return "GET";
  469. break;
  470. case UPDATE:
  471. return "UPDATE";
  472. break;
  473. case NAVIGATE:
  474. return "NAVIGATE";
  475. break;
  476. case ANY:
  477. return "ANY";
  478. break;
  479. }
  480. return "";
  481. }
  482. void LLMediaDataClient::Request::reEnqueue() const
  483. {
  484. // I sure hope this doesn't deref a bad pointer:
  485. mMDC->enqueue(this);
  486. }
  487. F32 LLMediaDataClient::Request::getRetryTimerDelay() const
  488. {
  489. return (mMDC == NULL) ? LLMediaDataClient::UNAVAILABLE_RETRY_TIMER_DELAY :
  490. mMDC->mRetryTimerDelay; 
  491. }
  492. U32 LLMediaDataClient::Request::getMaxNumRetries() const
  493. {
  494. return (mMDC == NULL) ? LLMediaDataClient::MAX_RETRIES : mMDC->mMaxNumRetries;
  495. }
  496. void LLMediaDataClient::Request::markSent(bool flag)
  497. {
  498.  if (mMarkedSent != flag)
  499.  {
  500.  mMarkedSent = flag;
  501.  if (!mMarkedSent)
  502.  {
  503.  mNum = ++sNum;
  504.  }
  505.  }
  506. }
  507.    
  508. void LLMediaDataClient::Request::updateScore()
  509. {
  510. F64 tmp = mObject->getMediaInterest();
  511. if (tmp != mScore)
  512. {
  513. LL_DEBUGS("LLMediaDataClient") << "Score for " << mObject->getID() << " changed from " << mScore << " to " << tmp << LL_ENDL; 
  514. mScore = tmp;
  515. }
  516. }
  517.    
  518. std::ostream& operator<<(std::ostream &s, const LLMediaDataClient::Request &r)
  519. {
  520. s << "request: num=" << r.getNum() 
  521. << " type=" << r.getTypeAsString() 
  522. << " ID=" << r.getObject()->getID() 
  523. << " #retries=" << r.getRetryCount();
  524. return s;
  525. }
  526. //////////////////////////////////////////////////////////////////////////////////////
  527. //
  528. // LLMediaDataClient::Responder
  529. //
  530. //////////////////////////////////////////////////////////////////////////////////////
  531. LLMediaDataClient::Responder::Responder(const request_ptr_t &request)
  532. : mRequest(request)
  533. {
  534. }
  535. LLMediaDataClient::Responder::~Responder()
  536. {
  537. LL_DEBUGS("LLMediaDataClient") << "~Responder" << *(getRequest()) << LL_ENDL;
  538. mRequest = NULL;
  539. }
  540. /*virtual*/
  541. void LLMediaDataClient::Responder::error(U32 status, const std::string& reason)
  542. {
  543. if (status == HTTP_SERVICE_UNAVAILABLE)
  544. {
  545. F32 retry_timeout = mRequest->getRetryTimerDelay();
  546. mRequest->incRetryCount();
  547. if (mRequest->getRetryCount() < mRequest->getMaxNumRetries()) 
  548. {
  549. LL_INFOS("LLMediaDataClient") << *mRequest << " got SERVICE_UNAVAILABLE...retrying in " << retry_timeout << " seconds" << LL_ENDL;
  550. // Start timer (instances are automagically tracked by
  551. // InstanceTracker<> and LLEventTimer)
  552. new RetryTimer(F32(retry_timeout/*secs*/), this);
  553. }
  554. else {
  555. LL_INFOS("LLMediaDataClient") << *mRequest << " got SERVICE_UNAVAILABLE...retry count " 
  556. << mRequest->getRetryCount() << " exceeds " << mRequest->getMaxNumRetries() << ", not retrying" << LL_ENDL;
  557. }
  558. }
  559. else {
  560. std::string msg = boost::lexical_cast<std::string>(status) + ": " + reason;
  561. LL_WARNS("LLMediaDataClient") << *mRequest << " http error(" << msg << ")" << LL_ENDL;
  562. }
  563. }
  564. /*virtual*/
  565. void LLMediaDataClient::Responder::result(const LLSD& content)
  566. {
  567. LL_DEBUGS("LLMediaDataClientResponse") << *mRequest << " result : " << ll_print_sd(content) << LL_ENDL;
  568. }
  569. //////////////////////////////////////////////////////////////////////////////////////
  570. //
  571. // LLObjectMediaDataClient
  572. // Subclass of LLMediaDataClient for the ObjectMedia cap
  573. //
  574. //////////////////////////////////////////////////////////////////////////////////////
  575. LLMediaDataClient::Responder *LLObjectMediaDataClient::createResponder(const request_ptr_t &request) const
  576. {
  577. return new LLObjectMediaDataClient::Responder(request);
  578. }
  579. const char *LLObjectMediaDataClient::getCapabilityName() const 
  580. {
  581. return "ObjectMedia";
  582. }
  583. void LLObjectMediaDataClient::fetchMedia(LLMediaDataClientObject *object)
  584. {
  585. LLSD sd_payload;
  586. sd_payload["verb"] = "GET";
  587. sd_payload[LLTextureEntry::OBJECT_ID_KEY] = object->getID();
  588. request(object, sd_payload);
  589. }
  590. void LLObjectMediaDataClient::updateMedia(LLMediaDataClientObject *object)
  591. {
  592. LLSD sd_payload;
  593. sd_payload["verb"] = "UPDATE";
  594. sd_payload[LLTextureEntry::OBJECT_ID_KEY] = object->getID();
  595. LLSD object_media_data;
  596. int i = 0;
  597. int end = object->getMediaDataCount();
  598. for ( ; i < end ; ++i) 
  599. {
  600. object_media_data.append(object->getMediaDataLLSD(i));
  601. }
  602. sd_payload[LLTextureEntry::OBJECT_MEDIA_DATA_KEY] = object_media_data;
  603. LL_DEBUGS("LLMediaDataClient") << "update media data: " << object->getID() << " " << ll_print_sd(sd_payload) << LL_ENDL;
  604. request(object, sd_payload);
  605. }
  606. /*virtual*/
  607. void LLObjectMediaDataClient::Responder::result(const LLSD& content)
  608. {
  609. const LLMediaDataClient::Request::Type type = getRequest()->getType();
  610. llassert(type == LLMediaDataClient::Request::GET || type == LLMediaDataClient::Request::UPDATE)
  611. if (type == LLMediaDataClient::Request::GET)
  612. {
  613. LL_DEBUGS("LLMediaDataClientResponse") << *(getRequest()) << " GET returned: " << ll_print_sd(content) << LL_ENDL;
  614. // Look for an error
  615. if (content.has("error"))
  616. {
  617. const LLSD &error = content["error"];
  618. LL_WARNS("LLMediaDataClient") << *(getRequest()) << " Error getting media data for object: code=" << 
  619. error["code"].asString() << ": " << error["message"].asString() << LL_ENDL;
  620. // XXX Warn user?
  621. }
  622. else {
  623. // Check the data
  624. const LLUUID &object_id = content[LLTextureEntry::OBJECT_ID_KEY];
  625. if (object_id != getRequest()->getObject()->getID()) 
  626. {
  627. // NOT good, wrong object id!!
  628. LL_WARNS("LLMediaDataClient") << *(getRequest()) << " DROPPING response with wrong object id (" << object_id << ")" << LL_ENDL;
  629. return;
  630. }
  631. // Otherwise, update with object media data
  632. getRequest()->getObject()->updateObjectMediaData(content[LLTextureEntry::OBJECT_MEDIA_DATA_KEY],
  633.  content[LLTextureEntry::MEDIA_VERSION_KEY]);
  634. }
  635. }
  636. else if (type == LLMediaDataClient::Request::UPDATE)
  637. {
  638. // just do what our superclass does
  639. LLMediaDataClient::Responder::result(content);
  640. }
  641. }
  642. //////////////////////////////////////////////////////////////////////////////////////
  643. //
  644. // LLObjectMediaNavigateClient
  645. // Subclass of LLMediaDataClient for the ObjectMediaNavigate cap
  646. //
  647. //////////////////////////////////////////////////////////////////////////////////////
  648. LLMediaDataClient::Responder *LLObjectMediaNavigateClient::createResponder(const request_ptr_t &request) const
  649. {
  650. return new LLObjectMediaNavigateClient::Responder(request);
  651. }
  652. const char *LLObjectMediaNavigateClient::getCapabilityName() const 
  653. {
  654. return "ObjectMediaNavigate";
  655. }
  656. void LLObjectMediaNavigateClient::navigate(LLMediaDataClientObject *object, U8 texture_index, const std::string &url)
  657. {
  658. LLSD sd_payload;
  659. sd_payload[LLTextureEntry::OBJECT_ID_KEY] = object->getID();
  660. sd_payload[LLMediaEntry::CURRENT_URL_KEY] = url;
  661. sd_payload[LLTextureEntry::TEXTURE_INDEX_KEY] = (LLSD::Integer)texture_index;
  662. LL_INFOS("LLMediaDataClient") << "navigate() initiated: " << ll_print_sd(sd_payload) << LL_ENDL;
  663. request(object, sd_payload);
  664. }
  665. /*virtual*/
  666. void LLObjectMediaNavigateClient::Responder::error(U32 status, const std::string& reason)
  667. {
  668. // Bounce back (unless HTTP_SERVICE_UNAVAILABLE, in which case call base
  669. // class
  670. if (status == HTTP_SERVICE_UNAVAILABLE)
  671. {
  672. LLMediaDataClient::Responder::error(status, reason);
  673. }
  674. else {
  675. // bounce the face back
  676. LL_WARNS("LLMediaDataClient") << *(getRequest()) << " Error navigating: http code=" << status << LL_ENDL;
  677. const LLSD &payload = getRequest()->getPayload();
  678. // bounce the face back
  679. getRequest()->getObject()->mediaNavigateBounceBack((LLSD::Integer)payload[LLTextureEntry::TEXTURE_INDEX_KEY]);
  680. }
  681. }
  682. /*virtual*/
  683. void LLObjectMediaNavigateClient::Responder::result(const LLSD& content)
  684. {
  685. LL_INFOS("LLMediaDataClient") << *(getRequest()) << " NAVIGATE returned " << ll_print_sd(content) << LL_ENDL;
  686. if (content.has("error"))
  687. {
  688. const LLSD &error = content["error"];
  689. int error_code = error["code"];
  690. if (ERROR_PERMISSION_DENIED_CODE == error_code)
  691. {
  692. LL_WARNS("LLMediaDataClient") << *(getRequest()) << " Navigation denied: bounce back" << LL_ENDL;
  693. const LLSD &payload = getRequest()->getPayload();
  694. // bounce the face back
  695. getRequest()->getObject()->mediaNavigateBounceBack((LLSD::Integer)payload[LLTextureEntry::TEXTURE_INDEX_KEY]);
  696. }
  697. else {
  698. LL_WARNS("LLMediaDataClient") << *(getRequest()) << " Error navigating: code=" << 
  699. error["code"].asString() << ": " << error["message"].asString() << LL_ENDL;
  700. }  
  701. // XXX Warn user?
  702. }
  703. else {
  704. // just do what our superclass does
  705. LLMediaDataClient::Responder::result(content);
  706. }
  707. }