XInventoryServicesConnector.cs 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799
  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 OpenSimulator 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 log4net;
  28. using System;
  29. using System.Collections.Generic;
  30. using System.IO;
  31. using System.Reflection;
  32. using Nini.Config;
  33. using OpenSim.Framework;
  34. using OpenSim.Framework.Console;
  35. using OpenSim.Framework.Monitoring;
  36. using OpenSim.Services.Interfaces;
  37. using OpenSim.Server.Base;
  38. using OpenMetaverse;
  39. namespace OpenSim.Services.Connectors
  40. {
  41. public class XInventoryServicesConnector : BaseServiceConnector, IInventoryService
  42. {
  43. private static readonly ILog m_log =
  44. LogManager.GetLogger(
  45. MethodBase.GetCurrentMethod().DeclaringType);
  46. /// <summary>
  47. /// Number of requests made to the remote inventory service.
  48. /// </summary>
  49. public int RequestsMade { get; private set; }
  50. private string m_ServerURI = String.Empty;
  51. /// <summary>
  52. /// Timeout for remote requests.
  53. /// </summary>
  54. /// <remarks>
  55. /// In this case, -1 is default timeout (100 seconds), not infinite.
  56. /// </remarks>
  57. private int m_requestTimeoutSecs = -1;
  58. private string m_configName = "InventoryService";
  59. private const double CACHE_EXPIRATION_SECONDS = 20.0;
  60. private static ExpiringCache<UUID, InventoryItemBase> m_ItemCache = new ExpiringCache<UUID,InventoryItemBase>();
  61. public XInventoryServicesConnector()
  62. {
  63. }
  64. public XInventoryServicesConnector(string serverURI)
  65. {
  66. m_ServerURI = serverURI.TrimEnd('/');
  67. }
  68. public XInventoryServicesConnector(IConfigSource source, string configName)
  69. : base(source, configName)
  70. {
  71. m_configName = configName;
  72. Initialise(source);
  73. }
  74. public XInventoryServicesConnector(IConfigSource source)
  75. : base(source, "InventoryService")
  76. {
  77. Initialise(source);
  78. }
  79. public virtual void Initialise(IConfigSource source)
  80. {
  81. IConfig config = source.Configs[m_configName];
  82. if (config == null)
  83. {
  84. m_log.ErrorFormat("[INVENTORY CONNECTOR]: {0} missing from OpenSim.ini", m_configName);
  85. throw new Exception("Inventory connector init error");
  86. }
  87. string serviceURI = config.GetString("InventoryServerURI",
  88. String.Empty);
  89. if (serviceURI == String.Empty)
  90. {
  91. m_log.Error("[INVENTORY CONNECTOR]: No Server URI named in section InventoryService");
  92. throw new Exception("Inventory connector init error");
  93. }
  94. m_ServerURI = serviceURI;
  95. m_requestTimeoutSecs = config.GetInt("RemoteRequestTimeout", m_requestTimeoutSecs);
  96. StatsManager.RegisterStat(
  97. new Stat(
  98. "RequestsMade",
  99. "Requests made",
  100. "Number of requests made to the remove inventory service",
  101. "requests",
  102. "inventory",
  103. serviceURI,
  104. StatType.Pull,
  105. MeasuresOfInterest.AverageChangeOverTime,
  106. s => s.Value = RequestsMade,
  107. StatVerbosity.Debug));
  108. }
  109. private bool CheckReturn(Dictionary<string, object> ret)
  110. {
  111. if (ret == null)
  112. return false;
  113. if (ret.Count == 0)
  114. return false;
  115. if (ret.ContainsKey("RESULT"))
  116. {
  117. if (ret["RESULT"] is string)
  118. {
  119. bool result;
  120. if (bool.TryParse((string)ret["RESULT"], out result))
  121. return result;
  122. return false;
  123. }
  124. }
  125. return true;
  126. }
  127. public bool CreateUserInventory(UUID principalID)
  128. {
  129. Dictionary<string,object> ret = MakeRequest(
  130. new Dictionary<string,object> {
  131. { "METHOD", "CREATEUSERINVENTORY"},
  132. { "PRINCIPAL", principalID.ToString() }
  133. });
  134. return CheckReturn(ret);
  135. }
  136. public List<InventoryFolderBase> GetInventorySkeleton(UUID principalID)
  137. {
  138. Dictionary<string,object> ret = MakeRequest(
  139. new Dictionary<string,object> {
  140. { "METHOD", "GETINVENTORYSKELETON"},
  141. { "PRINCIPAL", principalID.ToString() }
  142. });
  143. if (!CheckReturn(ret))
  144. return null;
  145. Dictionary<string, object> folders = (Dictionary<string, object>)ret["FOLDERS"];
  146. List<InventoryFolderBase> fldrs = new List<InventoryFolderBase>();
  147. try
  148. {
  149. foreach (Object o in folders.Values)
  150. fldrs.Add(BuildFolder((Dictionary<string, object>)o));
  151. }
  152. catch (Exception e)
  153. {
  154. m_log.Error("[XINVENTORY SERVICES CONNECTOR]: Exception unwrapping folder list: ", e);
  155. }
  156. return fldrs;
  157. }
  158. public InventoryFolderBase GetRootFolder(UUID principalID)
  159. {
  160. Dictionary<string,object> ret = MakeRequest(
  161. new Dictionary<string,object> {
  162. { "METHOD", "GETROOTFOLDER"},
  163. { "PRINCIPAL", principalID.ToString() }
  164. });
  165. if (!CheckReturn(ret))
  166. return null;
  167. return BuildFolder((Dictionary<string, object>)ret["folder"]);
  168. }
  169. public InventoryFolderBase GetFolderForType(UUID principalID, FolderType type)
  170. {
  171. Dictionary<string,object> ret = MakeRequest(
  172. new Dictionary<string,object> {
  173. { "METHOD", "GETFOLDERFORTYPE"},
  174. { "PRINCIPAL", principalID.ToString() },
  175. { "TYPE", ((int)type).ToString() }
  176. });
  177. if (!CheckReturn(ret))
  178. return null;
  179. return BuildFolder((Dictionary<string, object>)ret["folder"]);
  180. }
  181. public InventoryCollection GetFolderContent(UUID principalID, UUID folderID)
  182. {
  183. InventoryCollection inventory = new InventoryCollection();
  184. inventory.Folders = new List<InventoryFolderBase>();
  185. inventory.Items = new List<InventoryItemBase>();
  186. inventory.OwnerID = principalID;
  187. try
  188. {
  189. Dictionary<string,object> ret = MakeRequest(
  190. new Dictionary<string,object> {
  191. { "METHOD", "GETFOLDERCONTENT"},
  192. { "PRINCIPAL", principalID.ToString() },
  193. { "FOLDER", folderID.ToString() }
  194. });
  195. if (!CheckReturn(ret))
  196. return null;
  197. Dictionary<string,object> folders = ret.ContainsKey("FOLDERS") ?
  198. (Dictionary<string,object>)ret["FOLDERS"] : null;
  199. Dictionary<string,object> items = ret.ContainsKey("ITEMS") ?
  200. (Dictionary<string, object>)ret["ITEMS"] : null;
  201. if (folders != null)
  202. foreach (Object o in folders.Values) // getting the values directly, we don't care about the keys folder_i
  203. inventory.Folders.Add(BuildFolder((Dictionary<string, object>)o));
  204. if (items != null)
  205. foreach (Object o in items.Values) // getting the values directly, we don't care about the keys item_i
  206. inventory.Items.Add(BuildItem((Dictionary<string, object>)o));
  207. }
  208. catch (Exception e)
  209. {
  210. m_log.WarnFormat("[XINVENTORY SERVICES CONNECTOR]: Exception in GetFolderContent: {0}", e.Message);
  211. }
  212. return inventory;
  213. }
  214. public virtual InventoryCollection[] GetMultipleFoldersContent(UUID principalID, UUID[] folderIDs)
  215. {
  216. InventoryCollection[] inventoryArr = new InventoryCollection[folderIDs.Length];
  217. // m_log.DebugFormat("[XXX]: In GetMultipleFoldersContent {0}", String.Join(",", folderIDs));
  218. try
  219. {
  220. Dictionary<string, object> resultSet = MakeRequest(
  221. new Dictionary<string, object> {
  222. { "METHOD", "GETMULTIPLEFOLDERSCONTENT"},
  223. { "PRINCIPAL", principalID.ToString() },
  224. { "FOLDERS", String.Join(",", folderIDs) },
  225. { "COUNT", folderIDs.Length.ToString() }
  226. });
  227. if (!CheckReturn(resultSet))
  228. return null;
  229. int i = 0;
  230. foreach (KeyValuePair<string, object> kvp in resultSet)
  231. {
  232. InventoryCollection inventory = new InventoryCollection();
  233. if (kvp.Key.StartsWith("F_"))
  234. {
  235. UUID fid = UUID.Zero;
  236. if (UUID.TryParse(kvp.Key.Substring(2), out fid) && fid == folderIDs[i])
  237. {
  238. inventory.Folders = new List<InventoryFolderBase>();
  239. inventory.Items = new List<InventoryItemBase>();
  240. Dictionary<string, object> ret = (Dictionary<string, object>)kvp.Value;
  241. if (ret.ContainsKey("FID"))
  242. {
  243. if (!UUID.TryParse(ret["FID"].ToString(), out inventory.FolderID))
  244. m_log.WarnFormat("[XINVENTORY SERVICES CONNECTOR]: Could not parse folder id {0}", ret["FID"].ToString());
  245. }
  246. else
  247. m_log.WarnFormat("[XINVENTORY SERVICES CONNECTOR]: FID key not present in response");
  248. inventory.Version = -1;
  249. if (ret.ContainsKey("VERSION"))
  250. Int32.TryParse(ret["VERSION"].ToString(), out inventory.Version);
  251. if (ret.ContainsKey("OWNER"))
  252. UUID.TryParse(ret["OWNER"].ToString(), out inventory.OwnerID);
  253. //m_log.DebugFormat("[XXX]: Received {0} ({1}) {2} {3}", inventory.FolderID, fid, inventory.Version, inventory.OwnerID);
  254. if (ret.TryGetValue("FOLDERS", out object ofolders) && ofolders is Dictionary<string, object>)
  255. {
  256. var folders = ofolders as Dictionary<string, object>;
  257. foreach (Object o in folders.Values) // getting the values directly, we don't care about the keys folder_i
  258. {
  259. inventory.Folders.Add(BuildFolder((Dictionary<string, object>)o));
  260. }
  261. }
  262. if (ret.TryGetValue("ITEMS", out object oitems) && oitems is Dictionary<string, object>)
  263. {
  264. var items = oitems as Dictionary<string, object>;
  265. foreach (Object o in items.Values) // getting the values directly, we don't care about the keys item_i
  266. {
  267. inventory.Items.Add(BuildItem((Dictionary<string, object>)o));
  268. }
  269. }
  270. inventoryArr[i] = inventory;
  271. }
  272. else
  273. {
  274. m_log.WarnFormat("[XINVENTORY SERVICES CONNECTOR]: Folder id does not match. Expected {0} got {1}",
  275. folderIDs[i], fid);
  276. m_log.WarnFormat("[XINVENTORY SERVICES CONNECTOR]: {0} {1}", String.Join(",", folderIDs), String.Join(",", resultSet.Keys));
  277. }
  278. i += 1;
  279. }
  280. }
  281. }
  282. catch (Exception e)
  283. {
  284. m_log.WarnFormat("[XINVENTORY SERVICES CONNECTOR]: Exception in GetMultipleFoldersContent: {0}", e.Message);
  285. }
  286. return inventoryArr;
  287. }
  288. public List<InventoryItemBase> GetFolderItems(UUID principalID, UUID folderID)
  289. {
  290. Dictionary<string,object> ret = MakeRequest(
  291. new Dictionary<string,object> {
  292. { "METHOD", "GETFOLDERITEMS"},
  293. { "PRINCIPAL", principalID.ToString() },
  294. { "FOLDER", folderID.ToString() }
  295. });
  296. if (!CheckReturn(ret))
  297. return null;
  298. Dictionary<string, object> items = (Dictionary<string, object>)ret["ITEMS"];
  299. List<InventoryItemBase> fitems = new List<InventoryItemBase>();
  300. foreach (Object o in items.Values) // getting the values directly, we don't care about the keys item_i
  301. fitems.Add(BuildItem((Dictionary<string, object>)o));
  302. return fitems;
  303. }
  304. public bool AddFolder(InventoryFolderBase folder)
  305. {
  306. Dictionary<string,object> ret = MakeRequest(
  307. new Dictionary<string,object> {
  308. { "METHOD", "ADDFOLDER"},
  309. { "ParentID", folder.ParentID.ToString() },
  310. { "Type", folder.Type.ToString() },
  311. { "Version", folder.Version.ToString() },
  312. { "Name", folder.Name.ToString() },
  313. { "Owner", folder.Owner.ToString() },
  314. { "ID", folder.ID.ToString() }
  315. });
  316. return CheckReturn(ret);
  317. }
  318. public bool UpdateFolder(InventoryFolderBase folder)
  319. {
  320. Dictionary<string,object> ret = MakeRequest(
  321. new Dictionary<string,object> {
  322. { "METHOD", "UPDATEFOLDER"},
  323. { "ParentID", folder.ParentID.ToString() },
  324. { "Type", folder.Type.ToString() },
  325. { "Version", folder.Version.ToString() },
  326. { "Name", folder.Name.ToString() },
  327. { "Owner", folder.Owner.ToString() },
  328. { "ID", folder.ID.ToString() }
  329. });
  330. return CheckReturn(ret);
  331. }
  332. public bool MoveFolder(InventoryFolderBase folder)
  333. {
  334. Dictionary<string,object> ret = MakeRequest(
  335. new Dictionary<string,object> {
  336. { "METHOD", "MOVEFOLDER"},
  337. { "ParentID", folder.ParentID.ToString() },
  338. { "ID", folder.ID.ToString() },
  339. { "PRINCIPAL", folder.Owner.ToString() }
  340. });
  341. return CheckReturn(ret);
  342. }
  343. public bool DeleteFolders(UUID principalID, List<UUID> folderIDs)
  344. {
  345. List<string> slist = new List<string>();
  346. foreach (UUID f in folderIDs)
  347. slist.Add(f.ToString());
  348. Dictionary<string,object> ret = MakeRequest(
  349. new Dictionary<string,object> {
  350. { "METHOD", "DELETEFOLDERS"},
  351. { "PRINCIPAL", principalID.ToString() },
  352. { "FOLDERS", slist }
  353. });
  354. return CheckReturn(ret);
  355. }
  356. public bool PurgeFolder(InventoryFolderBase folder)
  357. {
  358. Dictionary<string,object> ret = MakeRequest(
  359. new Dictionary<string,object> {
  360. { "METHOD", "PURGEFOLDER"},
  361. { "ID", folder.ID.ToString() }
  362. });
  363. return CheckReturn(ret);
  364. }
  365. public bool AddItem(InventoryItemBase item)
  366. {
  367. if (item.Description == null)
  368. item.Description = String.Empty;
  369. if (item.CreatorData == null)
  370. item.CreatorData = String.Empty;
  371. if (item.CreatorId == null)
  372. item.CreatorId = String.Empty;
  373. Dictionary<string, object> ret = MakeRequest(
  374. new Dictionary<string,object> {
  375. { "METHOD", "ADDITEM"},
  376. { "AssetID", item.AssetID.ToString() },
  377. { "AssetType", item.AssetType.ToString() },
  378. { "Name", item.Name.ToString() },
  379. { "Owner", item.Owner.ToString() },
  380. { "ID", item.ID.ToString() },
  381. { "InvType", item.InvType.ToString() },
  382. { "Folder", item.Folder.ToString() },
  383. { "CreatorId", item.CreatorId.ToString() },
  384. { "CreatorData", item.CreatorData.ToString() },
  385. { "Description", item.Description.ToString() },
  386. { "NextPermissions", item.NextPermissions.ToString() },
  387. { "CurrentPermissions", item.CurrentPermissions.ToString() },
  388. { "BasePermissions", item.BasePermissions.ToString() },
  389. { "EveryOnePermissions", item.EveryOnePermissions.ToString() },
  390. { "GroupPermissions", item.GroupPermissions.ToString() },
  391. { "GroupID", item.GroupID.ToString() },
  392. { "GroupOwned", item.GroupOwned.ToString() },
  393. { "SalePrice", item.SalePrice.ToString() },
  394. { "SaleType", item.SaleType.ToString() },
  395. { "Flags", item.Flags.ToString() },
  396. { "CreationDate", item.CreationDate.ToString() }
  397. });
  398. return CheckReturn(ret);
  399. }
  400. public bool UpdateItem(InventoryItemBase item)
  401. {
  402. if (item.CreatorData == null)
  403. item.CreatorData = String.Empty;
  404. Dictionary<string,object> ret = MakeRequest(
  405. new Dictionary<string,object> {
  406. { "METHOD", "UPDATEITEM"},
  407. { "AssetID", item.AssetID.ToString() },
  408. { "AssetType", item.AssetType.ToString() },
  409. { "Name", item.Name.ToString() },
  410. { "Owner", item.Owner.ToString() },
  411. { "ID", item.ID.ToString() },
  412. { "InvType", item.InvType.ToString() },
  413. { "Folder", item.Folder.ToString() },
  414. { "CreatorId", item.CreatorId.ToString() },
  415. { "CreatorData", item.CreatorData.ToString() },
  416. { "Description", item.Description.ToString() },
  417. { "NextPermissions", item.NextPermissions.ToString() },
  418. { "CurrentPermissions", item.CurrentPermissions.ToString() },
  419. { "BasePermissions", item.BasePermissions.ToString() },
  420. { "EveryOnePermissions", item.EveryOnePermissions.ToString() },
  421. { "GroupPermissions", item.GroupPermissions.ToString() },
  422. { "GroupID", item.GroupID.ToString() },
  423. { "GroupOwned", item.GroupOwned.ToString() },
  424. { "SalePrice", item.SalePrice.ToString() },
  425. { "SaleType", item.SaleType.ToString() },
  426. { "Flags", item.Flags.ToString() },
  427. { "CreationDate", item.CreationDate.ToString() }
  428. });
  429. bool result = CheckReturn(ret);
  430. if (result)
  431. {
  432. m_ItemCache.AddOrUpdate(item.ID, item, CACHE_EXPIRATION_SECONDS);
  433. }
  434. return result;
  435. }
  436. public bool MoveItems(UUID principalID, List<InventoryItemBase> items)
  437. {
  438. List<string> idlist = new List<string>();
  439. List<string> destlist = new List<string>();
  440. foreach (InventoryItemBase item in items)
  441. {
  442. idlist.Add(item.ID.ToString());
  443. destlist.Add(item.Folder.ToString());
  444. }
  445. Dictionary<string,object> ret = MakeRequest(
  446. new Dictionary<string,object> {
  447. { "METHOD", "MOVEITEMS"},
  448. { "PRINCIPAL", principalID.ToString() },
  449. { "IDLIST", idlist },
  450. { "DESTLIST", destlist }
  451. });
  452. return CheckReturn(ret);
  453. }
  454. public bool DeleteItems(UUID principalID, List<UUID> itemIDs)
  455. {
  456. List<string> slist = new List<string>();
  457. foreach (UUID f in itemIDs)
  458. slist.Add(f.ToString());
  459. Dictionary<string,object> ret = MakeRequest(
  460. new Dictionary<string,object> {
  461. { "METHOD", "DELETEITEMS"},
  462. { "PRINCIPAL", principalID.ToString() },
  463. { "ITEMS", slist }
  464. });
  465. return CheckReturn(ret);
  466. }
  467. public InventoryItemBase GetItem(UUID principalID, UUID itemID)
  468. {
  469. InventoryItemBase retrieved = null;
  470. if (m_ItemCache.TryGetValue(itemID, out retrieved))
  471. {
  472. return retrieved;
  473. }
  474. try
  475. {
  476. Dictionary<string, object> ret = MakeRequest(
  477. new Dictionary<string, object> {
  478. { "METHOD", "GETITEM"},
  479. { "ID", itemID.ToString() },
  480. { "PRINCIPAL", principalID.ToString() }
  481. });
  482. if (!CheckReturn(ret))
  483. return null;
  484. retrieved = BuildItem((Dictionary<string, object>)ret["item"]);
  485. }
  486. catch (Exception e)
  487. {
  488. m_log.Error("[XINVENTORY SERVICES CONNECTOR]: Exception in GetItem: ", e);
  489. }
  490. m_ItemCache.AddOrUpdate(itemID, retrieved, CACHE_EXPIRATION_SECONDS);
  491. return retrieved;
  492. }
  493. public virtual InventoryItemBase[] GetMultipleItems(UUID principalID, UUID[] itemIDs)
  494. {
  495. //m_log.DebugFormat("[XXX]: In GetMultipleItems {0}", String.Join(",", itemIDs));
  496. InventoryItemBase[] itemArr = new InventoryItemBase[itemIDs.Length];
  497. // Try to get them from the cache
  498. List<UUID> pending = new List<UUID>();
  499. InventoryItemBase item = null;
  500. int i = 0;
  501. foreach (UUID id in itemIDs)
  502. {
  503. if (m_ItemCache.TryGetValue(id, out item))
  504. itemArr[i++] = item;
  505. else
  506. pending.Add(id);
  507. }
  508. if (pending.Count == 0) // we're done, everything was in the cache
  509. return itemArr;
  510. try
  511. {
  512. Dictionary<string, object> resultSet = MakeRequest(
  513. new Dictionary<string, object> {
  514. { "METHOD", "GETMULTIPLEITEMS"},
  515. { "PRINCIPAL", principalID.ToString() },
  516. { "ITEMS", String.Join(",", pending.ToArray()) },
  517. { "COUNT", pending.Count.ToString() }
  518. });
  519. if (!CheckReturn(resultSet))
  520. {
  521. if (i == 0)
  522. return null;
  523. else
  524. return itemArr;
  525. }
  526. // carry over index i where we left above
  527. foreach (KeyValuePair<string, object> kvp in resultSet)
  528. {
  529. InventoryCollection inventory = new InventoryCollection();
  530. if (kvp.Key.StartsWith("item_"))
  531. {
  532. if (kvp.Value is Dictionary<string, object>)
  533. {
  534. item = BuildItem((Dictionary<string, object>)kvp.Value);
  535. m_ItemCache.AddOrUpdate(item.ID, item, CACHE_EXPIRATION_SECONDS);
  536. itemArr[i++] = item;
  537. }
  538. else
  539. itemArr[i++] = null;
  540. }
  541. }
  542. }
  543. catch (Exception e)
  544. {
  545. m_log.WarnFormat("[XINVENTORY SERVICES CONNECTOR]: Exception in GetMultipleItems: {0}", e.Message);
  546. }
  547. return itemArr;
  548. }
  549. public InventoryFolderBase GetFolder(UUID principalID, UUID folderID)
  550. {
  551. try
  552. {
  553. Dictionary<string, object> ret = MakeRequest(
  554. new Dictionary<string, object> {
  555. { "METHOD", "GETFOLDER"},
  556. { "ID", folderID.ToString() },
  557. { "PRINCIPAL", principalID.ToString() }
  558. });
  559. if (!CheckReturn(ret))
  560. return null;
  561. return BuildFolder((Dictionary<string, object>)ret["folder"]);
  562. }
  563. catch (Exception e)
  564. {
  565. m_log.Error("[XINVENTORY SERVICES CONNECTOR]: Exception in GetFolder: ", e);
  566. }
  567. return null;
  568. }
  569. public List<InventoryItemBase> GetActiveGestures(UUID principalID)
  570. {
  571. Dictionary<string,object> ret = MakeRequest(
  572. new Dictionary<string,object> {
  573. { "METHOD", "GETACTIVEGESTURES"},
  574. { "PRINCIPAL", principalID.ToString() }
  575. });
  576. if (!CheckReturn(ret))
  577. return null;
  578. List<InventoryItemBase> items = new List<InventoryItemBase>();
  579. foreach (Object o in ((Dictionary<string,object>)ret["ITEMS"]).Values)
  580. items.Add(BuildItem((Dictionary<string, object>)o));
  581. return items;
  582. }
  583. public int GetAssetPermissions(UUID principalID, UUID assetID)
  584. {
  585. Dictionary<string,object> ret = MakeRequest(
  586. new Dictionary<string,object> {
  587. { "METHOD", "GETASSETPERMISSIONS"},
  588. { "PRINCIPAL", principalID.ToString() },
  589. { "ASSET", assetID.ToString() }
  590. });
  591. // We cannot use CheckReturn() here because valid values for RESULT are "false" (in the case of request failure) or an int
  592. if (ret == null)
  593. return 0;
  594. if (ret.ContainsKey("RESULT"))
  595. {
  596. if (ret["RESULT"] is string)
  597. {
  598. int intResult;
  599. if (int.TryParse ((string)ret["RESULT"], out intResult))
  600. return intResult;
  601. }
  602. }
  603. return 0;
  604. }
  605. public bool HasInventoryForUser(UUID principalID)
  606. {
  607. return false;
  608. }
  609. // Helpers
  610. //
  611. private Dictionary<string,object> MakeRequest(Dictionary<string, object> sendData)
  612. {
  613. RequestsMade++;
  614. string reply = String.Empty;
  615. reply = SynchronousRestFormsRequester.MakePostRequest(
  616. m_ServerURI + "/xinventory",
  617. ServerUtils.BuildQueryString(sendData), m_Auth, m_requestTimeoutSecs);
  618. if(string.IsNullOrWhiteSpace(reply))
  619. return new Dictionary<string, object>();
  620. Dictionary<string, object> replyData = ServerUtils.ParseXmlResponse(reply);
  621. return replyData;
  622. }
  623. private InventoryFolderBase BuildFolder(Dictionary<string,object> data)
  624. {
  625. InventoryFolderBase folder = new InventoryFolderBase();
  626. try
  627. {
  628. folder.ParentID = new UUID(data["ParentID"].ToString());
  629. folder.Type = short.Parse(data["Type"].ToString());
  630. folder.Version = ushort.Parse(data["Version"].ToString());
  631. folder.Name = data["Name"].ToString();
  632. folder.Owner = new UUID(data["Owner"].ToString());
  633. folder.ID = new UUID(data["ID"].ToString());
  634. }
  635. catch (Exception e)
  636. {
  637. m_log.Error("[XINVENTORY SERVICES CONNECTOR]: Exception building folder: ", e);
  638. }
  639. return folder;
  640. }
  641. private InventoryItemBase BuildItem(Dictionary<string,object> data)
  642. {
  643. InventoryItemBase item = new InventoryItemBase();
  644. try
  645. {
  646. item.AssetID = new UUID(data["AssetID"].ToString());
  647. item.AssetType = int.Parse(data["AssetType"].ToString());
  648. item.Name = data["Name"].ToString();
  649. item.Owner = new UUID(data["Owner"].ToString());
  650. item.ID = new UUID(data["ID"].ToString());
  651. item.InvType = int.Parse(data["InvType"].ToString());
  652. item.Folder = new UUID(data["Folder"].ToString());
  653. item.CreatorId = data["CreatorId"].ToString();
  654. if (data.ContainsKey("CreatorData"))
  655. item.CreatorData = data["CreatorData"].ToString();
  656. item.Description = data["Description"].ToString();
  657. item.NextPermissions = uint.Parse(data["NextPermissions"].ToString());
  658. item.CurrentPermissions = uint.Parse(data["CurrentPermissions"].ToString());
  659. item.BasePermissions = uint.Parse(data["BasePermissions"].ToString());
  660. item.EveryOnePermissions = uint.Parse(data["EveryOnePermissions"].ToString());
  661. item.GroupPermissions = uint.Parse(data["GroupPermissions"].ToString());
  662. item.GroupID = new UUID(data["GroupID"].ToString());
  663. item.GroupOwned = bool.Parse(data["GroupOwned"].ToString());
  664. item.SalePrice = int.Parse(data["SalePrice"].ToString());
  665. item.SaleType = byte.Parse(data["SaleType"].ToString());
  666. item.Flags = uint.Parse(data["Flags"].ToString());
  667. item.CreationDate = int.Parse(data["CreationDate"].ToString());
  668. }
  669. catch (Exception e)
  670. {
  671. m_log.Error("[XINVENTORY CONNECTOR]: Exception building item: ", e);
  672. }
  673. return item;
  674. }
  675. }
  676. }