Updated client to use new caps
brought over server changes to llExperienceCachemaster
parent
bc8b81b16d
commit
179e944f45
|
|
@ -23,25 +23,26 @@
|
|||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
#include "llexperiencecache.h"
|
||||
|
||||
#include "linden_common.h"
|
||||
#include "llavatarname.h"
|
||||
#include "llframetimer.h"
|
||||
#include "llhttpclient.h"
|
||||
#include "llsdserialize.h"
|
||||
#include <set>
|
||||
#include <map>
|
||||
#include "boost\tokenizer.hpp"
|
||||
#include "boost/tokenizer.hpp"
|
||||
|
||||
|
||||
#include "llexperiencecache.h"
|
||||
|
||||
|
||||
|
||||
namespace LLExperienceCache
|
||||
{
|
||||
const std::string& MAP_KEY = PUBLIC_KEY;
|
||||
std::string sLookupURL;
|
||||
|
||||
typedef std::set<LLUUID> ask_queue_t;
|
||||
typedef std::map<LLUUID, std::string> ask_queue_t;
|
||||
ask_queue_t sAskQueue;
|
||||
|
||||
typedef std::map<LLUUID, F64> pending_queue_t;
|
||||
|
|
@ -65,20 +66,40 @@ namespace LLExperienceCache
|
|||
bool max_age_from_cache_control(const std::string& cache_control, S32 *max_age);
|
||||
void eraseExpired();
|
||||
|
||||
void processExperience( const LLUUID& agent_id, const LLExperienceData& experience )
|
||||
void processExperience( const LLUUID& public_key, const LLSD& experience )
|
||||
{
|
||||
sCache[agent_id]=experience;
|
||||
sCache[public_key]=experience;
|
||||
LLSD & row = sCache[public_key];
|
||||
|
||||
if(row.has("expires"))
|
||||
{
|
||||
row["expires"] = row["expires"].asReal() + LLFrameTimer::getTotalSeconds();
|
||||
}
|
||||
|
||||
if(row.has(PUBLIC_KEY))
|
||||
{
|
||||
sPendingQueue.erase(row[PUBLIC_KEY].asUUID());
|
||||
}
|
||||
|
||||
if(row.has(PRIVATE_KEY))
|
||||
{
|
||||
sPendingQueue.erase(row[PRIVATE_KEY].asUUID());
|
||||
}
|
||||
|
||||
if(row.has(CREATOR_KEY))
|
||||
{
|
||||
sPendingQueue.erase(row[CREATOR_KEY].asUUID());
|
||||
}
|
||||
|
||||
sPendingQueue.erase(agent_id);
|
||||
|
||||
//signal
|
||||
signal_map_t::iterator sig_it = sSignalMap.find(agent_id);
|
||||
signal_map_t::iterator sig_it = sSignalMap.find(public_key);
|
||||
if (sig_it != sSignalMap.end())
|
||||
{
|
||||
callback_signal_t* signal = sig_it->second;
|
||||
(*signal)(agent_id, experience);
|
||||
(*signal)(experience);
|
||||
|
||||
sSignalMap.erase(agent_id);
|
||||
sSignalMap.erase(public_key);
|
||||
|
||||
delete signal;
|
||||
}
|
||||
|
|
@ -109,7 +130,7 @@ namespace LLExperienceCache
|
|||
std::string cache_control = cache_control_header.asString();
|
||||
if (max_age_from_cache_control(cache_control, &max_age))
|
||||
{
|
||||
LL_DEBUGS("ExperienceCache")
|
||||
LL_WARNS("ExperienceCache")
|
||||
<< "got expiration from headers, max_age " << max_age
|
||||
<< LL_ENDL;
|
||||
F64 now = LLFrameTimer::getTotalSeconds();
|
||||
|
|
@ -186,16 +207,14 @@ namespace LLExperienceCache
|
|||
S32 parse_count = LLSDSerialize::fromXMLDocument(data, istr);
|
||||
if(parse_count < 1) return;
|
||||
|
||||
LLSD agents = data["agents"];
|
||||
LLSD experiences = data["experiences"];
|
||||
|
||||
LLUUID agent_id;
|
||||
LLExperienceData experience;
|
||||
LLSD::map_const_iterator it = agents.beginMap();
|
||||
for(; it != agents.endMap() ; ++it)
|
||||
LLUUID public_key;
|
||||
LLSD::map_const_iterator it = experiences.beginMap();
|
||||
for(; it != experiences.endMap() ; ++it)
|
||||
{
|
||||
agent_id.set(it->first);
|
||||
experience.fromLLSD( it->second);
|
||||
sCache[agent_id]=experience;
|
||||
public_key.set(it->first);
|
||||
sCache[public_key]=it->second;
|
||||
}
|
||||
|
||||
LL_INFOS("ExperienceCache") << "loaded " << sCache.size() << LL_ENDL;
|
||||
|
|
@ -203,16 +222,20 @@ namespace LLExperienceCache
|
|||
|
||||
void exportFile(std::ostream& ostr)
|
||||
{
|
||||
LLSD agents;
|
||||
LLSD experiences;
|
||||
|
||||
cache_t::const_iterator it =sCache.begin();
|
||||
for( ; it != sCache.end() ; ++it)
|
||||
{
|
||||
agents[it->first.asString()] = it->second.asLLSD();
|
||||
if(!it->second.has(PUBLIC_KEY) || it->second[PUBLIC_KEY].asUUID().isNull() ||
|
||||
it->second.has("error"))
|
||||
continue;
|
||||
|
||||
experiences[it->first.asString()] = it->second;
|
||||
}
|
||||
|
||||
LLSD data;
|
||||
data["agents"] = agents;
|
||||
data["experiences"] = experiences;
|
||||
|
||||
LLSDSerialize::toPrettyXML(data, ostr);
|
||||
}
|
||||
|
|
@ -220,8 +243,8 @@ namespace LLExperienceCache
|
|||
class LLExperienceResponder : public LLHTTPClient::Responder
|
||||
{
|
||||
public:
|
||||
LLExperienceResponder(const std::vector<LLUUID>& agent_ids)
|
||||
:mAgentIds(agent_ids)
|
||||
LLExperienceResponder(const ask_queue_t& keys)
|
||||
:mKeys(keys)
|
||||
{
|
||||
|
||||
}
|
||||
|
|
@ -233,60 +256,65 @@ namespace LLExperienceCache
|
|||
|
||||
virtual void result(const LLSD& content)
|
||||
{
|
||||
LLSD agents = content["agents"];
|
||||
LLSD::array_const_iterator it = agents.beginArray();
|
||||
for( /**/ ; it != agents.endArray(); ++it)
|
||||
LLSD experiences = content["experience_keys"];
|
||||
LLSD::array_const_iterator it = experiences.beginArray();
|
||||
for( /**/ ; it != experiences.endArray(); ++it)
|
||||
{
|
||||
const LLSD& row = *it;
|
||||
LLUUID agent_id = row["id"].asUUID();
|
||||
LLUUID public_key = row[PUBLIC_KEY].asUUID();
|
||||
|
||||
LLExperienceData experience;
|
||||
|
||||
if(experience.fromLLSD(row))
|
||||
LL_INFOS("ExperienceCache") << "Received result for " << public_key
|
||||
<< " display '" << row[LLExperienceCache::NAME].asString() << "'" << LL_ENDL ;
|
||||
|
||||
processExperience(public_key, row);
|
||||
}
|
||||
|
||||
LLSD error_ids = content["error_ids"];
|
||||
LLSD::map_const_iterator errIt = error_ids.beginMap();
|
||||
for( /**/ ; errIt != error_ids.endMap() ; ++errIt )
|
||||
{
|
||||
LLUUID id = LLUUID(errIt->first);
|
||||
for( it = errIt->second.beginArray(); it != errIt->second.endArray() ; ++it)
|
||||
{
|
||||
LL_DEBUGS("ExperienceCache") << __FUNCTION__ << "Received result for " << agent_id
|
||||
<< "display '" << experience.mDisplayName << "'" << LL_ENDL ;
|
||||
LL_INFOS("ExperienceCache") << "Clearing error result for " << id
|
||||
<< " of type '" << it->asString() << "'" << LL_ENDL ;
|
||||
|
||||
processExperience(agent_id, experience);
|
||||
erase(id, it->asString());
|
||||
}
|
||||
}
|
||||
|
||||
LLSD unresolved_agents = content["bad_ids"];
|
||||
S32 num_unresolved = unresolved_agents.size();
|
||||
if(num_unresolved > 0)
|
||||
{
|
||||
LL_DEBUGS("ExperienceCache") << __FUNCTION__ << "Ignoring " << num_unresolved
|
||||
<< " bad ids" << LL_ENDL ;
|
||||
}
|
||||
|
||||
LL_DEBUGS("ExperienceCache") << __FUNCTION__ << sCache.size() << " cached experiences" << LL_ENDL;
|
||||
LL_INFOS("ExperienceCache") << sCache.size() << " cached experiences" << LL_ENDL;
|
||||
}
|
||||
|
||||
void error(U32 status, const std::string& reason)
|
||||
virtual void error(U32 status, const std::string& reason)
|
||||
{
|
||||
// We're going to construct a dummy record and cache it for a while,
|
||||
// either briefly for a 503 Service Unavailable, or longer for other
|
||||
// errors.
|
||||
F64 retry_timestamp = errorRetryTimestamp(status);
|
||||
|
||||
LLExperienceData experience;
|
||||
experience.mDisplayName = LLExperienceCache::DUMMY_NAME;
|
||||
experience.mDescription = LLExperienceCache::DUMMY_NAME;
|
||||
experience.mExpires = retry_timestamp;
|
||||
|
||||
// Add dummy records for all agent IDs in this request
|
||||
std::vector<LLUUID>::const_iterator it = mAgentIds.begin();
|
||||
for ( ; it != mAgentIds.end(); ++it)
|
||||
LL_WARNS("ExperienceCache") << "Request failed "<<status<<" "<<reason<< LL_ENDL;
|
||||
// We're going to construct a dummy record and cache it for a while,
|
||||
// either briefly for a 503 Service Unavailable, or longer for other
|
||||
// errors.
|
||||
F64 retry_timestamp = errorRetryTimestamp(status);
|
||||
|
||||
|
||||
// Add dummy records for all agent IDs in this request
|
||||
ask_queue_t::const_iterator it = mKeys.begin();
|
||||
for ( ; it != mKeys.end(); ++it)
|
||||
{
|
||||
LLExperienceCache::processExperience((*it), experience);
|
||||
}
|
||||
LLSD exp;
|
||||
exp["expires"]=retry_timestamp;
|
||||
exp[it->second] = it->first;
|
||||
exp["key_type"] = it->second;
|
||||
exp["uuid"] = it->first;
|
||||
exp["error"] = (LLSD::Integer)status;
|
||||
LLExperienceCache::processExperience(it->first, exp);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Return time to retry a request that generated an error, based on
|
||||
// error type and headers. Return value is seconds-since-epoch.
|
||||
F64 errorRetryTimestamp(S32 status)
|
||||
{
|
||||
F64 now = LLFrameTimer::getTotalSeconds();
|
||||
|
||||
// Retry-After takes priority
|
||||
LLSD retry_after = mHeaders["retry-after"];
|
||||
|
|
@ -297,7 +325,7 @@ namespace LLExperienceCache
|
|||
if (delta_seconds > 0)
|
||||
{
|
||||
// ...valid delta-seconds
|
||||
return now + F64(delta_seconds);
|
||||
return F64(delta_seconds);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -313,78 +341,87 @@ namespace LLExperienceCache
|
|||
{
|
||||
// ...service unavailable, retry soon
|
||||
const F64 SERVICE_UNAVAILABLE_DELAY = 600.0; // 10 min
|
||||
return now + SERVICE_UNAVAILABLE_DELAY;
|
||||
return SERVICE_UNAVAILABLE_DELAY;
|
||||
}
|
||||
else if (status == 499)
|
||||
{
|
||||
// ...we were probably too busy, retry quickly
|
||||
const F64 BUSY_DELAY = 10.0; // 10 seconds
|
||||
return BUSY_DELAY;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
// ...other unexpected error
|
||||
const F64 DEFAULT_DELAY = 3600.0; // 1 hour
|
||||
return now + DEFAULT_DELAY;
|
||||
return DEFAULT_DELAY;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<LLUUID> mAgentIds;
|
||||
ask_queue_t mKeys;
|
||||
LLSD mHeaders;
|
||||
};
|
||||
|
||||
void requestExperiences()
|
||||
{
|
||||
if(sAskQueue.empty())
|
||||
if(sAskQueue.empty() || sLookupURL.empty())
|
||||
return;
|
||||
|
||||
F64 now = LLFrameTimer::getTotalSeconds();
|
||||
|
||||
const U32 NAME_URL_MAX = 4096;
|
||||
const U32 NAME_URL_SEND_THRESHOLD = 3000;
|
||||
const U32 EXP_URL_SEND_THRESHOLD = 3000;
|
||||
|
||||
std::string url;
|
||||
url.reserve(NAME_URL_MAX);
|
||||
|
||||
std::vector<LLUUID> agent_ids;
|
||||
agent_ids.reserve(128);
|
||||
std::ostringstream ostr;
|
||||
|
||||
url += sLookupURL;
|
||||
ask_queue_t keys;
|
||||
|
||||
std::string arg="?ids=";
|
||||
ostr << sLookupURL;
|
||||
|
||||
char arg='?';
|
||||
|
||||
int request_count = 0;
|
||||
for(ask_queue_t::const_iterator it = sAskQueue.begin() ; it != sAskQueue.end() && request_count < sMaximumLookups; ++it)
|
||||
{
|
||||
const LLUUID& agent_id = *it;
|
||||
const LLUUID& key = it->first;
|
||||
const std::string& key_type = it->second;
|
||||
|
||||
ostr << arg << key_type << '=' << key.asString() ;
|
||||
|
||||
url += arg;
|
||||
url += agent_id.asString();
|
||||
agent_ids.push_back(agent_id);
|
||||
keys[key]=key_type;
|
||||
request_count++;
|
||||
|
||||
sPendingQueue[agent_id] = now;
|
||||
sPendingQueue[key] = now;
|
||||
|
||||
arg[0]='&';
|
||||
arg='&';
|
||||
|
||||
if(url.size() > NAME_URL_SEND_THRESHOLD)
|
||||
if(ostr.tellp() > EXP_URL_SEND_THRESHOLD)
|
||||
{
|
||||
LLHTTPClient::get(url, new LLExperienceResponder(agent_ids));
|
||||
url = sLookupURL;
|
||||
arg[0]='?';
|
||||
agent_ids.clear();
|
||||
LL_INFOS("ExperienceCache") << " query: " << ostr.str() << LL_ENDL;
|
||||
LLHTTPClient::get(ostr.str(), new LLExperienceResponder(keys));
|
||||
ostr.clear();
|
||||
ostr.str(sLookupURL);
|
||||
arg='?';
|
||||
keys.clear();
|
||||
}
|
||||
}
|
||||
|
||||
if(url.size() > sLookupURL.size())
|
||||
if(ostr.tellp() > sLookupURL.size())
|
||||
{
|
||||
LLHTTPClient::get(url, new LLExperienceResponder(agent_ids));
|
||||
LL_INFOS("ExperienceCache") << " query: " << ostr.str() << LL_ENDL;
|
||||
LLHTTPClient::get(ostr.str(), new LLExperienceResponder(keys));
|
||||
}
|
||||
|
||||
sAskQueue.clear();
|
||||
}
|
||||
|
||||
bool isRequestPending(const LLUUID& agent_id)
|
||||
bool isRequestPending(const LLUUID& public_key)
|
||||
{
|
||||
bool isPending = false;
|
||||
const F64 PENDING_TIMEOUT_SECS = 5.0 * 60.0;
|
||||
|
||||
pending_queue_t::const_iterator it = sPendingQueue.find(agent_id);
|
||||
pending_queue_t::const_iterator it = sPendingQueue.find(public_key);
|
||||
|
||||
if(it != sPendingQueue.end())
|
||||
{
|
||||
|
|
@ -399,6 +436,10 @@ namespace LLExperienceCache
|
|||
void setLookupURL( const std::string& lookup_url )
|
||||
{
|
||||
sLookupURL = lookup_url;
|
||||
if(!sLookupURL.empty())
|
||||
{
|
||||
sLookupURL += "id/";
|
||||
}
|
||||
}
|
||||
|
||||
bool hasLookupURL()
|
||||
|
|
@ -429,87 +470,136 @@ namespace LLExperienceCache
|
|||
}
|
||||
}
|
||||
|
||||
void erase( const LLUUID& agent_id )
|
||||
struct FindByKey
|
||||
{
|
||||
sCache.erase(agent_id);
|
||||
FindByKey(const LLUUID& key, const std::string& key_type):mKey(key), mKeyType(key_type){}
|
||||
const LLUUID& mKey;
|
||||
const std::string& mKeyType;
|
||||
|
||||
bool operator()(cache_t::value_type& experience)
|
||||
{
|
||||
return experience.second.has(mKeyType) && experience.second[mKeyType].asUUID() == mKey;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
cache_t::iterator Find(const LLUUID& key, const std::string& key_type)
|
||||
{
|
||||
LL_INFOS("ExperienceCache") << " searching for " << key << " of type " << key_type << LL_ENDL;
|
||||
if(key_type == MAP_KEY)
|
||||
{
|
||||
return sCache.find(key);
|
||||
}
|
||||
|
||||
return std::find_if(sCache.begin(), sCache.end(), FindByKey(key, key_type));
|
||||
}
|
||||
|
||||
|
||||
void erase( const LLUUID& key, const std::string& key_type )
|
||||
{
|
||||
cache_t::iterator it = Find(key, key_type);
|
||||
|
||||
if(it != sCache.end())
|
||||
{
|
||||
sCache.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
void eraseExpired()
|
||||
{
|
||||
S32 expired_count = 0;
|
||||
F64 now = LLFrameTimer::getTotalSeconds();
|
||||
cache_t::iterator it = sCache.begin();
|
||||
while (it != sCache.end())
|
||||
{
|
||||
cache_t::iterator cur = it;
|
||||
LLSD& exp = cur->second;
|
||||
++it;
|
||||
const LLExperienceData& experience = cur->second;
|
||||
if (experience.mExpires < now)
|
||||
if(exp.has("expires") && exp["expires"].asReal() < now)
|
||||
{
|
||||
sCache.erase(cur);
|
||||
expired_count++;
|
||||
if(exp.has("key_type") && exp.has("uuid"))
|
||||
{
|
||||
fetch(exp["uuid"].asUUID(), exp["key_type"].asString(), true);
|
||||
sCache.erase(cur);
|
||||
}
|
||||
else if(exp.has(MAP_KEY))
|
||||
{
|
||||
LLUUID id = exp[MAP_KEY];
|
||||
if(!id.isNull())
|
||||
{
|
||||
fetch(id, MAP_KEY, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void fetch( const LLUUID& agent_id )
|
||||
|
||||
bool fetch( const LLUUID& key, const std::string& key_type, bool refresh/* = true*/ )
|
||||
{
|
||||
LL_DEBUGS("ExperienceCache") << __FUNCTION__ << "queue request for agent" << agent_id << LL_ENDL ;
|
||||
sAskQueue.insert(agent_id);
|
||||
if(!key.isNull() && !isRequestPending(key) && (refresh || Find(key, key_type)==sCache.end()))
|
||||
{
|
||||
LL_INFOS("ExperienceCache") << " queue request for " << key_type << " " << key << LL_ENDL ;
|
||||
sAskQueue[key]=key_type;
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void insert( const LLUUID& agent_id, const LLExperienceData& experience_data )
|
||||
void insert(const LLSD& experience_data )
|
||||
{
|
||||
sCache[agent_id]=experience_data;
|
||||
if(experience_data.has(MAP_KEY))
|
||||
{
|
||||
sCache[experience_data[MAP_KEY].asUUID()]=experience_data;
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_WARNS("ExperienceCache") << ": Ignoring cache insert of experience which is missing " << MAP_KEY << LL_ENDL;
|
||||
}
|
||||
}
|
||||
|
||||
bool get( const LLUUID& agent_id, LLExperienceData* experience_data )
|
||||
bool get( const LLUUID& key, const std::string& key_type, LLSD& experience_data )
|
||||
{
|
||||
cache_t::const_iterator it = sCache.find(agent_id);
|
||||
if(key.isNull()) return false;
|
||||
cache_t::const_iterator it = Find(key, key_type);
|
||||
|
||||
if (it != sCache.end())
|
||||
{
|
||||
llassert(experience_data);
|
||||
*experience_data = it->second;
|
||||
experience_data = it->second;
|
||||
return true;
|
||||
}
|
||||
|
||||
if(!isRequestPending(agent_id))
|
||||
{
|
||||
fetch(agent_id);
|
||||
}
|
||||
fetch(key, key_type);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void get( const LLUUID& agent_id, callback_slot_t slot )
|
||||
void get( const LLUUID& key, const std::string& key_type, callback_slot_t slot )
|
||||
{
|
||||
cache_t::const_iterator it = sCache.find(agent_id);
|
||||
if(key.isNull()) return;
|
||||
|
||||
cache_t::const_iterator it = Find(key, key_type);
|
||||
if (it != sCache.end())
|
||||
{
|
||||
// ...name already exists in cache, fire callback now
|
||||
callback_signal_t signal;
|
||||
signal.connect(slot);
|
||||
signal(agent_id, it->second);
|
||||
|
||||
signal(it->second);
|
||||
return;
|
||||
}
|
||||
|
||||
// schedule a request
|
||||
if (!isRequestPending(agent_id))
|
||||
{
|
||||
sAskQueue.insert(agent_id);
|
||||
}
|
||||
fetch(key, key_type);
|
||||
|
||||
// always store additional callback, even if request is pending
|
||||
signal_map_t::iterator sig_it = sSignalMap.find(agent_id);
|
||||
signal_map_t::iterator sig_it = sSignalMap.find(key);
|
||||
if (sig_it == sSignalMap.end())
|
||||
{
|
||||
// ...new callback for this id
|
||||
callback_signal_t* signal = new callback_signal_t();
|
||||
signal->connect(slot);
|
||||
sSignalMap[agent_id] = signal;
|
||||
sSignalMap[key] = signal;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -520,30 +610,3 @@ namespace LLExperienceCache
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
static const std::string EXPERIENCE_NAME("username");
|
||||
static const std::string EXPERIENCE_DESCRIPTION("display_name");
|
||||
static const std::string EXPERIENCE_EXPIRATION("display_name_expires");
|
||||
|
||||
bool LLExperienceData::fromLLSD( const LLSD& sd )
|
||||
{
|
||||
mDisplayName = sd[EXPERIENCE_NAME].asString();
|
||||
mDescription = sd[EXPERIENCE_DESCRIPTION].asString();
|
||||
LLDate expiration = sd[EXPERIENCE_EXPIRATION];
|
||||
mExpires = expiration.secondsSinceEpoch();
|
||||
|
||||
if(mDisplayName.empty() || mDescription.empty()) return false;
|
||||
|
||||
mDescription += " % Hey, this is a description!";
|
||||
return true;
|
||||
}
|
||||
|
||||
LLSD LLExperienceData::asLLSD() const
|
||||
{
|
||||
LLSD sd;
|
||||
sd[EXPERIENCE_NAME] = mDisplayName;
|
||||
sd[EXPERIENCE_DESCRIPTION] = mDescription.substr(0, llmin(mDescription.size(),mDescription.find(" %")));
|
||||
sd[EXPERIENCE_EXPIRATION] = LLDate(mExpires);
|
||||
|
||||
return sd;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,36 +29,35 @@
|
|||
#ifndef LL_LLEXPERIENCECACHE_H
|
||||
#define LL_LLEXPERIENCECACHE_H
|
||||
|
||||
#include <string>
|
||||
#include "linden_common.h"
|
||||
#include <boost/signals2.hpp>
|
||||
|
||||
class LLSD;
|
||||
class LLUUID;
|
||||
|
||||
|
||||
class LLExperienceData
|
||||
{
|
||||
public:
|
||||
bool fromLLSD(const LLSD& sd);
|
||||
LLSD asLLSD() const;
|
||||
|
||||
|
||||
std::string mDisplayName;
|
||||
std::string mDescription;
|
||||
F64 mExpires;
|
||||
};
|
||||
|
||||
|
||||
|
||||
namespace LLExperienceCache
|
||||
{
|
||||
const std::string PUBLIC_KEY = "public-id";
|
||||
const std::string PRIVATE_KEY = "private-id";
|
||||
const std::string CREATOR_KEY = "creator-id";
|
||||
const std::string NAME = "name";
|
||||
const std::string PROPERTIES = "properties";
|
||||
const std::string EXPIRES = "expires";
|
||||
|
||||
const int EXPERIENCE_INVALID = (1 << 0);
|
||||
const int EXPERIENCE_NORMAL = (1 << 1);
|
||||
const int EXPERIENCE_REGION = (1 << 2);
|
||||
const static F64 DEFAULT_EXPIRATION = 600.0;
|
||||
|
||||
// dummy name used when we have nothing else
|
||||
const std::string DUMMY_NAME = "\?\?\?";
|
||||
// Callback types for get() below
|
||||
typedef boost::signals2::signal<
|
||||
void (const LLUUID& agent_id, const LLExperienceData& experience)>
|
||||
typedef boost::signals2::signal<void (const LLSD& experience)>
|
||||
callback_signal_t;
|
||||
typedef callback_signal_t::slot_type callback_slot_t;
|
||||
typedef std::map<LLUUID, LLExperienceData> cache_t;
|
||||
typedef std::map<LLUUID, LLSD> cache_t;
|
||||
|
||||
|
||||
void setLookupURL(const std::string& lookup_url);
|
||||
|
|
@ -70,14 +69,14 @@ namespace LLExperienceCache
|
|||
void exportFile(std::ostream& ostr);
|
||||
void importFile(std::istream& istr);
|
||||
void initClass();
|
||||
|
||||
void erase(const LLUUID& agent_id);
|
||||
void fetch(const LLUUID& agent_id);
|
||||
void insert(const LLUUID& agent_id, const LLExperienceData& experience_data);
|
||||
bool get(const LLUUID& agent_id, LLExperienceData* experience_data);
|
||||
|
||||
void erase(const LLUUID& key, const std::string& key_type);
|
||||
bool fetch(const LLUUID& key, const std::string& key_type, bool refresh = false);
|
||||
void insert(LLSD& experience_data);
|
||||
bool get(const LLUUID& key, const std::string& key_type, LLSD& experience_data);
|
||||
|
||||
// If name information is in cache, callback will be called immediately.
|
||||
void get(const LLUUID& agent_id, callback_slot_t slot);
|
||||
void get(const LLUUID& key, const std::string& key_type, callback_slot_t slot);
|
||||
|
||||
const cache_t& getCached();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -4818,12 +4818,12 @@ void LLAppViewer::idleExperienceCache()
|
|||
LLViewerRegion* region = gAgent.getRegion();
|
||||
if (!region) return;
|
||||
|
||||
std::string lookup_url=region->getCapability("GetDisplayNames"); // use GetDisplayNames for testing round trip
|
||||
std::string lookup_url=region->getCapability("GetExperienceInfo");
|
||||
if(!lookup_url.empty() && lookup_url.back() != '/')
|
||||
{
|
||||
lookup_url += '/';
|
||||
}
|
||||
|
||||
|
||||
LLExperienceCache::setLookupURL(lookup_url);
|
||||
|
||||
LLExperienceCache::idle();
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
#include "llpanelprofile.h"
|
||||
#include "lluictrlfactory.h"
|
||||
#include "llexperiencecache.h"
|
||||
#include "llagent.h"
|
||||
|
||||
#include "llpanelexperiences.h"
|
||||
|
||||
|
|
@ -26,6 +27,61 @@ void* LLPanelExperiences::create( void* data )
|
|||
return new LLPanelExperiences();
|
||||
}
|
||||
|
||||
void ExperienceResult(LLHandle<LLPanelExperiences> panel, const LLSD& experience)
|
||||
{
|
||||
LLPanelExperiences* experiencePanel = panel.get();
|
||||
if(experiencePanel)
|
||||
{
|
||||
experiencePanel->addExperienceInfo(experience);
|
||||
}
|
||||
}
|
||||
|
||||
class LLExperienceListResponder : public LLHTTPClient::Responder
|
||||
{
|
||||
public:
|
||||
LLExperienceListResponder(const LLHandle<LLPanelExperiences>& parent):mParent(parent)
|
||||
{
|
||||
}
|
||||
|
||||
LLHandle<LLPanelExperiences> mParent;
|
||||
|
||||
virtual void result(const LLSD& content)
|
||||
{
|
||||
if(mParent.isDead())
|
||||
return;
|
||||
|
||||
LLSD experiences = content["experiences"];
|
||||
LLSD::array_const_iterator it = experiences.beginArray();
|
||||
for( /**/ ; it != experiences.endArray(); ++it)
|
||||
{
|
||||
LLUUID public_key = it->asUUID();
|
||||
|
||||
LLExperienceCache::get(public_key, LLExperienceCache::PUBLIC_KEY, boost::bind(ExperienceResult, mParent, _1));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void LLPanelExperiences::addExperienceInfo(const LLSD& experience)
|
||||
{
|
||||
LLExperienceItem* item = new LLExperienceItem();
|
||||
if(experience.has(LLExperienceCache::NAME))
|
||||
{
|
||||
item->setExperienceName(experience[LLExperienceCache::NAME].asString());
|
||||
}
|
||||
else if(experience.has("error"))
|
||||
{
|
||||
item->setExperienceName(experience["error"].asString());
|
||||
}
|
||||
|
||||
if(experience.has(LLExperienceCache::PUBLIC_KEY))
|
||||
{
|
||||
item->setExperienceDescription(experience[LLExperienceCache::PUBLIC_KEY].asString());
|
||||
}
|
||||
|
||||
mExperiencesList->addItem(item);
|
||||
|
||||
}
|
||||
|
||||
|
||||
BOOL LLPanelExperiences::postBuild( void )
|
||||
{
|
||||
|
|
@ -35,15 +91,15 @@ BOOL LLPanelExperiences::postBuild( void )
|
|||
mExperiencesList->setNoItemsCommentText(getString("no_experiences"));
|
||||
}
|
||||
|
||||
const LLExperienceCache::cache_t& experiences = LLExperienceCache::getCached();
|
||||
|
||||
LLExperienceCache::cache_t::const_iterator it = experiences.begin();
|
||||
for( ; it != experiences.end() && mExperiencesList->getChildCount() < 10 ; ++it)
|
||||
LLViewerRegion* region = gAgent.getRegion();
|
||||
if (region)
|
||||
{
|
||||
LLExperienceItem* item = new LLExperienceItem();
|
||||
item->setExperienceName(it->second.mDisplayName);
|
||||
item->setExperienceDescription(it->second.mDescription);
|
||||
mExperiencesList->addItem(item);
|
||||
std::string lookup_url=region->getCapability("GetExperiences");
|
||||
if(!lookup_url.empty())
|
||||
{
|
||||
LLHTTPClient::get(lookup_url, new LLExperienceListResponder(getDerivedHandle<LLPanelExperiences>()));
|
||||
}
|
||||
}
|
||||
|
||||
mExperiencesAccTab = getChild<LLAccordionCtrlTab>("tab_experiences");
|
||||
|
|
@ -71,17 +127,6 @@ void LLPanelExperiences::updateData()
|
|||
if(isDirty())
|
||||
{
|
||||
mNoExperiences = false;
|
||||
|
||||
/*
|
||||
mNoItemsLabel->setValue(LLTrans::getString("PicksClassifiedsLoadingText"));
|
||||
mNoItemsLabel->setVisible(TRUE);
|
||||
|
||||
mPicksList->clear();
|
||||
LLAvatarPropertiesProcessor::getInstance()->sendAvatarPicksRequest(getAvatarId());
|
||||
|
||||
mClassifiedsList->clear();
|
||||
LLAvatarPropertiesProcessor::getInstance()->sendAvatarClassifiedsRequest(getAvatarId());
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -179,10 +224,13 @@ LLExperienceItem::LLExperienceItem()
|
|||
buildFromFile("panel_experience_info.xml");
|
||||
}
|
||||
|
||||
void LLExperienceItem::init( LLExperienceData* experience_data )
|
||||
void LLExperienceItem::init( LLSD* experience_data )
|
||||
{
|
||||
setExperienceDescription(experience_data->mDescription);
|
||||
setExperienceName(experience_data->mDisplayName);
|
||||
if(experience_data)
|
||||
{
|
||||
setExperienceDescription(experience_data->has(LLExperienceCache::PUBLIC_KEY)?(*experience_data)[LLExperienceCache::PUBLIC_KEY].asString() : std::string());
|
||||
setExperienceName(experience_data->has(LLExperienceCache::NAME)?(*experience_data)[LLExperienceCache::NAME].asString() : std::string());
|
||||
}
|
||||
}
|
||||
|
||||
void LLExperienceItem::setExperienceDescription( const std::string& val )
|
||||
|
|
|
|||
|
|
@ -31,7 +31,6 @@
|
|||
#include "llflatlistview.h"
|
||||
#include "llpanelavatar.h"
|
||||
|
||||
class LLExperienceData;
|
||||
class LLExperienceItem;
|
||||
class LLPanelProfile;
|
||||
|
||||
|
|
@ -69,7 +68,7 @@ public:
|
|||
LLExperienceItem* getSelectedExperienceItem();
|
||||
|
||||
void setProfilePanel(LLPanelProfile* profile_panel);
|
||||
|
||||
void addExperienceInfo(const LLSD& experience);
|
||||
protected:
|
||||
|
||||
void onListCommit(const LLFlatListView* f_list);
|
||||
|
|
@ -97,7 +96,7 @@ public:
|
|||
LLExperienceItem();
|
||||
~LLExperienceItem();
|
||||
|
||||
void init(LLExperienceData* experience_data);
|
||||
void init(LLSD* experience_data);
|
||||
/*virtual*/ BOOL postBuild();
|
||||
void update();
|
||||
|
||||
|
|
|
|||
|
|
@ -1536,6 +1536,8 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames)
|
|||
}
|
||||
|
||||
capabilityNames.append("GetDisplayNames");
|
||||
capabilityNames.append("GetExperiences");
|
||||
capabilityNames.append("GetExperienceInfo");
|
||||
capabilityNames.append("GetMesh");
|
||||
capabilityNames.append("GetObjectCost");
|
||||
capabilityNames.append("GetObjectPhysicsData");
|
||||
|
|
|
|||
|
|
@ -2517,10 +2517,7 @@ void LLVOAvatar::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)
|
|||
idleUpdateBelowWater(); // wind effect uses this
|
||||
idleUpdateWindEffect();
|
||||
}
|
||||
|
||||
LLExperienceData ed;
|
||||
LLExperienceCache::get(getID(), &ed);
|
||||
|
||||
|
||||
idleUpdateNameTag( root_pos_last );
|
||||
idleUpdateRenderCost();
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue