diff options
Diffstat (limited to 'OpenSim/Services')
-rw-r--r-- | OpenSim/Services/Connectors/Inventory/XInventoryServicesConnector.cs | 285 |
1 files changed, 219 insertions, 66 deletions
diff --git a/OpenSim/Services/Connectors/Inventory/XInventoryServicesConnector.cs b/OpenSim/Services/Connectors/Inventory/XInventoryServicesConnector.cs index 36d4ae2..f235446 100644 --- a/OpenSim/Services/Connectors/Inventory/XInventoryServicesConnector.cs +++ b/OpenSim/Services/Connectors/Inventory/XInventoryServicesConnector.cs | |||
@@ -33,22 +33,37 @@ using System.Reflection; | |||
33 | using Nini.Config; | 33 | using Nini.Config; |
34 | using OpenSim.Framework; | 34 | using OpenSim.Framework; |
35 | using OpenSim.Framework.Console; | 35 | using OpenSim.Framework.Console; |
36 | using OpenSim.Framework.Communications; | 36 | |
37 | using OpenSim.Framework.Monitoring; | ||
37 | using OpenSim.Services.Interfaces; | 38 | using OpenSim.Services.Interfaces; |
38 | using OpenSim.Server.Base; | 39 | using OpenSim.Server.Base; |
39 | using OpenMetaverse; | 40 | using OpenMetaverse; |
40 | 41 | ||
41 | namespace OpenSim.Services.Connectors | 42 | namespace OpenSim.Services.Connectors |
42 | { | 43 | { |
43 | public class XInventoryServicesConnector : IInventoryService | 44 | public class XInventoryServicesConnector : BaseServiceConnector, IInventoryService |
44 | { | 45 | { |
45 | private static readonly ILog m_log = | 46 | private static readonly ILog m_log = |
46 | LogManager.GetLogger( | 47 | LogManager.GetLogger( |
47 | MethodBase.GetCurrentMethod().DeclaringType); | 48 | MethodBase.GetCurrentMethod().DeclaringType); |
48 | 49 | ||
50 | /// <summary> | ||
51 | /// Number of requests made to the remote inventory service. | ||
52 | /// </summary> | ||
53 | public int RequestsMade { get; private set; } | ||
54 | |||
49 | private string m_ServerURI = String.Empty; | 55 | private string m_ServerURI = String.Empty; |
50 | 56 | ||
51 | private object m_Lock = new object(); | 57 | /// <summary> |
58 | /// Timeout for remote requests. | ||
59 | /// </summary> | ||
60 | /// <remarks> | ||
61 | /// In this case, -1 is default timeout (100 seconds), not infinite. | ||
62 | /// </remarks> | ||
63 | private int m_requestTimeoutSecs = -1; | ||
64 | |||
65 | private const double CACHE_EXPIRATION_SECONDS = 20.0; | ||
66 | private static ExpiringCache<UUID, InventoryItemBase> m_ItemCache = new ExpiringCache<UUID,InventoryItemBase>(); | ||
52 | 67 | ||
53 | public XInventoryServicesConnector() | 68 | public XInventoryServicesConnector() |
54 | { | 69 | { |
@@ -60,20 +75,21 @@ namespace OpenSim.Services.Connectors | |||
60 | } | 75 | } |
61 | 76 | ||
62 | public XInventoryServicesConnector(IConfigSource source) | 77 | public XInventoryServicesConnector(IConfigSource source) |
78 | : base(source, "InventoryService") | ||
63 | { | 79 | { |
64 | Initialise(source); | 80 | Initialise(source); |
65 | } | 81 | } |
66 | 82 | ||
67 | public virtual void Initialise(IConfigSource source) | 83 | public virtual void Initialise(IConfigSource source) |
68 | { | 84 | { |
69 | IConfig assetConfig = source.Configs["InventoryService"]; | 85 | IConfig config = source.Configs["InventoryService"]; |
70 | if (assetConfig == null) | 86 | if (config == null) |
71 | { | 87 | { |
72 | m_log.Error("[INVENTORY CONNECTOR]: InventoryService missing from OpenSim.ini"); | 88 | m_log.Error("[INVENTORY CONNECTOR]: InventoryService missing from OpenSim.ini"); |
73 | throw new Exception("Inventory connector init error"); | 89 | throw new Exception("Inventory connector init error"); |
74 | } | 90 | } |
75 | 91 | ||
76 | string serviceURI = assetConfig.GetString("InventoryServerURI", | 92 | string serviceURI = config.GetString("InventoryServerURI", |
77 | String.Empty); | 93 | String.Empty); |
78 | 94 | ||
79 | if (serviceURI == String.Empty) | 95 | if (serviceURI == String.Empty) |
@@ -82,6 +98,21 @@ namespace OpenSim.Services.Connectors | |||
82 | throw new Exception("Inventory connector init error"); | 98 | throw new Exception("Inventory connector init error"); |
83 | } | 99 | } |
84 | m_ServerURI = serviceURI; | 100 | m_ServerURI = serviceURI; |
101 | |||
102 | m_requestTimeoutSecs = config.GetInt("RemoteRequestTimeout", m_requestTimeoutSecs); | ||
103 | |||
104 | StatsManager.RegisterStat( | ||
105 | new Stat( | ||
106 | "RequestsMade", | ||
107 | "Requests made", | ||
108 | "Number of requests made to the remove inventory service", | ||
109 | "requests", | ||
110 | "inventory", | ||
111 | serviceURI, | ||
112 | StatType.Pull, | ||
113 | MeasuresOfInterest.AverageChangeOverTime, | ||
114 | s => s.Value = RequestsMade, | ||
115 | StatVerbosity.Debug)); | ||
85 | } | 116 | } |
86 | 117 | ||
87 | private bool CheckReturn(Dictionary<string, object> ret) | 118 | private bool CheckReturn(Dictionary<string, object> ret) |
@@ -158,7 +189,7 @@ namespace OpenSim.Services.Connectors | |||
158 | return BuildFolder((Dictionary<string, object>)ret["folder"]); | 189 | return BuildFolder((Dictionary<string, object>)ret["folder"]); |
159 | } | 190 | } |
160 | 191 | ||
161 | public InventoryFolderBase GetFolderForType(UUID principalID, AssetType type) | 192 | public InventoryFolderBase GetFolderForType(UUID principalID, FolderType type) |
162 | { | 193 | { |
163 | Dictionary<string,object> ret = MakeRequest("GETFOLDERFORTYPE", | 194 | Dictionary<string,object> ret = MakeRequest("GETFOLDERFORTYPE", |
164 | new Dictionary<string,object> { | 195 | new Dictionary<string,object> { |
@@ -177,7 +208,7 @@ namespace OpenSim.Services.Connectors | |||
177 | InventoryCollection inventory = new InventoryCollection(); | 208 | InventoryCollection inventory = new InventoryCollection(); |
178 | inventory.Folders = new List<InventoryFolderBase>(); | 209 | inventory.Folders = new List<InventoryFolderBase>(); |
179 | inventory.Items = new List<InventoryItemBase>(); | 210 | inventory.Items = new List<InventoryItemBase>(); |
180 | inventory.UserID = principalID; | 211 | inventory.OwnerID = principalID; |
181 | 212 | ||
182 | try | 213 | try |
183 | { | 214 | { |
@@ -190,15 +221,17 @@ namespace OpenSim.Services.Connectors | |||
190 | if (!CheckReturn(ret)) | 221 | if (!CheckReturn(ret)) |
191 | return null; | 222 | return null; |
192 | 223 | ||
193 | Dictionary<string,object> folders = | 224 | Dictionary<string,object> folders = ret.ContainsKey("FOLDERS") ? |
194 | (Dictionary<string,object>)ret["FOLDERS"]; | 225 | (Dictionary<string,object>)ret["FOLDERS"] : null; |
195 | Dictionary<string,object> items = | 226 | Dictionary<string,object> items = ret.ContainsKey("ITEMS") ? |
196 | (Dictionary<string,object>)ret["ITEMS"]; | 227 | (Dictionary<string, object>)ret["ITEMS"] : null; |
197 | 228 | ||
198 | foreach (Object o in folders.Values) // getting the values directly, we don't care about the keys folder_i | 229 | if (folders != null) |
199 | inventory.Folders.Add(BuildFolder((Dictionary<string, object>)o)); | 230 | foreach (Object o in folders.Values) // getting the values directly, we don't care about the keys folder_i |
200 | foreach (Object o in items.Values) // getting the values directly, we don't care about the keys item_i | 231 | inventory.Folders.Add(BuildFolder((Dictionary<string, object>)o)); |
201 | inventory.Items.Add(BuildItem((Dictionary<string, object>)o)); | 232 | if (items != null) |
233 | foreach (Object o in items.Values) // getting the values directly, we don't care about the keys item_i | ||
234 | inventory.Items.Add(BuildItem((Dictionary<string, object>)o)); | ||
202 | } | 235 | } |
203 | catch (Exception e) | 236 | catch (Exception e) |
204 | { | 237 | { |
@@ -207,6 +240,87 @@ namespace OpenSim.Services.Connectors | |||
207 | 240 | ||
208 | return inventory; | 241 | return inventory; |
209 | } | 242 | } |
243 | |||
244 | public virtual InventoryCollection[] GetMultipleFoldersContent(UUID principalID, UUID[] folderIDs) | ||
245 | { | ||
246 | InventoryCollection[] inventoryArr = new InventoryCollection[folderIDs.Length]; | ||
247 | // m_log.DebugFormat("[XXX]: In GetMultipleFoldersContent {0}", String.Join(",", folderIDs)); | ||
248 | try | ||
249 | { | ||
250 | Dictionary<string, object> resultSet = MakeRequest("GETMULTIPLEFOLDERSCONTENT", | ||
251 | new Dictionary<string, object> { | ||
252 | { "PRINCIPAL", principalID.ToString() }, | ||
253 | { "FOLDERS", String.Join(",", folderIDs) }, | ||
254 | { "COUNT", folderIDs.Length.ToString() } | ||
255 | }); | ||
256 | |||
257 | if (!CheckReturn(resultSet)) | ||
258 | return null; | ||
259 | |||
260 | int i = 0; | ||
261 | foreach (KeyValuePair<string, object> kvp in resultSet) | ||
262 | { | ||
263 | InventoryCollection inventory = new InventoryCollection(); | ||
264 | if (kvp.Key.StartsWith("F_")) | ||
265 | { | ||
266 | UUID fid = UUID.Zero; | ||
267 | if (UUID.TryParse(kvp.Key.Substring(2), out fid) && fid == folderIDs[i]) | ||
268 | { | ||
269 | inventory.Folders = new List<InventoryFolderBase>(); | ||
270 | inventory.Items = new List<InventoryItemBase>(); | ||
271 | |||
272 | Dictionary<string, object> ret = (Dictionary<string, object>)kvp.Value; | ||
273 | |||
274 | if (ret.ContainsKey("FID")) | ||
275 | { | ||
276 | if (!UUID.TryParse(ret["FID"].ToString(), out inventory.FolderID)) | ||
277 | m_log.WarnFormat("[XINVENTORY SERVICES CONNECTOR]: Could not parse folder id {0}", ret["FID"].ToString()); | ||
278 | } | ||
279 | else | ||
280 | m_log.WarnFormat("[XINVENTORY SERVICES CONNECTOR]: FID key not present in response"); | ||
281 | |||
282 | inventory.Version = -1; | ||
283 | if (ret.ContainsKey("VERSION")) | ||
284 | Int32.TryParse(ret["VERSION"].ToString(), out inventory.Version); | ||
285 | if (ret.ContainsKey("OWNER")) | ||
286 | UUID.TryParse(ret["OWNER"].ToString(), out inventory.OwnerID); | ||
287 | |||
288 | //m_log.DebugFormat("[XXX]: Received {0} ({1}) {2} {3}", inventory.FolderID, fid, inventory.Version, inventory.OwnerID); | ||
289 | |||
290 | Dictionary<string, object> folders = | ||
291 | (Dictionary<string, object>)ret["FOLDERS"]; | ||
292 | Dictionary<string, object> items = | ||
293 | (Dictionary<string, object>)ret["ITEMS"]; | ||
294 | |||
295 | foreach (Object o in folders.Values) // getting the values directly, we don't care about the keys folder_i | ||
296 | { | ||
297 | inventory.Folders.Add(BuildFolder((Dictionary<string, object>)o)); | ||
298 | } | ||
299 | foreach (Object o in items.Values) // getting the values directly, we don't care about the keys item_i | ||
300 | { | ||
301 | inventory.Items.Add(BuildItem((Dictionary<string, object>)o)); | ||
302 | } | ||
303 | |||
304 | inventoryArr[i] = inventory; | ||
305 | } | ||
306 | else | ||
307 | { | ||
308 | m_log.WarnFormat("[XINVENTORY SERVICES CONNECTOR]: Folder id does not match. Expected {0} got {1}", | ||
309 | folderIDs[i], fid); | ||
310 | m_log.WarnFormat("[XINVENTORY SERVICES CONNECTOR]: {0} {1}", String.Join(",", folderIDs), String.Join(",", resultSet.Keys)); | ||
311 | } | ||
312 | |||
313 | i += 1; | ||
314 | } | ||
315 | } | ||
316 | } | ||
317 | catch (Exception e) | ||
318 | { | ||
319 | m_log.WarnFormat("[XINVENTORY SERVICES CONNECTOR]: Exception in GetMultipleFoldersContent: {0}", e.Message); | ||
320 | } | ||
321 | |||
322 | return inventoryArr; | ||
323 | } | ||
210 | 324 | ||
211 | public List<InventoryItemBase> GetFolderItems(UUID principalID, UUID folderID) | 325 | public List<InventoryItemBase> GetFolderItems(UUID principalID, UUID folderID) |
212 | { | 326 | { |
@@ -297,9 +411,13 @@ namespace OpenSim.Services.Connectors | |||
297 | 411 | ||
298 | public bool AddItem(InventoryItemBase item) | 412 | public bool AddItem(InventoryItemBase item) |
299 | { | 413 | { |
414 | if (item.Description == null) | ||
415 | item.Description = String.Empty; | ||
300 | if (item.CreatorData == null) | 416 | if (item.CreatorData == null) |
301 | item.CreatorData = String.Empty; | 417 | item.CreatorData = String.Empty; |
302 | Dictionary<string,object> ret = MakeRequest("ADDITEM", | 418 | if (item.CreatorId == null) |
419 | item.CreatorId = String.Empty; | ||
420 | Dictionary<string, object> ret = MakeRequest("ADDITEM", | ||
303 | new Dictionary<string,object> { | 421 | new Dictionary<string,object> { |
304 | { "AssetID", item.AssetID.ToString() }, | 422 | { "AssetID", item.AssetID.ToString() }, |
305 | { "AssetType", item.AssetType.ToString() }, | 423 | { "AssetType", item.AssetType.ToString() }, |
@@ -398,6 +516,10 @@ namespace OpenSim.Services.Connectors | |||
398 | 516 | ||
399 | public InventoryItemBase GetItem(InventoryItemBase item) | 517 | public InventoryItemBase GetItem(InventoryItemBase item) |
400 | { | 518 | { |
519 | InventoryItemBase retrieved = null; | ||
520 | if (m_ItemCache.TryGetValue(item.ID, out retrieved)) | ||
521 | return retrieved; | ||
522 | |||
401 | try | 523 | try |
402 | { | 524 | { |
403 | Dictionary<string, object> ret = MakeRequest("GETITEM", | 525 | Dictionary<string, object> ret = MakeRequest("GETITEM", |
@@ -408,14 +530,78 @@ namespace OpenSim.Services.Connectors | |||
408 | if (!CheckReturn(ret)) | 530 | if (!CheckReturn(ret)) |
409 | return null; | 531 | return null; |
410 | 532 | ||
411 | return BuildItem((Dictionary<string, object>)ret["item"]); | 533 | retrieved = BuildItem((Dictionary<string, object>)ret["item"]); |
412 | } | 534 | } |
413 | catch (Exception e) | 535 | catch (Exception e) |
414 | { | 536 | { |
415 | m_log.Error("[XINVENTORY SERVICES CONNECTOR]: Exception in GetItem: ", e); | 537 | m_log.Error("[XINVENTORY SERVICES CONNECTOR]: Exception in GetItem: ", e); |
416 | } | 538 | } |
417 | 539 | ||
418 | return null; | 540 | m_ItemCache.AddOrUpdate(item.ID, retrieved, CACHE_EXPIRATION_SECONDS); |
541 | |||
542 | return retrieved; | ||
543 | } | ||
544 | |||
545 | public virtual InventoryItemBase[] GetMultipleItems(UUID principalID, UUID[] itemIDs) | ||
546 | { | ||
547 | //m_log.DebugFormat("[XXX]: In GetMultipleItems {0}", String.Join(",", itemIDs)); | ||
548 | |||
549 | InventoryItemBase[] itemArr = new InventoryItemBase[itemIDs.Length]; | ||
550 | // Try to get them from the cache | ||
551 | List<UUID> pending = new List<UUID>(); | ||
552 | InventoryItemBase item = null; | ||
553 | int i = 0; | ||
554 | foreach (UUID id in itemIDs) | ||
555 | { | ||
556 | if (m_ItemCache.TryGetValue(id, out item)) | ||
557 | itemArr[i++] = item; | ||
558 | else | ||
559 | pending.Add(id); | ||
560 | } | ||
561 | |||
562 | if (pending.Count == 0) // we're done, everything was in the cache | ||
563 | return itemArr; | ||
564 | |||
565 | try | ||
566 | { | ||
567 | Dictionary<string, object> resultSet = MakeRequest("GETMULTIPLEITEMS", | ||
568 | new Dictionary<string, object> { | ||
569 | { "PRINCIPAL", principalID.ToString() }, | ||
570 | { "ITEMS", String.Join(",", pending.ToArray()) }, | ||
571 | { "COUNT", pending.Count.ToString() } | ||
572 | }); | ||
573 | |||
574 | if (!CheckReturn(resultSet)) | ||
575 | { | ||
576 | if (i == 0) | ||
577 | return null; | ||
578 | else | ||
579 | return itemArr; | ||
580 | } | ||
581 | |||
582 | // carry over index i where we left above | ||
583 | foreach (KeyValuePair<string, object> kvp in resultSet) | ||
584 | { | ||
585 | InventoryCollection inventory = new InventoryCollection(); | ||
586 | if (kvp.Key.StartsWith("item_")) | ||
587 | { | ||
588 | if (kvp.Value is Dictionary<string, object>) | ||
589 | { | ||
590 | item = BuildItem((Dictionary<string, object>)kvp.Value); | ||
591 | m_ItemCache.AddOrUpdate(item.ID, item, CACHE_EXPIRATION_SECONDS); | ||
592 | itemArr[i++] = item; | ||
593 | } | ||
594 | else | ||
595 | itemArr[i++] = null; | ||
596 | } | ||
597 | } | ||
598 | } | ||
599 | catch (Exception e) | ||
600 | { | ||
601 | m_log.WarnFormat("[XINVENTORY SERVICES CONNECTOR]: Exception in GetMultipleItems: {0}", e.Message); | ||
602 | } | ||
603 | |||
604 | return itemArr; | ||
419 | } | 605 | } |
420 | 606 | ||
421 | public InventoryFolderBase GetFolder(InventoryFolderBase folder) | 607 | public InventoryFolderBase GetFolder(InventoryFolderBase folder) |
@@ -484,45 +670,6 @@ namespace OpenSim.Services.Connectors | |||
484 | return 0; | 670 | return 0; |
485 | } | 671 | } |
486 | 672 | ||
487 | public InventoryCollection GetUserInventory(UUID principalID) | ||
488 | { | ||
489 | InventoryCollection inventory = new InventoryCollection(); | ||
490 | inventory.Folders = new List<InventoryFolderBase>(); | ||
491 | inventory.Items = new List<InventoryItemBase>(); | ||
492 | inventory.UserID = principalID; | ||
493 | |||
494 | try | ||
495 | { | ||
496 | Dictionary<string, object> ret = MakeRequest("GETUSERINVENTORY", | ||
497 | new Dictionary<string, object> { | ||
498 | { "PRINCIPAL", principalID.ToString() } | ||
499 | }); | ||
500 | |||
501 | if (!CheckReturn(ret)) | ||
502 | return null; | ||
503 | |||
504 | Dictionary<string, object> folders = | ||
505 | (Dictionary<string, object>)ret["FOLDERS"]; | ||
506 | Dictionary<string, object> items = | ||
507 | (Dictionary<string, object>)ret["ITEMS"]; | ||
508 | |||
509 | foreach (Object o in folders.Values) // getting the values directly, we don't care about the keys folder_i | ||
510 | inventory.Folders.Add(BuildFolder((Dictionary<string, object>)o)); | ||
511 | foreach (Object o in items.Values) // getting the values directly, we don't care about the keys item_i | ||
512 | inventory.Items.Add(BuildItem((Dictionary<string, object>)o)); | ||
513 | } | ||
514 | catch (Exception e) | ||
515 | { | ||
516 | m_log.Error("[XINVENTORY SERVICES CONNECTOR]: Exception in GetUserInventory: ", e); | ||
517 | } | ||
518 | |||
519 | return inventory; | ||
520 | } | ||
521 | |||
522 | public void GetUserInventory(UUID principalID, InventoryReceiptCallback callback) | ||
523 | { | ||
524 | } | ||
525 | |||
526 | public bool HasInventoryForUser(UUID principalID) | 673 | public bool HasInventoryForUser(UUID principalID) |
527 | { | 674 | { |
528 | return false; | 675 | return false; |
@@ -533,13 +680,19 @@ namespace OpenSim.Services.Connectors | |||
533 | private Dictionary<string,object> MakeRequest(string method, | 680 | private Dictionary<string,object> MakeRequest(string method, |
534 | Dictionary<string,object> sendData) | 681 | Dictionary<string,object> sendData) |
535 | { | 682 | { |
536 | sendData["METHOD"] = method; | 683 | // Add "METHOD" as the first key in the dictionary. This ensures that it will be |
684 | // visible even when using partial logging ("debug http all 5"). | ||
685 | Dictionary<string, object> temp = sendData; | ||
686 | sendData = new Dictionary<string,object>{ { "METHOD", method } }; | ||
687 | foreach (KeyValuePair<string, object> kvp in temp) | ||
688 | sendData.Add(kvp.Key, kvp.Value); | ||
689 | |||
690 | RequestsMade++; | ||
537 | 691 | ||
538 | string reply = string.Empty; | 692 | string reply |
539 | lock (m_Lock) | 693 | = SynchronousRestFormsRequester.MakeRequest( |
540 | reply = SynchronousRestFormsRequester.MakeRequest("POST", | 694 | "POST", m_ServerURI + "/xinventory", |
541 | m_ServerURI + "/xinventory", | 695 | ServerUtils.BuildQueryString(sendData), m_requestTimeoutSecs, m_Auth); |
542 | ServerUtils.BuildQueryString(sendData)); | ||
543 | 696 | ||
544 | Dictionary<string, object> replyData = ServerUtils.ParseXmlResponse( | 697 | Dictionary<string, object> replyData = ServerUtils.ParseXmlResponse( |
545 | reply); | 698 | reply); |
@@ -607,4 +760,4 @@ namespace OpenSim.Services.Connectors | |||
607 | return item; | 760 | return item; |
608 | } | 761 | } |
609 | } | 762 | } |
610 | } \ No newline at end of file | 763 | } |