summaryrefslogtreecommitdiff
path: root/indra/llmessage/llavatarnamecache.h
blob: fe51355207c830c7ed4f7b5482017ffca1554281 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
/**
 * @file llavatarnamecache.h
 * @brief Provides lookup of avatar SLIDs ("bobsmith123") and display names
 * ("James Cook") from avatar UUIDs.
 *
 * $LicenseInfo:firstyear=2010&license=viewerlgpl$
 * Second Life Viewer Source Code
 * Copyright (C) 2010, 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$
 */

#ifndef LLAVATARNAMECACHE_H
#define LLAVATARNAMECACHE_H

#include "llavatarname.h"   // for convenience
#include "llsingleton.h"
#include <boost/signals2.hpp>
#include <set>

class LLSD;
class LLUUID;

class LLAvatarNameCache : public LLSingleton<LLAvatarNameCache>
{
    LLSINGLETON(LLAvatarNameCache);
    ~LLAvatarNameCache();
public:
    typedef boost::signals2::signal<void (void)> use_display_name_signal_t;
    typedef boost::function<void (const LLUUID id, const LLAvatarName& av_name)> account_name_changed_callback_t;

    // Import/export the name cache to file.
    bool importFile(std::istream& istr);
    void exportFile(std::ostream& ostr);

    // On the viewer, usually a simulator capabilities.
    // If empty, name cache will fall back to using legacy name lookup system.
    void setNameLookupURL(const std::string& name_lookup_url);

    // Do we have a valid lookup URL, i.e. are we trying to use the
    // more recent display name lookup system?
    bool hasNameLookupURL();
    void setUsePeopleAPI(bool use_api);
    bool usePeopleAPI();

    // Periodically makes a batch request for display names not already in
    // cache. Called once per frame.
    void idle();

    // If name is in cache, returns true and fills in provided LLAvatarName
    // otherwise returns false.
    static bool get(const LLUUID& agent_id, LLAvatarName *av_name);
    bool getName(const LLUUID& agent_id, LLAvatarName *av_name);

    // Callback types for get() below
    typedef boost::signals2::signal<
        void (const LLUUID& agent_id, const LLAvatarName& av_name)>
            callback_signal_t;
    typedef callback_signal_t::slot_type callback_slot_t;
    typedef boost::signals2::connection callback_connection_t;

    // Fetches name information and calls callbacks.
    // If name information is in cache, callbacks will be called immediately.
    static callback_connection_t get(const LLUUID& agent_id, callback_slot_t slot);
    callback_connection_t getNameCallback(const LLUUID& agent_id, callback_slot_t slot);

    // Set display name: flips the switch and triggers the callbacks.
    void setUseDisplayNames(bool use);

    void setUseUsernames(bool use);

    void insert(const LLUUID& agent_id, const LLAvatarName& av_name);
    void erase(const LLUUID& agent_id);

    // A way to find agent id by UUID, very slow, also unreliable
    // since it doesn't request names, just serch exsisting ones
    // that are likely not in cache.
    //
    // Todo: Find a way to remove this.
    // Curently this method is used for chat history and in some cases notices.
    LLUUID findIdByName(const std::string& name);

    /// Provide some fallback for agents that return errors.
    void handleAgentError(const LLUUID& agent_id);

    // Compute name expiration time from HTTP Cache-Control header,
    // or return default value, in seconds from epoch.
    F64 nameExpirationFromHeaders(const LLSD& headers);

    void addUseDisplayNamesCallback(const use_display_name_signal_t::slot_type& cb);

    void setAccountNameChangedCallback(const account_name_changed_callback_t& cb) { mAccountNameChangedCallback = cb; }

private:
    // Handle name response off network.
    void processName(const LLUUID& agent_id,
        const LLAvatarName& av_name);

    void requestNamesViaCapability();

    // Legacy name system callbacks
    static void legacyNameCallback(const LLUUID& agent_id,
        const std::string& full_name,
        bool is_group);
    static void legacyNameFetch(const LLUUID& agent_id,
        const std::string& full_name,
        bool is_group);

    void requestNamesViaLegacy();

    // Do a single callback to a given slot
    void fireSignal(const LLUUID& agent_id,
        const callback_slot_t& slot,
        const LLAvatarName& av_name);

    // Is a request in-flight over the network?
    bool isRequestPending(const LLUUID& agent_id);

    // Erase expired names from cache
    void eraseUnrefreshed();

    bool expirationFromCacheControl(const LLSD& headers, F64 *expires);

    // This is a coroutine.
    static void requestAvatarNameCache_(std::string url, std::vector<LLUUID> agentIds);

    void handleAvNameCacheSuccess(const LLSD &data, const LLSD &httpResult);

private:

    use_display_name_signal_t mUseDisplayNamesSignal;
    account_name_changed_callback_t mAccountNameChangedCallback;

    // Cache starts in a paused state until we can determine if the
    // current region supports display names.
    bool mRunning;

    // Use the People API (modern) for fetching name if true. Use the old legacy protocol if false.
    // For testing, there's a UsePeopleAPI setting that can be flipped (must restart viewer).
    bool mUsePeopleAPI;

    // Base lookup URL for name service.
    // On simulator, loaded from indra.xml
    // On viewer, usually a simulator capability (at People API team's request)
    // Includes the trailing slash, like "http://pdp60.lindenlab.com:8000/agents/"
    std::string mNameLookupURL;

    // Accumulated agent IDs for next query against service
    typedef std::set<LLUUID> ask_queue_t;
    ask_queue_t mAskQueue;

    // Agent IDs that have been requested, but with no reply.
    // Maps agent ID to frame time request was made.
    typedef std::map<LLUUID, F64> pending_queue_t;
    pending_queue_t mPendingQueue;

    // Callbacks to fire when we received a name.
    // May have multiple callbacks for a single ID, which are
    // represented as multiple slots bound to the signal.
    // Avoid copying signals via pointers.
    typedef std::map<LLUUID, callback_signal_t*> signal_map_t;
    signal_map_t mSignalMap;

    // The cache at last, i.e. avatar names we know about.
    typedef std::map<LLUUID, LLAvatarName> cache_t;
    cache_t mCache;

    // Time when unrefreshed cached names were checked last.
    F64 mLastExpireCheck;
};

// Parse a cache-control header to get the max-age delta-seconds.
// Returns true if header has max-age param and it parses correctly.
// Exported here to ease unit testing.
bool max_age_from_cache_control(const std::string& cache_control, S32 *max_age);

#endif