phoenix-firestorm/indra/newview/llexperiencelog.cpp

301 lines
7.4 KiB
C++

/**
* @file llexperiencelog.cpp
* @brief llexperiencelog implementation
*
* $LicenseInfo:firstyear=2014&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2014, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#include "llviewerprecompiledheaders.h"
#include "llexperiencelog.h"
#include "lldispatcher.h"
#include "llsdserialize.h"
#include "llviewergenericmessage.h"
#include "llnotificationsutil.h"
#include "lltrans.h"
#include "llerror.h"
#include "lldate.h"
class LLExperienceLogDispatchHandler : public LLDispatchHandler
{
public:
virtual bool operator()(
const LLDispatcher* dispatcher,
const std::string& key,
const LLUUID& invoice,
const sparam_t& strings)
{
LLSD message;
sparam_t::const_iterator it = strings.begin();
if(it != strings.end()){
const std::string& llsdRaw = *it++;
std::istringstream llsdData(llsdRaw);
if (!LLSDSerialize::deserialize(message, llsdData, llsdRaw.length()))
{
LL_WARNS() << "LLExperienceLogDispatchHandler: Attempted to read parameter data into LLSD but failed:" << llsdRaw << LL_ENDL;
}
}
message["public_id"] = invoice;
// Object Name
if(it != strings.end())
{
message["ObjectName"] = *it++;
}
// parcel Name
if(it != strings.end())
{
message["ParcelName"] = *it++;
}
message["Count"] = 1;
LLExperienceLog::instance().handleExperienceMessage(message);
return true;
}
};
static LLExperienceLogDispatchHandler experience_log_dispatch_handler;
void LLExperienceLog::handleExperienceMessage(LLSD& message)
{
time_t now;
time(&now);
char daybuf[16];/* Flawfinder: ignore */
char time_of_day[16];/* Flawfinder: ignore */
strftime(daybuf, 16, "%Y-%m-%d", localtime(&now));
strftime(time_of_day, 16, " %H:%M:%S", localtime(&now));
message["Time"] = time_of_day;
std::string day = daybuf;
if(!mEvents.has(day))
{
mEvents[day] = LLSD::emptyArray();
}
LLSD& dayEvents = mEvents[day];
if(dayEvents.size() > 0)
{
LLSD& last = *(dayEvents.rbeginArray());
if( last["public_id"].asUUID() == message["public_id"].asUUID()
&& last["ObjectName"].asString() == message["ObjectName"].asString()
&& last["OwnerID"].asUUID() == message["OwnerID"].asUUID()
&& last["ParcelName"].asString() == message["ParcelName"].asString()
&& last["Permission"].asInteger() == message["Permission"].asInteger())
{
last["Count"] = last["Count"].asInteger() + 1;
last["Time"] = time_of_day;
mSignals(last);
return;
}
}
message["Time"] = time_of_day;
mEvents[day].append(message);
mEventsToSave[day].append(message);
mSignals(message);
}
LLExperienceLog::LLExperienceLog()
: mMaxDays(7)
, mPageSize(25)
, mNotifyNewEvent(false)
{
}
void LLExperienceLog::initialize()
{
loadEvents();
if(!gGenericDispatcher.isHandlerPresent("ExperienceEvent"))
{
gGenericDispatcher.addHandler("ExperienceEvent", &experience_log_dispatch_handler);
}
}
std::string LLExperienceLog::getFilename()
{
return gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "experience_events.xml");
}
std::string LLExperienceLog::getPermissionString( const LLSD& message, const std::string& base )
{
std::ostringstream buf;
if(message.has("Permission"))
{
buf << base << message["Permission"].asInteger();
std::string entry;
if(LLTrans::findString(entry, buf.str()))
{
buf.str(entry);
}
}
if(buf.str().empty())
{
buf << base << "Unknown";
buf.str(LLTrans::getString(buf.str(), message));
}
return buf.str();
}
void LLExperienceLog::notify( LLSD& message )
{
message["EventType"] = getPermissionString(message, "ExperiencePermission");
if(message.has("IsAttachment") && message["IsAttachment"].asBoolean())
{
LLNotificationsUtil::add("ExperienceEventAttachment", message);
}
else
{
LLNotificationsUtil::add("ExperienceEvent", message);
}
message.erase("EventType");
}
void LLExperienceLog::saveEvents()
{
std::string filename = getFilename();
LLSD settings = LLSD::emptyMap().with("Events", mEventsToSave);
settings["MaxDays"] = (int)mMaxDays;
settings["Notify"] = mNotifyNewEvent;
settings["PageSize"] = (int)mPageSize;
llofstream stream(filename.c_str());
LLSDSerialize::toPrettyXML(settings, stream);
}
void LLExperienceLog::loadEvents()
{
LLSD settings = LLSD::emptyMap();
std::string filename = getFilename();
llifstream stream(filename.c_str());
LLSDSerialize::fromXMLDocument(settings, stream);
if(settings.has("MaxDays"))
{
setMaxDays((U32)settings["MaxDays"].asInteger());
}
if(settings.has("Notify"))
{
setNotifyNewEvent(settings["Notify"].asBoolean());
}
if(settings.has("PageSize"))
{
setPageSize((U32)settings["PageSize"].asInteger());
}
mEvents.clear();
if(mMaxDays > 0 && settings.has("Events"))
{
mEvents = settings["Events"];
eraseExpired(); // <FS:Ansariel> FIRE-21781: experience_events.xml log file grows indefinitely
mEventsToSave = mEvents;
}
}
LLExperienceLog::~LLExperienceLog()
{
saveEvents();
}
void LLExperienceLog::eraseExpired()
{
// <FS:Ansariel> FIRE-21781: experience_events.xml log file grows indefinitely
//while(mEvents.size() > mMaxDays && mMaxDays > 0)
//{
// mEvents.erase(mEvents.beginMap()->first);
//}
if (mMaxDays > 0)
{
LLSD events = mEvents;
for (LLSD::map_const_iterator it = mEvents.beginMap(); it != mEvents.endMap(); ++it)
{
std::string date = it->first;
if (!isNotExpired(date))
{
events.erase(it->first);
}
}
mEvents = events;
}
// </FS:Ansariel>
}
bool LLExperienceLog::isNotExpired(std::string& date)
{
LLDate event_date;
S32 month, day, year;
S32 matched = sscanf(date.c_str(), "%d-%d-%d", &year, &month, &day);
if (matched != 3) return false;
event_date.fromYMDHMS(year, month, day);
const U32 seconds_in_day = 24 * 60 * 60;
S32 curr_year = 0, curr_month = 0, curr_day = 0;
LLDate curr_date = LLDate::now();
curr_date.split(&curr_year, &curr_month, &curr_day);
curr_date.fromYMDHMS(curr_year, curr_month, curr_day); // Set hour, min, and sec to 0
LLDate boundary_date = LLDate(curr_date.secondsSinceEpoch() - seconds_in_day*getMaxDays());
return event_date >= boundary_date;
}
const LLSD& LLExperienceLog::getEvents() const
{
return mEvents;
}
void LLExperienceLog::clear()
{
mEvents.clear();
}
void LLExperienceLog::setMaxDays( U32 val )
{
mMaxDays = val;
}
LLExperienceLog::callback_connection_t LLExperienceLog::addUpdateSignal( const callback_slot_t& cb )
{
return mSignals.connect(cb);
}
void LLExperienceLog::setNotifyNewEvent( bool val )
{
mNotifyNewEvent = val;
if(!val && mNotifyConnection.connected())
{
mNotifyConnection.disconnect();
}
else if( val && !mNotifyConnection.connected())
{
mNotifyConnection = addUpdateSignal(boost::function<void(LLSD&)>(LLExperienceLog::notify));
}
}