XInventoryServicesConnector.cs 31 KB

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