UserProfileCacheService.cs 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. /*
  2. * Copyright (c) Contributors, http://opensimulator.org/
  3. * See CONTRIBUTORS.TXT for a full list of copyright holders.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. * * Redistributions of source code must retain the above copyright
  8. * notice, this list of conditions and the following disclaimer.
  9. * * Redistributions in binary form must reproduce the above copyright
  10. * notice, this list of conditions and the following disclaimer in the
  11. * documentation and/or other materials provided with the distribution.
  12. * * Neither the name of the OpenSim Project nor the
  13. * names of its contributors may be used to endorse or promote products
  14. * derived from this software without specific prior written permission.
  15. *
  16. * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
  17. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  18. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  19. * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
  20. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  21. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  22. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  23. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  24. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  25. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26. */
  27. using System.Collections.Generic;
  28. using System.Reflection;
  29. using log4net;
  30. using OpenMetaverse;
  31. namespace OpenSim.Framework.Communications.Cache
  32. {
  33. /// <summary>
  34. /// Holds user profile information and retrieves it from backend services.
  35. /// </summary>
  36. public class UserProfileCacheService
  37. {
  38. private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
  39. /// <value>
  40. /// Standard format for names.
  41. /// </value>
  42. public const string NAME_FORMAT = "{0} {1}";
  43. /// <summary>
  44. /// The comms manager holds references to services (user, grid, inventory, etc.)
  45. /// </summary>
  46. private readonly CommunicationsManager m_commsManager;
  47. /// <summary>
  48. /// User profiles indexed by UUID
  49. /// </summary>
  50. private readonly Dictionary<UUID, CachedUserInfo> m_userProfilesById
  51. = new Dictionary<UUID, CachedUserInfo>();
  52. /// <summary>
  53. /// User profiles indexed by name
  54. /// </summary>
  55. private readonly Dictionary<string, CachedUserInfo> m_userProfilesByName
  56. = new Dictionary<string, CachedUserInfo>();
  57. /// <summary>
  58. /// The root library folder.
  59. /// </summary>
  60. public readonly InventoryFolderImpl LibraryRoot;
  61. /// <summary>
  62. /// Constructor
  63. /// </summary>
  64. /// <param name="commsManager"></param>
  65. /// <param name="libraryRootFolder"></param>
  66. public UserProfileCacheService(CommunicationsManager commsManager, LibraryRootFolder libraryRootFolder)
  67. {
  68. m_commsManager = commsManager;
  69. LibraryRoot = libraryRootFolder;
  70. }
  71. /// <summary>
  72. /// A new user has moved into a region in this instance so retrieve their profile from the user service.
  73. /// </summary>
  74. ///
  75. /// It isn't strictly necessary to make this call since user data can be lazily requested later on. However,
  76. /// it might be helpful in order to avoid an initial response delay later on
  77. ///
  78. /// <param name="userID"></param>
  79. public void AddNewUser(UUID userID)
  80. {
  81. if (userID == UUID.Zero)
  82. return;
  83. //m_log.DebugFormat("[USER CACHE]: Adding user profile for {0}", userID);
  84. GetUserDetails(userID);
  85. }
  86. /// <summary>
  87. /// Remove this user's profile cache.
  88. /// </summary>
  89. /// <param name="userID"></param>
  90. /// <returns>true if the user was successfully removed, false otherwise</returns>
  91. public bool RemoveUser(UUID userId)
  92. {
  93. if (!RemoveFromCaches(userId))
  94. {
  95. m_log.WarnFormat(
  96. "[USER CACHE]: Tried to remove the profile of user {0}, but this was not in the scene", userId);
  97. return false;
  98. }
  99. return true;
  100. }
  101. /// <summary>
  102. /// Get details of the given user.
  103. /// </summary>
  104. /// If the user isn't in cache then the user is requested from the profile service.
  105. /// <param name="userID"></param>
  106. /// <returns>null if no user details are found</returns>
  107. public CachedUserInfo GetUserDetails(string fname, string lname)
  108. {
  109. lock (m_userProfilesByName)
  110. {
  111. CachedUserInfo userInfo;
  112. if (m_userProfilesByName.TryGetValue(string.Format(NAME_FORMAT, fname, lname), out userInfo))
  113. {
  114. return userInfo;
  115. }
  116. else
  117. {
  118. UserProfileData userProfile = m_commsManager.UserService.GetUserProfile(fname, lname);
  119. if (userProfile != null)
  120. return AddToCaches(userProfile);
  121. else
  122. return null;
  123. }
  124. }
  125. }
  126. /// <summary>
  127. /// Get details of the given user.
  128. /// </summary>
  129. /// If the user isn't in cache then the user is requested from the profile service.
  130. /// <param name="userID"></param>
  131. /// <returns>null if no user details are found</returns>
  132. public CachedUserInfo GetUserDetails(UUID userID)
  133. {
  134. if (userID == UUID.Zero)
  135. return null;
  136. lock (m_userProfilesById)
  137. {
  138. if (m_userProfilesById.ContainsKey(userID))
  139. {
  140. return m_userProfilesById[userID];
  141. }
  142. else
  143. {
  144. UserProfileData userProfile = m_commsManager.UserService.GetUserProfile(userID);
  145. if (userProfile != null)
  146. return AddToCaches(userProfile);
  147. else
  148. return null;
  149. }
  150. }
  151. }
  152. /// <summary>
  153. /// Update an existing profile
  154. /// </summary>
  155. /// <param name="userProfile"></param>
  156. /// <returns>true if a user profile was found to update, false otherwise</returns>
  157. // Commented out for now. The implementation needs to be improved by protecting against race conditions,
  158. // probably by making sure that the update doesn't use the UserCacheInfo.UserProfile directly (possibly via
  159. // returning a read only class from the cache).
  160. // public bool UpdateProfile(UserProfileData userProfile)
  161. // {
  162. // lock (m_userProfilesById)
  163. // {
  164. // CachedUserInfo userInfo = GetUserDetails(userProfile.ID);
  165. //
  166. // if (userInfo != null)
  167. // {
  168. // userInfo.m_userProfile = userProfile;
  169. // m_commsManager.UserService.UpdateUserProfile(userProfile);
  170. //
  171. // return true;
  172. // }
  173. // }
  174. //
  175. // return false;
  176. // }
  177. /// <summary>
  178. /// Populate caches with the given user profile
  179. /// </summary>
  180. /// <param name="userProfile"></param>
  181. protected CachedUserInfo AddToCaches(UserProfileData userProfile)
  182. {
  183. CachedUserInfo createdUserInfo = new CachedUserInfo(m_commsManager, userProfile);
  184. lock (m_userProfilesById)
  185. {
  186. m_userProfilesById[createdUserInfo.UserProfile.ID] = createdUserInfo;
  187. lock (m_userProfilesByName)
  188. {
  189. m_userProfilesByName[createdUserInfo.UserProfile.Name] = createdUserInfo;
  190. }
  191. }
  192. return createdUserInfo;
  193. }
  194. /// <summary>
  195. /// Remove profile belong to the given uuid from the caches
  196. /// </summary>
  197. /// <param name="userUuid"></param>
  198. /// <returns>true if there was a profile to remove, false otherwise</returns>
  199. protected bool RemoveFromCaches(UUID userId)
  200. {
  201. lock (m_userProfilesById)
  202. {
  203. if (m_userProfilesById.ContainsKey(userId))
  204. {
  205. CachedUserInfo userInfo = m_userProfilesById[userId];
  206. m_userProfilesById.Remove(userId);
  207. lock (m_userProfilesByName)
  208. {
  209. m_userProfilesByName.Remove(userInfo.UserProfile.Name);
  210. }
  211. return true;
  212. }
  213. }
  214. return false;
  215. }
  216. /// <summary>
  217. /// Preloads User data into the region cache. Modules may use this service to add non-standard clients
  218. /// </summary>
  219. /// <param name="userData"></param>
  220. public void PreloadUserCache(UserProfileData userData)
  221. {
  222. AddToCaches(userData);
  223. }
  224. }
  225. }