/Aurora/Services/DataService/Connectors/Database/Grid/LocalGridConnector.cs

https://bitbucket.org/VirtualReality/software-testing · C# · 594 lines · 478 code · 90 blank · 26 comment · 77 complexity · 37851c40ef8962a3ef5173a7270762d0 MD5 · raw file

  1. /*
  2. * Copyright (c) Contributors, http://aurora-sim.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 Aurora-Sim 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 Aurora.Framework;
  28. using Aurora.Framework.ConsoleFramework;
  29. using Aurora.Framework.DatabaseInterfaces;
  30. using Aurora.Framework.Modules;
  31. using Aurora.Framework.SceneInfo;
  32. using Aurora.Framework.Services;
  33. using Aurora.Framework.Utilities;
  34. using Nini.Config;
  35. using OpenMetaverse;
  36. using OpenMetaverse.StructuredData;
  37. using System;
  38. using System.Collections.Generic;
  39. using GridRegion = Aurora.Framework.Services.GridRegion;
  40. using RegionFlags = Aurora.Framework.Services.RegionFlags;
  41. namespace Aurora.Services.DataService
  42. {
  43. public class LocalGridConnector : IRegionData
  44. {
  45. private IGenericData GD;
  46. private string m_realm = "gridregions";
  47. #region IRegionData Members
  48. public void Initialize(IGenericData GenericData, IConfigSource source, IRegistryCore simBase,
  49. string defaultConnectionString)
  50. {
  51. if (source.Configs["AuroraConnectors"].GetString("GridConnector", "LocalConnector") == "LocalConnector")
  52. {
  53. GD = GenericData;
  54. string connectionString = (source.Configs[Name] != null)
  55. ? connectionString =
  56. source.Configs[Name].GetString("ConnectionString",
  57. defaultConnectionString)
  58. : defaultConnectionString;
  59. if (GD != null)
  60. GD.ConnectToDatabase(connectionString, "GridRegions",
  61. source.Configs["AuroraConnectors"].GetBoolean("ValidateTables", true));
  62. Framework.Utilities.DataManager.RegisterPlugin(this);
  63. if (MainConsole.Instance != null)
  64. {
  65. MainConsole.Instance.Commands.AddCommand("fix missing region owner", "fix missing region owner",
  66. "Attempts to fix missing region owners in the database.",
  67. delegate(string[] cmd) { FixMissingRegionOwners(); });
  68. }
  69. }
  70. }
  71. public string Name
  72. {
  73. get { return "IRegionData"; }
  74. }
  75. private void FixMissingRegionOwners()
  76. {
  77. QueryFilter filter = new QueryFilter();
  78. filter.andFilters["OwnerUUID"] = UUID.Zero;
  79. List<GridRegion> borked = ParseQuery(null, GD.Query(new string[1] {"*"}, m_realm, filter, null, null, null));
  80. if (borked.Count < 1)
  81. {
  82. MainConsole.Instance.Debug("[LocalGridConnector] No regions found with missing owners.");
  83. }
  84. IEstateConnector estatePlugin = Framework.Utilities.DataManager.RequestPlugin<IEstateConnector>();
  85. if (estatePlugin == null)
  86. {
  87. MainConsole.Instance.Error("[LocalGridConnector] " + borked.Count +
  88. " regions found with missing owners, but could not get IEstateConnector plugin.");
  89. return;
  90. }
  91. else
  92. {
  93. MainConsole.Instance.Error("[LocalGridConnector] " + borked.Count +
  94. " regions found with missing owners, attempting fix.");
  95. }
  96. Dictionary<int, List<GridRegion>> borkedByEstate = new Dictionary<int, List<GridRegion>>();
  97. foreach (GridRegion region in borked)
  98. {
  99. int estateID = estatePlugin.GetEstateID(region.RegionID);
  100. if (!borkedByEstate.ContainsKey(estateID))
  101. {
  102. borkedByEstate[estateID] = new List<GridRegion>();
  103. }
  104. borkedByEstate[estateID].Add(region);
  105. }
  106. Dictionary<int, UUID> estateOwnerIDs = new Dictionary<int, UUID>();
  107. uint estateFail = 0;
  108. foreach (int estateID in borkedByEstate.Keys)
  109. {
  110. EstateSettings es = estatePlugin.GetEstateSettings(estateID);
  111. if (es == null)
  112. {
  113. MainConsole.Instance.Error("[LocalGridConnector] Cannot fix missing owner for regions in Estate " +
  114. estateID + ", could not get estate settings.");
  115. }
  116. else if (es.EstateOwner == UUID.Zero)
  117. {
  118. MainConsole.Instance.Error("[LocalGridConnector] Cannot fix missing owner for regions in Estate " +
  119. estateID + ", Estate Owner is also missing.");
  120. }
  121. if (es == null || es.EstateOwner == UUID.Zero)
  122. {
  123. ++estateFail;
  124. continue;
  125. }
  126. estateOwnerIDs[estateID] = es.EstateOwner;
  127. }
  128. if (estateFail > 0)
  129. {
  130. if (estateFail == borkedByEstate.Count)
  131. {
  132. MainConsole.Instance.Error("[LocalGridConnector] " + borked.Count +
  133. " regions found with missing owners, could not locate any estate settings from IEstateConnector plugin.");
  134. return;
  135. }
  136. else
  137. {
  138. MainConsole.Instance.Error("[LocalGridConnector] " + borked.Count +
  139. " regions found with missing owners, could not locate estate settings for " +
  140. estateFail + " estates.");
  141. }
  142. }
  143. uint storeSuccess = 0;
  144. uint storeFail = 0;
  145. int borkedCount = borked.Count;
  146. foreach (KeyValuePair<int, UUID> kvp in estateOwnerIDs)
  147. {
  148. List<GridRegion> regions = borkedByEstate[kvp.Key];
  149. foreach (GridRegion region in regions)
  150. {
  151. region.EstateOwner = kvp.Value;
  152. if (!Store(region))
  153. {
  154. MainConsole.Instance.Error("[LocalGridConnector] Failed to fix missing region for " +
  155. region.RegionName + " (" + region.RegionID + ")");
  156. ++storeFail;
  157. }
  158. else
  159. {
  160. ++storeSuccess;
  161. borked.Remove(region);
  162. }
  163. }
  164. }
  165. if (storeFail > 0)
  166. {
  167. MainConsole.Instance.Error("[LocalGridConnector] " + borkedCount +
  168. " regions found with missing owners, fix failed on " + storeFail +
  169. " regions, fix attempted on " + storeSuccess + " regions.");
  170. }
  171. else if (storeSuccess != borked.Count)
  172. {
  173. MainConsole.Instance.Error("[LocalGridConnector] " + borkedCount +
  174. " regions found with missing owners, fix attempted on " + storeSuccess +
  175. " regions.");
  176. }
  177. else
  178. {
  179. MainConsole.Instance.Info(
  180. "[LocalGridConnector] All regions found with missing owners should have their owners restored.");
  181. }
  182. if (borked.Count > 0)
  183. {
  184. List<string> blurbs = new List<string>(borked.Count);
  185. foreach (GridRegion region in borked)
  186. {
  187. blurbs.Add(region.RegionName + " (" + region.RegionID + ")");
  188. }
  189. MainConsole.Instance.Info("[LocalGridConnector] Failed to fix missing region owners for regions " +
  190. string.Join(", ", blurbs.ToArray()));
  191. }
  192. }
  193. public uint GetCount(string regionName, List<UUID> scopeIDs)
  194. {
  195. QueryFilter filter = new QueryFilter();
  196. filter.andLikeFilters["RegionName"] = regionName;
  197. return uint.Parse(GD.Query(new[] {"COUNT(*)"}, m_realm, filter, null, null, null)[0]);
  198. }
  199. public List<GridRegion> Get(string regionName, List<UUID> scopeIDs, uint? start, uint? count)
  200. {
  201. QueryFilter filter = new QueryFilter();
  202. filter.andLikeFilters["RegionName"] = regionName;
  203. List<string> query = GD.Query(new string[1] {"*"}, m_realm, filter, null, start, count);
  204. return (query.Count == 0) ? null : ParseQuery(scopeIDs, query);
  205. }
  206. public List<GridRegion> Get(RegionFlags flags)
  207. {
  208. QueryFilter filter = new QueryFilter();
  209. filter.andBitfieldAndFilters["Flags"] = (uint) flags;
  210. return ParseQuery(null, GD.Query(new string[1] {"*"}, m_realm, filter, null, null, null));
  211. }
  212. public GridRegion GetZero(int posX, int posY, List<UUID> scopeIDs)
  213. {
  214. QueryFilter filter = new QueryFilter();
  215. filter.andFilters["LocX"] = posX;
  216. filter.andFilters["LocY"] = posY;
  217. List<string> query = GD.Query(new string[1] {"*"}, m_realm, filter, null, null, null);
  218. return (query.Count == 0) ? null : ParseQuery(scopeIDs, query)[0];
  219. }
  220. public List<GridRegion> Get(int posX, int posY, List<UUID> scopeIDs)
  221. {
  222. QueryFilter filter = new QueryFilter();
  223. filter.andFilters["LocX"] = posX;
  224. filter.andFilters["LocY"] = posY;
  225. Dictionary<string, bool> sort = new Dictionary<string, bool>(1);
  226. sort["LocZ"] = true;
  227. return ParseQuery(scopeIDs, GD.Query(new string[1] {"*"}, m_realm, filter, sort, null, null));
  228. }
  229. public GridRegion Get(UUID regionID, List<UUID> scopeIDs)
  230. {
  231. List<string> query;
  232. Dictionary<string, object> where = new Dictionary<string, object>();
  233. where["RegionUUID"] = regionID;
  234. query = GD.Query(new string[1] {"*"}, m_realm, new QueryFilter
  235. {
  236. andFilters = where
  237. }, null, null, null);
  238. return (query.Count == 0) ? null : ParseQuery(scopeIDs, query)[0];
  239. }
  240. public List<GridRegion> Get(int startX, int startY, int endX, int endY, List<UUID> scopeIDs)
  241. {
  242. int foo;
  243. if (startX > endX)
  244. {
  245. foo = endX;
  246. endX = startX;
  247. startX = foo;
  248. }
  249. if (startY > endY)
  250. {
  251. foo = endY;
  252. endY = startY;
  253. startY = foo;
  254. }
  255. QueryFilter filter = new QueryFilter();
  256. filter.andGreaterThanEqFilters["LocX"] = startX;
  257. filter.andLessThanEqFilters["LocX"] = endX;
  258. filter.andGreaterThanEqFilters["LocY"] = startY;
  259. filter.andLessThanEqFilters["LocY"] = endY;
  260. return ParseQuery(scopeIDs, GD.Query(new string[1] {"*"}, m_realm, filter, null, null, null));
  261. }
  262. public List<GridRegion> Get(RegionFlags flags, Dictionary<string, bool> sort)
  263. {
  264. return Get(flags, 0, null, null, sort);
  265. }
  266. public List<GridRegion> Get(uint start, uint count, uint estateID, RegionFlags flags,
  267. Dictionary<string, bool> sort)
  268. {
  269. List<GridRegion> resp = new List<GridRegion>();
  270. IEstateConnector estates = Framework.Utilities.DataManager.RequestPlugin<IEstateConnector>();
  271. if (count == 0 || estates == null)
  272. {
  273. return resp;
  274. }
  275. EstateSettings es = estates.GetEstateSettings((int) estateID);
  276. QueryFilter filter = new QueryFilter();
  277. filter.andBitfieldAndFilters["Flags"] = (uint) flags;
  278. while (resp.Count < count)
  279. {
  280. uint limit = count - (uint) resp.Count;
  281. List<GridRegion> query = ParseQuery(null,
  282. GD.Query(new string[] {"*"}, m_realm, filter, sort, start, count));
  283. if (query.Count == 0)
  284. {
  285. break;
  286. }
  287. query.ForEach(delegate(GridRegion region)
  288. {
  289. if (region.EstateOwner == es.EstateOwner &&
  290. estates.GetEstateID(region.RegionID) == es.EstateID)
  291. {
  292. resp.Add(region);
  293. }
  294. });
  295. start += limit;
  296. }
  297. return resp;
  298. }
  299. public List<GridRegion> Get(RegionFlags includeFlags, RegionFlags excludeFlags, uint? start, uint? count,
  300. Dictionary<string, bool> sort)
  301. {
  302. QueryFilter filter = new QueryFilter();
  303. if (includeFlags > 0)
  304. {
  305. filter.andBitfieldAndFilters["Flags"] = (uint) includeFlags;
  306. }
  307. if (excludeFlags > 0)
  308. {
  309. filter.andBitfieldNandFilters["Flags"] = (uint) excludeFlags;
  310. }
  311. return ParseQuery(null, GD.Query(new string[1] {"*"}, m_realm, filter, sort, start, count));
  312. }
  313. public uint Count(RegionFlags includeFlags, RegionFlags excludeFlags)
  314. {
  315. QueryFilter filter = new QueryFilter();
  316. if (includeFlags > 0)
  317. {
  318. filter.andBitfieldAndFilters["Flags"] = (uint) includeFlags;
  319. }
  320. if (excludeFlags > 0)
  321. {
  322. filter.andBitfieldNandFilters["Flags"] = (uint) excludeFlags;
  323. }
  324. return uint.Parse(GD.Query(new string[1] {"COUNT(*)"}, m_realm, filter, null, null, null)[0]);
  325. }
  326. public List<GridRegion> GetNeighbours(UUID regionID, List<UUID> scopeIDs, uint squareRangeFromCenterInMeters)
  327. {
  328. List<GridRegion> regions = new List<GridRegion>(0);
  329. GridRegion region = Get(regionID, scopeIDs);
  330. if (region != null)
  331. {
  332. int centerX = region.RegionLocX + (region.RegionSizeX/2); // calculate center of region
  333. int centerY = region.RegionLocY + (region.RegionSizeY/2); // calculate center of region
  334. regions = Get(scopeIDs, region.RegionID, centerX, centerY, squareRangeFromCenterInMeters);
  335. }
  336. return regions;
  337. }
  338. public List<GridRegion> Get(List<UUID> scopeIDs, UUID excludeRegion, float centerX, float centerY,
  339. uint squareRangeFromCenterInMeters)
  340. {
  341. QueryFilter filter = new QueryFilter();
  342. if (excludeRegion != UUID.Zero)
  343. {
  344. filter.andNotFilters["RegionUUID"] = excludeRegion;
  345. }
  346. filter.andGreaterThanEqFilters["(LocX + SizeX)"] = centerX - squareRangeFromCenterInMeters;
  347. filter.andGreaterThanEqFilters["(LocY + SizeY)"] = centerY - squareRangeFromCenterInMeters;
  348. filter.andLessThanEqFilters["(LocX - SizeX)"] = centerX + squareRangeFromCenterInMeters;
  349. filter.andLessThanEqFilters["(LocY - SizeY)"] = centerY + squareRangeFromCenterInMeters;
  350. Dictionary<string, bool> sort = new Dictionary<string, bool>(3);
  351. sort["LocZ"] = true;
  352. sort["LocX"] = true;
  353. sort["LocY"] = true;
  354. return ParseQuery(scopeIDs, GD.Query(new string[] {"*"}, m_realm, filter, sort, null, null));
  355. }
  356. public uint Count(uint estateID, RegionFlags flags)
  357. {
  358. IEstateConnector estates = Framework.Utilities.DataManager.RequestPlugin<IEstateConnector>();
  359. if (estates == null)
  360. {
  361. return 0;
  362. }
  363. EstateSettings es = estates.GetEstateSettings((int) estateID);
  364. QueryFilter filter = new QueryFilter();
  365. filter.andBitfieldAndFilters["Flags"] = (uint) flags;
  366. List<GridRegion> query = ParseQuery(null, GD.Query(new string[] {"*"}, m_realm, filter, null, null, null));
  367. uint count = 0;
  368. query.ForEach(delegate(GridRegion region)
  369. {
  370. if (region.EstateOwner == es.EstateOwner &&
  371. estates.GetEstateID(region.RegionID) == es.EstateID)
  372. {
  373. ++count;
  374. }
  375. });
  376. return count;
  377. }
  378. public bool Store(GridRegion region)
  379. {
  380. if (region.EstateOwner == UUID.Zero)
  381. {
  382. IEstateConnector EstateConnector = Framework.Utilities.DataManager.RequestPlugin<IEstateConnector>();
  383. EstateSettings ES = null;
  384. if (EstateConnector != null)
  385. {
  386. ES = EstateConnector.GetEstateSettings(region.RegionID);
  387. if (ES != null)
  388. region.EstateOwner = ES.EstateOwner;
  389. }
  390. if (region.EstateOwner == UUID.Zero && ES != null && ES.EstateID != 0)
  391. {
  392. MainConsole.Instance.Error(
  393. "[LocalGridConnector] Attempt to store region with owner of UUID.Zero detected:" +
  394. (new System.Diagnostics.StackTrace()).GetFrame(1).ToString());
  395. }
  396. }
  397. Dictionary<string, object> row = new Dictionary<string, object>(14);
  398. row["ScopeID"] = region.ScopeID;
  399. row["RegionUUID"] = region.RegionID;
  400. row["RegionName"] = region.RegionName;
  401. row["LocX"] = region.RegionLocX;
  402. row["LocY"] = region.RegionLocY;
  403. row["LocZ"] = region.RegionLocZ;
  404. row["OwnerUUID"] = region.EstateOwner;
  405. row["Access"] = region.Access;
  406. row["SizeX"] = region.RegionSizeX;
  407. row["SizeY"] = region.RegionSizeY;
  408. row["SizeZ"] = region.RegionSizeZ;
  409. row["Flags"] = region.Flags;
  410. row["SessionID"] = region.SessionID;
  411. row["Info"] = OSDParser.SerializeJsonString(region.ToOSD());
  412. return GD.Replace(m_realm, row);
  413. }
  414. public bool Delete(UUID regionID)
  415. {
  416. QueryFilter filter = new QueryFilter();
  417. filter.andFilters["RegionUUID"] = regionID;
  418. return GD.Delete(m_realm, filter);
  419. }
  420. public bool DeleteAll(string[] criteriaKey, object[] criteriaValue)
  421. {
  422. QueryFilter filter = new QueryFilter();
  423. int i = 0;
  424. foreach (object value in criteriaValue)
  425. {
  426. filter.andFilters[criteriaKey[i++]] = value;
  427. }
  428. return GD.Delete(m_realm, filter);
  429. }
  430. public List<GridRegion> GetDefaultRegions(List<UUID> scopeIDs)
  431. {
  432. return Get((int) RegionFlags.DefaultRegion, scopeIDs);
  433. }
  434. public List<GridRegion> GetFallbackRegions(List<UUID> scopeIDs, int x, int y)
  435. {
  436. List<GridRegion> regions = Get((int) RegionFlags.FallbackRegion, scopeIDs);
  437. RegionDataDistanceCompare distanceComparer = new RegionDataDistanceCompare(x, y);
  438. regions.Sort(distanceComparer);
  439. return regions;
  440. }
  441. public List<GridRegion> GetSafeRegions(List<UUID> scopeIDs, int x, int y)
  442. {
  443. List<GridRegion> Regions = Get((int) RegionFlags.Safe, scopeIDs);
  444. Regions.AddRange(Get((int) RegionFlags.RegionOnline, scopeIDs));
  445. RegionDataDistanceCompare distanceComparer = new RegionDataDistanceCompare(x, y);
  446. Regions.Sort(distanceComparer);
  447. return Regions;
  448. }
  449. #endregion
  450. public void Dispose()
  451. {
  452. }
  453. private List<GridRegion> Get(int regionFlags, List<UUID> scopeIDs)
  454. {
  455. QueryFilter filter = new QueryFilter();
  456. filter.andBitfieldAndFilters["Flags"] = (uint) regionFlags;
  457. return ParseQuery(scopeIDs, GD.Query(new string[1] {"*"}, m_realm, filter, null, null, null));
  458. }
  459. protected List<GridRegion> ParseQuery(List<UUID> scopeIDs, List<string> query)
  460. {
  461. List<GridRegion> regionData = new List<GridRegion>();
  462. if ((query.Count%14) == 0)
  463. {
  464. for (int i = 0; i < query.Count; i += 14)
  465. {
  466. GridRegion data = new GridRegion();
  467. OSDMap map = (OSDMap) OSDParser.DeserializeJson(query[i + 13]);
  468. map["owner_uuid"] = (!map.ContainsKey("owner_uuid") || map["owner_uuid"].AsUUID() == UUID.Zero)
  469. ? OSD.FromUUID(UUID.Parse(query[i + 6]))
  470. : map["owner_uuid"];
  471. map["EstateOwner"] = (!map.ContainsKey("EstateOwner") || map["EstateOwner"].AsUUID() == UUID.Zero)
  472. ? OSD.FromUUID(UUID.Parse(query[i + 6]))
  473. : map["EstateOwner"];
  474. data.FromOSD(map);
  475. if (!regionData.Contains(data))
  476. regionData.Add(data);
  477. }
  478. }
  479. return AllScopeIDImpl.CheckScopeIDs(scopeIDs, regionData);
  480. }
  481. #region Nested type: RegionDataDistanceCompare
  482. public class RegionDataDistanceCompare : IComparer<GridRegion>
  483. {
  484. private readonly Vector2 m_origin;
  485. public RegionDataDistanceCompare(int x, int y)
  486. {
  487. m_origin = new Vector2(x, y);
  488. }
  489. #region IComparer<GridRegion> Members
  490. public int Compare(GridRegion regionA, GridRegion regionB)
  491. {
  492. Vector2 vectorA = new Vector2(regionA.RegionLocX, regionA.RegionLocY);
  493. Vector2 vectorB = new Vector2(regionB.RegionLocX, regionB.RegionLocY);
  494. return Math.Sign(VectorDistance(m_origin, vectorA) - VectorDistance(m_origin, vectorB));
  495. }
  496. #endregion
  497. private float VectorDistance(Vector2 x, Vector2 y)
  498. {
  499. return (x - y).Length();
  500. }
  501. }
  502. #endregion
  503. }
  504. }