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

游戏引擎

开发平台:

C++ Builder

  1. /**
  2.  * @file   llnotificationslistener.cpp
  3.  * @author Brad Kittenbrink
  4.  * @date   2009-07-08
  5.  * @brief  Implementation for llnotificationslistener.
  6.  * 
  7.  * $LicenseInfo:firstyear=2009&license=viewergpl$
  8.  * 
  9.  * Copyright (c) 2009-2010, Linden Research, Inc.
  10.  * 
  11.  * Second Life Viewer Source Code
  12.  * The source code in this file ("Source Code") is provided by Linden Lab
  13.  * to you under the terms of the GNU General Public License, version 2.0
  14.  * ("GPL"), unless you have obtained a separate licensing agreement
  15.  * ("Other License"), formally executed by you and Linden Lab.  Terms of
  16.  * the GPL can be found in doc/GPL-license.txt in this distribution, or
  17.  * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  18.  * 
  19.  * There are special exceptions to the terms and conditions of the GPL as
  20.  * it is applied to this Source Code. View the full text of the exception
  21.  * in the file doc/FLOSS-exception.txt in this software distribution, or
  22.  * online at
  23.  * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  24.  * 
  25.  * By copying, modifying or distributing this software, you acknowledge
  26.  * that you have read and understood your obligations described above,
  27.  * and agree to abide by those obligations.
  28.  * 
  29.  * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  30.  * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  31.  * COMPLETENESS OR PERFORMANCE.
  32.  * $/LicenseInfo$
  33.  */
  34. #include "linden_common.h"
  35. #include "llnotificationslistener.h"
  36. #include "llnotifications.h"
  37. #include "llsd.h"
  38. #include "llui.h"
  39. LLNotificationsListener::LLNotificationsListener(LLNotifications & notifications) :
  40.     LLEventAPI("LLNotifications",
  41.                "LLNotifications listener to (e.g.) pop up a notification"),
  42.     mNotifications(notifications)
  43. {
  44.     add("requestAdd",
  45.         "Add a notification with specified ["name"], ["substitutions"] and ["payload"].n"
  46.         "If optional ["reply"] specified, arrange to send user response on that LLEventPump.",
  47.         &LLNotificationsListener::requestAdd);
  48.     add("listChannels",
  49.         "Post to ["reply"] a map of info on existing channels",
  50.         &LLNotificationsListener::listChannels,
  51.         LLSD().with("reply", LLSD()));
  52.     add("listChannelNotifications",
  53.         "Post to ["reply"] an array of info on notifications in channel ["channel"]",
  54.         &LLNotificationsListener::listChannelNotifications,
  55.         LLSD().with("reply", LLSD()).with("channel", LLSD()));
  56.     add("respond",
  57.         "Respond to notification ["uuid"] with data in ["response"]",
  58.         &LLNotificationsListener::respond,
  59.         LLSD().with("uuid", LLSD()));
  60.     add("cancel",
  61.         "Cancel notification ["uuid"]",
  62.         &LLNotificationsListener::cancel,
  63.         LLSD().with("uuid", LLSD()));
  64.     add("ignore",
  65.         "Ignore future notification ["name"]n"
  66.         "(from <notification name= > in notifications.xml)n"
  67.         "according to boolean ["ignore"].n"
  68.         "If ["name"] is omitted or undefined, [un]ignore all future notifications.n"
  69.         "Note that ignored notifications are not forwarded unless intercepted beforen"
  70.         "the "Ignore" channel.",
  71.         &LLNotificationsListener::ignore);
  72.     add("forward",
  73.         "Forward to ["pump"] future notifications on channel ["channel"]n"
  74.         "according to boolean ["forward"]. When enabled, only types matchingn"
  75.         "["types"] are forwarded, as follows:n"
  76.         "omitted or undefined: forward all notificationsn"
  77.         "string: forward only the specific named [sig]typen"
  78.         "array of string: forward any notification matching any named [sig]type.n"
  79.         "When boolean ["respond"] is true, we auto-respond to each forwardedn"
  80.         "notification.",
  81.         &LLNotificationsListener::forward,
  82.         LLSD().with("channel", LLSD()));
  83. }
  84. // This is here in the .cpp file so we don't need the definition of class
  85. // Forwarder in the header file.
  86. LLNotificationsListener::~LLNotificationsListener()
  87. {
  88. }
  89. void LLNotificationsListener::requestAdd(const LLSD& event_data) const
  90. {
  91. if(event_data.has("reply"))
  92. {
  93. mNotifications.add(event_data["name"], 
  94.    event_data["substitutions"], 
  95.    event_data["payload"],
  96.    boost::bind(&LLNotificationsListener::NotificationResponder, 
  97.    this, 
  98.    event_data["reply"].asString(), 
  99.    _1, _2
  100.    )
  101.    );
  102. }
  103. else
  104. {
  105. mNotifications.add(event_data["name"], 
  106.    event_data["substitutions"], 
  107.    event_data["payload"]);
  108. }
  109. }
  110. void LLNotificationsListener::NotificationResponder(const std::string& reply_pump, 
  111. const LLSD& notification, 
  112. const LLSD& response) const
  113. {
  114. LLSD reponse_event;
  115. reponse_event["notification"] = notification;
  116. reponse_event["response"] = response;
  117. LLEventPumps::getInstance()->obtain(reply_pump).post(reponse_event);
  118. }
  119. void LLNotificationsListener::listChannels(const LLSD& params) const
  120. {
  121.     LLReqID reqID(params);
  122.     LLSD response(reqID.makeResponse());
  123.     for (LLNotifications::ChannelMap::const_iterator cmi(mNotifications.mChannels.begin()),
  124.                                                      cmend(mNotifications.mChannels.end());
  125.          cmi != cmend; ++cmi)
  126.     {
  127.         LLSD channelInfo;
  128.         channelInfo["parent"] = cmi->second->getParentChannelName();
  129.         response[cmi->first] = channelInfo;
  130.     }
  131.     LLEventPumps::instance().obtain(params["reply"]).post(response);
  132. }
  133. void LLNotificationsListener::listChannelNotifications(const LLSD& params) const
  134. {
  135.     LLReqID reqID(params);
  136.     LLSD response(reqID.makeResponse());
  137.     LLNotificationChannelPtr channel(mNotifications.getChannel(params["channel"]));
  138.     if (channel)
  139.     {
  140.         LLSD notifications(LLSD::emptyArray());
  141.         for (LLNotificationChannel::Iterator ni(channel->begin()), nend(channel->end());
  142.              ni != nend; ++ni)
  143.         {
  144.             notifications.append(asLLSD(*ni));
  145.         }
  146.         response["notifications"] = notifications;
  147.     }
  148.     LLEventPumps::instance().obtain(params["reply"]).post(response);
  149. }
  150. void LLNotificationsListener::respond(const LLSD& params) const
  151. {
  152.     LLNotificationPtr notification(mNotifications.find(params["uuid"]));
  153.     if (notification)
  154.     {
  155.         notification->respond(params["response"]);
  156.     }
  157. }
  158. void LLNotificationsListener::cancel(const LLSD& params) const
  159. {
  160.     LLNotificationPtr notification(mNotifications.find(params["uuid"]));
  161.     if (notification)
  162.     {
  163.         mNotifications.cancel(notification);
  164.     }
  165. }
  166. void LLNotificationsListener::ignore(const LLSD& params) const
  167. {
  168.     // Calling a method named "ignore", but omitting its "ignore" Boolean
  169.     // argument, should by default cause something to be ignored. Explicitly
  170.     // pass ["ignore"] = false to cancel ignore.
  171.     bool ignore = true;
  172.     if (params.has("ignore"))
  173.     {
  174.         ignore = params["ignore"].asBoolean();
  175.     }
  176.     // This method can be used to affect either a single notification name or
  177.     // all future notifications. The two use substantially different mechanisms.
  178.     if (params["name"].isDefined())
  179.     {
  180.         // ["name"] was passed: ignore just that notification
  181.         LLUI::sSettingGroups["ignores"]->setBOOL(params["name"], ignore);
  182.     }
  183.     else
  184.     {
  185.         // no ["name"]: ignore all future notifications
  186.         mNotifications.setIgnoreAllNotifications(ignore);
  187.     }
  188. }
  189. class LLNotificationsListener::Forwarder: public LLEventTrackable
  190. {
  191.     LOG_CLASS(LLNotificationsListener::Forwarder);
  192. public:
  193.     Forwarder(LLNotifications& llnotifications, const std::string& channel):
  194.         mNotifications(llnotifications),
  195.         mRespond(false)
  196.     {
  197.         // Connect to the specified channel on construction. Because
  198.         // LLEventTrackable is a base, we should automatically disconnect when
  199.         // destroyed.
  200.         LLNotificationChannelPtr channelptr(llnotifications.getChannel(channel));
  201.         if (channelptr)
  202.         {
  203.             // Insert our processing as a "passed filter" listener. This way
  204.             // we get to run before all the "changed" listeners, and we get to
  205.             // swipe it (hide it from the other listeners) if desired.
  206.             channelptr->connectPassedFilter(boost::bind(&Forwarder::handle, this, _1));
  207.         }
  208.     }
  209.     void setPumpName(const std::string& name) { mPumpName = name; }
  210.     void setTypes(const LLSD& types) { mTypes = types; }
  211.     void setRespond(bool respond) { mRespond = respond; }
  212. private:
  213.     bool handle(const LLSD& notification) const;
  214.     bool matchType(const LLSD& filter, const std::string& type) const;
  215.     LLNotifications& mNotifications;
  216.     std::string mPumpName;
  217.     LLSD mTypes;
  218.     bool mRespond;
  219. };
  220. void LLNotificationsListener::forward(const LLSD& params)
  221. {
  222.     std::string channel(params["channel"]);
  223.     // First decide whether we're supposed to start forwarding or stop it.
  224.     // Default to true.
  225.     bool forward = true;
  226.     if (params.has("forward"))
  227.     {
  228.         forward = params["forward"].asBoolean();
  229.     }
  230.     if (! forward)
  231.     {
  232.         // This is a request to stop forwarding notifications on the specified
  233.         // channel. The rest of the params don't matter.
  234.         // Because mForwarders contains scoped_ptrs, erasing the map entry
  235.         // DOES delete the heap Forwarder object. Because Forwarder derives
  236.         // from LLEventTrackable, destroying it disconnects it from the
  237.         // channel.
  238.         mForwarders.erase(channel);
  239.         return;
  240.     }
  241.     // From here on, we know we're being asked to start (or modify) forwarding
  242.     // on the specified channel. Find or create an appropriate Forwarder.
  243.     ForwarderMap::iterator
  244.         entry(mForwarders.insert(ForwarderMap::value_type(channel, ForwarderMap::mapped_type())).first);
  245.     if (! entry->second)
  246.     {
  247.         entry->second.reset(new Forwarder(mNotifications, channel));
  248.     }
  249.     // Now, whether this Forwarder is brand-new or not, update it with the new
  250.     // request info.
  251.     Forwarder& fwd(*entry->second);
  252.     fwd.setPumpName(params["pump"]);
  253.     fwd.setTypes(params["types"]);
  254.     fwd.setRespond(params["respond"]);
  255. }
  256. bool LLNotificationsListener::Forwarder::handle(const LLSD& notification) const
  257. {
  258.     LL_INFOS("LLNotificationsListener") << "handle(" << notification << ")" << LL_ENDL;
  259.     if (notification["sigtype"].asString() == "delete")
  260.     {
  261.         LL_INFOS("LLNotificationsListener") << "ignoring delete" << LL_ENDL;
  262.         // let other listeners see the "delete" operation
  263.         return false;
  264.     }
  265.     LLNotificationPtr note(mNotifications.find(notification["id"]));
  266.     if (! note)
  267.     {
  268.         LL_INFOS("LLNotificationsListener") << notification["id"] << " not found" << LL_ENDL;
  269.         return false;
  270.     }
  271.     if (! matchType(mTypes, note->getType()))
  272.     {
  273.         LL_INFOS("LLNotificationsListener") << "didn't match types " << mTypes << LL_ENDL;
  274.         // We're not supposed to intercept this particular notification. Let
  275.         // other listeners process it.
  276.         return false;
  277.     }
  278.     LL_INFOS("LLNotificationsListener") << "sending via '" << mPumpName << "'" << LL_ENDL;
  279.     // This is a notification we care about. Forward it through specified
  280.     // LLEventPump.
  281.     LLEventPumps::instance().obtain(mPumpName).post(asLLSD(note));
  282.     // Are we also being asked to auto-respond?
  283.     if (mRespond)
  284.     {
  285.         LL_INFOS("LLNotificationsListener") << "should respond" << LL_ENDL;
  286.         note->respond(LLSD::emptyMap());
  287.         // Did that succeed in removing the notification? Only cancel() if
  288.         // it's still around -- otherwise we get an LL_ERRS crash!
  289.         note = mNotifications.find(notification["id"]);
  290.         if (note)
  291.         {
  292.             LL_INFOS("LLNotificationsListener") << "respond() didn't clear, canceling" << LL_ENDL;
  293.             mNotifications.cancel(note);
  294.         }
  295.     }
  296.     // If we've auto-responded to this notification, then it's going to be
  297.     // deleted. Other listeners would get the change operation, try to look it
  298.     // up and be baffled by lookup failure. So when we auto-respond, suppress
  299.     // this notification: don't pass it to other listeners.
  300.     return mRespond;
  301. }
  302. bool LLNotificationsListener::Forwarder::matchType(const LLSD& filter, const std::string& type) const
  303. {
  304.     // Decide whether this notification matches filter:
  305.     // undefined: forward all notifications
  306.     if (filter.isUndefined())
  307.     {
  308.         return true;
  309.     }
  310.     // array of string: forward any notification matching any named type
  311.     if (filter.isArray())
  312.     {
  313.         for (LLSD::array_const_iterator ti(filter.beginArray()), tend(filter.endArray());
  314.              ti != tend; ++ti)
  315.         {
  316.             if (ti->asString() == type)
  317.             {
  318.                 return true;
  319.             }
  320.         }
  321.         // Didn't match any entry in the array
  322.         return false;
  323.     }
  324.     // string: forward only the specific named type
  325.     return (filter.asString() == type);
  326. }
  327. LLSD LLNotificationsListener::asLLSD(LLNotificationPtr note)
  328. {
  329.     LLSD notificationInfo(note->asLLSD());
  330.     // For some reason the following aren't included in LLNotification::asLLSD().
  331.     notificationInfo["summary"] = note->summarize();
  332.     notificationInfo["id"]      = note->id();
  333.     notificationInfo["type"]    = note->getType();
  334.     notificationInfo["message"] = note->getMessage();
  335.     notificationInfo["label"]   = note->getLabel();
  336.     return notificationInfo;
  337. }