MySQLUserData.cs 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917
  1. /*
  2. * Copyright (c) Contributors, http://opensimulator.org/
  3. * See CONTRIBUTORS.TXT for a full list of copyright holders.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. * * Redistributions of source code must retain the above copyright
  8. * notice, this list of conditions and the following disclaimer.
  9. * * Redistributions in binary form must reproduce the above copyright
  10. * notice, this list of conditions and the following disclaimer in the
  11. * documentation and/or other materials provided with the distribution.
  12. * * Neither the name of the OpenSim Project nor the
  13. * names of its contributors may be used to endorse or promote products
  14. * derived from this software without specific prior written permission.
  15. *
  16. * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
  17. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  18. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  19. * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
  20. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  21. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  22. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  23. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  24. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  25. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26. */
  27. using System;
  28. using System.Collections;
  29. using System.Collections.Generic;
  30. using System.Data;
  31. using System.Reflection;
  32. using System.Text.RegularExpressions;
  33. using System.Threading;
  34. using log4net;
  35. using OpenMetaverse;
  36. using OpenSim.Framework;
  37. namespace OpenSim.Data.MySQL
  38. {
  39. /// <summary>
  40. /// A database interface class to a user profile storage system
  41. /// </summary>
  42. public class MySQLUserData : UserDataBase
  43. {
  44. private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
  45. /// <summary>
  46. /// Database manager for MySQL
  47. /// </summary>
  48. public MySQLManager database;
  49. /// <summary>
  50. /// Better DB manager. Swap-in replacement too.
  51. /// </summary>
  52. public Dictionary<int, MySQLSuperManager> m_dbconnections = new Dictionary<int, MySQLSuperManager>();
  53. public int m_maxConnections = 10;
  54. public int m_lastConnect;
  55. private string m_agentsTableName = "agents";
  56. private string m_usersTableName = "users";
  57. private string m_userFriendsTableName = "userfriends";
  58. private string m_appearanceTableName = "avatarappearance";
  59. private string m_attachmentsTableName = "avatarattachments";
  60. private string m_connectString;
  61. public override void Initialise()
  62. {
  63. m_log.Info("[MySQLUserData]: " + Name + " cannot be default-initialized!");
  64. throw new PluginNotInitialisedException(Name);
  65. }
  66. public MySQLSuperManager GetLockedConnection(string why)
  67. {
  68. int lockedCons = 0;
  69. while (true)
  70. {
  71. m_lastConnect++;
  72. // Overflow protection
  73. if (m_lastConnect == int.MaxValue)
  74. m_lastConnect = 0;
  75. MySQLSuperManager x = m_dbconnections[m_lastConnect%m_maxConnections];
  76. if (!x.Locked)
  77. {
  78. x.GetLock();
  79. x.Running = why;
  80. return x;
  81. }
  82. lockedCons++;
  83. if (lockedCons > m_maxConnections)
  84. {
  85. lockedCons = 0;
  86. Thread.Sleep(1000); // Wait some time before searching them again.
  87. m_log.Debug(
  88. "WARNING: All threads are in use. Probable cause: Something didnt release a mutex properly, or high volume of requests inbound.");
  89. m_log.Debug("Current connections-in-use dump:");
  90. foreach (KeyValuePair<int, MySQLSuperManager> kvp in m_dbconnections)
  91. {
  92. m_log.Debug(kvp.Value.Running);
  93. }
  94. }
  95. }
  96. }
  97. /// <summary>
  98. /// Initialise User Interface
  99. /// Loads and initialises the MySQL storage plugin
  100. /// Warns and uses the obsolete mysql_connection.ini if connect string is empty.
  101. /// Checks for migration
  102. /// </summary>
  103. /// <param name="connect">connect string.</param>
  104. public override void Initialise(string connect)
  105. {
  106. if (connect == String.Empty)
  107. {
  108. // TODO: actually do something with our connect string
  109. // instead of loading the second config
  110. m_log.Warn("Using obsoletely mysql_connection.ini, try using user_source connect string instead");
  111. IniFile iniFile = new IniFile("mysql_connection.ini");
  112. string settingHostname = iniFile.ParseFileReadValue("hostname");
  113. string settingDatabase = iniFile.ParseFileReadValue("database");
  114. string settingUsername = iniFile.ParseFileReadValue("username");
  115. string settingPassword = iniFile.ParseFileReadValue("password");
  116. string settingPooling = iniFile.ParseFileReadValue("pooling");
  117. string settingPort = iniFile.ParseFileReadValue("port");
  118. m_connectString = "Server=" + settingHostname + ";Port=" + settingPort + ";Database=" + settingDatabase +
  119. ";User ID=" +
  120. settingUsername + ";Password=" + settingPassword + ";Pooling=" + settingPooling + ";";
  121. m_log.Info("Creating " + m_maxConnections + " DB connections...");
  122. for (int i = 0; i < m_maxConnections; i++)
  123. {
  124. m_log.Info("Connecting to DB... [" + i + "]");
  125. MySQLSuperManager msm = new MySQLSuperManager();
  126. msm.Manager = new MySQLManager(m_connectString);
  127. m_dbconnections.Add(i, msm);
  128. }
  129. database = new MySQLManager(m_connectString);
  130. }
  131. else
  132. {
  133. m_connectString = connect;
  134. database = new MySQLManager(m_connectString);
  135. m_log.Info("Creating " + m_maxConnections + " DB connections...");
  136. for (int i = 0; i < m_maxConnections; i++)
  137. {
  138. m_log.Info("Connecting to DB... [" + i + "]");
  139. MySQLSuperManager msm = new MySQLSuperManager();
  140. msm.Manager = new MySQLManager(m_connectString);
  141. m_dbconnections.Add(i, msm);
  142. }
  143. }
  144. // This actually does the roll forward assembly stuff
  145. Assembly assem = GetType().Assembly;
  146. Migration m = new Migration(database.Connection, assem, "UserStore");
  147. m.Update();
  148. }
  149. public override void Dispose()
  150. {
  151. }
  152. // see IUserDataPlugin
  153. public override UserProfileData GetUserByName(string user, string last)
  154. {
  155. MySQLSuperManager dbm = GetLockedConnection("GetUserByName");
  156. try
  157. {
  158. Dictionary<string, object> param = new Dictionary<string, object>();
  159. param["?first"] = user;
  160. param["?second"] = last;
  161. IDbCommand result =
  162. dbm.Manager.Query(
  163. "SELECT * FROM " + m_usersTableName + " WHERE username = ?first AND lastname = ?second", param);
  164. IDataReader reader = result.ExecuteReader();
  165. UserProfileData row = dbm.Manager.readUserRow(reader);
  166. reader.Dispose();
  167. result.Dispose();
  168. return row;
  169. }
  170. catch (Exception e)
  171. {
  172. dbm.Manager.Reconnect();
  173. m_log.Error(e.ToString());
  174. return null;
  175. }
  176. finally
  177. {
  178. dbm.Release();
  179. }
  180. }
  181. #region User Friends List Data
  182. public override void AddNewUserFriend(UUID friendlistowner, UUID friend, uint perms)
  183. {
  184. int dtvalue = Util.UnixTimeSinceEpoch();
  185. Dictionary<string, object> param = new Dictionary<string, object>();
  186. param["?ownerID"] = friendlistowner.ToString();
  187. param["?friendID"] = friend.ToString();
  188. param["?friendPerms"] = perms.ToString();
  189. param["?datetimestamp"] = dtvalue.ToString();
  190. MySQLSuperManager dbm = GetLockedConnection("AddNewUserFriend");
  191. try
  192. {
  193. IDbCommand adder =
  194. dbm.Manager.Query(
  195. "INSERT INTO `" + m_userFriendsTableName + "` " +
  196. "(`ownerID`,`friendID`,`friendPerms`,`datetimestamp`) " +
  197. "VALUES " +
  198. "(?ownerID,?friendID,?friendPerms,?datetimestamp)",
  199. param);
  200. adder.ExecuteNonQuery();
  201. adder =
  202. dbm.Manager.Query(
  203. "INSERT INTO `" + m_userFriendsTableName + "` " +
  204. "(`ownerID`,`friendID`,`friendPerms`,`datetimestamp`) " +
  205. "VALUES " +
  206. "(?friendID,?ownerID,?friendPerms,?datetimestamp)",
  207. param);
  208. adder.ExecuteNonQuery();
  209. }
  210. catch (Exception e)
  211. {
  212. dbm.Manager.Reconnect();
  213. m_log.Error(e.ToString());
  214. return;
  215. }
  216. finally
  217. {
  218. dbm.Release();
  219. }
  220. }
  221. public override void RemoveUserFriend(UUID friendlistowner, UUID friend)
  222. {
  223. Dictionary<string, object> param = new Dictionary<string, object>();
  224. param["?ownerID"] = friendlistowner.ToString();
  225. param["?friendID"] = friend.ToString();
  226. MySQLSuperManager dbm = GetLockedConnection("RemoveUserFriend");
  227. try
  228. {
  229. IDbCommand updater =
  230. dbm.Manager.Query(
  231. "delete from " + m_userFriendsTableName + " where ownerID = ?ownerID and friendID = ?friendID",
  232. param);
  233. updater.ExecuteNonQuery();
  234. updater =
  235. dbm.Manager.Query(
  236. "delete from " + m_userFriendsTableName + " where ownerID = ?friendID and friendID = ?ownerID",
  237. param);
  238. updater.ExecuteNonQuery();
  239. }
  240. catch (Exception e)
  241. {
  242. dbm.Manager.Reconnect();
  243. m_log.Error(e.ToString());
  244. return;
  245. }
  246. finally
  247. {
  248. dbm.Release();
  249. }
  250. }
  251. public override void UpdateUserFriendPerms(UUID friendlistowner, UUID friend, uint perms)
  252. {
  253. Dictionary<string, object> param = new Dictionary<string, object>();
  254. param["?ownerID"] = friendlistowner.ToString();
  255. param["?friendID"] = friend.ToString();
  256. param["?friendPerms"] = perms.ToString();
  257. MySQLSuperManager dbm = GetLockedConnection("UpdateUserFriendPerms");
  258. try
  259. {
  260. IDbCommand updater =
  261. dbm.Manager.Query(
  262. "update " + m_userFriendsTableName +
  263. " SET friendPerms = ?friendPerms " +
  264. "where ownerID = ?ownerID and friendID = ?friendID",
  265. param);
  266. updater.ExecuteNonQuery();
  267. }
  268. catch (Exception e)
  269. {
  270. dbm.Manager.Reconnect();
  271. m_log.Error(e.ToString());
  272. return;
  273. }
  274. finally
  275. {
  276. dbm.Release();
  277. }
  278. }
  279. public override List<FriendListItem> GetUserFriendList(UUID friendlistowner)
  280. {
  281. List<FriendListItem> Lfli = new List<FriendListItem>();
  282. Dictionary<string, object> param = new Dictionary<string, object>();
  283. param["?ownerID"] = friendlistowner.ToString();
  284. MySQLSuperManager dbm = GetLockedConnection("GetUserFriendList");
  285. try
  286. {
  287. //Left Join userfriends to itself
  288. IDbCommand result =
  289. dbm.Manager.Query(
  290. "select a.ownerID,a.friendID,a.friendPerms,b.friendPerms as ownerperms from " +
  291. m_userFriendsTableName + " as a, " + m_userFriendsTableName + " as b" +
  292. " where a.ownerID = ?ownerID and b.ownerID = a.friendID and b.friendID = a.ownerID",
  293. param);
  294. IDataReader reader = result.ExecuteReader();
  295. while (reader.Read())
  296. {
  297. FriendListItem fli = new FriendListItem();
  298. fli.FriendListOwner = new UUID((string) reader["ownerID"]);
  299. fli.Friend = new UUID((string) reader["friendID"]);
  300. fli.FriendPerms = (uint) Convert.ToInt32(reader["friendPerms"]);
  301. // This is not a real column in the database table, it's a joined column from the opposite record
  302. fli.FriendListOwnerPerms = (uint) Convert.ToInt32(reader["ownerperms"]);
  303. Lfli.Add(fli);
  304. }
  305. reader.Dispose();
  306. result.Dispose();
  307. }
  308. catch (Exception e)
  309. {
  310. dbm.Manager.Reconnect();
  311. m_log.Error(e.ToString());
  312. return Lfli;
  313. }
  314. finally
  315. {
  316. dbm.Release();
  317. }
  318. return Lfli;
  319. }
  320. override public Dictionary<UUID, FriendRegionInfo> GetFriendRegionInfos (List<UUID> uuids)
  321. {
  322. MySQLSuperManager dbm = GetLockedConnection("GetFriendRegionInfos");
  323. Dictionary<UUID, FriendRegionInfo> infos = new Dictionary<UUID,FriendRegionInfo>();
  324. try
  325. {
  326. foreach (UUID uuid in uuids)
  327. {
  328. Dictionary<string, object> param = new Dictionary<string, object>();
  329. param["?uuid"] = uuid.ToString();
  330. IDbCommand result =
  331. dbm.Manager.Query("select agentOnline,currentHandle from " + m_agentsTableName +
  332. " where UUID = ?uuid", param);
  333. IDataReader reader = result.ExecuteReader();
  334. while (reader.Read())
  335. {
  336. FriendRegionInfo fri = new FriendRegionInfo();
  337. fri.isOnline = (sbyte)reader["agentOnline"] != 0;
  338. fri.regionHandle = (ulong)reader["currentHandle"];
  339. infos[uuid] = fri;
  340. }
  341. reader.Dispose();
  342. result.Dispose();
  343. }
  344. }
  345. catch (Exception e)
  346. {
  347. m_log.Warn("[MYSQL]: Got exception on trying to find friends regions:", e);
  348. dbm.Manager.Reconnect();
  349. m_log.Error(e.ToString());
  350. }
  351. finally
  352. {
  353. dbm.Release();
  354. }
  355. return infos;
  356. }
  357. #endregion
  358. public override List<AvatarPickerAvatar> GeneratePickerResults(UUID queryID, string query)
  359. {
  360. List<AvatarPickerAvatar> returnlist = new List<AvatarPickerAvatar>();
  361. Regex objAlphaNumericPattern = new Regex("[^a-zA-Z0-9]");
  362. string[] querysplit;
  363. querysplit = query.Split(' ');
  364. if (querysplit.Length > 1 && querysplit[1].Trim() != String.Empty)
  365. {
  366. Dictionary<string, object> param = new Dictionary<string, object>();
  367. param["?first"] = objAlphaNumericPattern.Replace(querysplit[0], String.Empty) + "%";
  368. param["?second"] = objAlphaNumericPattern.Replace(querysplit[1], String.Empty) + "%";
  369. MySQLSuperManager dbm = GetLockedConnection("GeneratePickerResults");
  370. try
  371. {
  372. IDbCommand result =
  373. dbm.Manager.Query(
  374. "SELECT UUID,username,lastname FROM " + m_usersTableName +
  375. " WHERE username like ?first AND lastname like ?second LIMIT 100",
  376. param);
  377. IDataReader reader = result.ExecuteReader();
  378. while (reader.Read())
  379. {
  380. AvatarPickerAvatar user = new AvatarPickerAvatar();
  381. user.AvatarID = new UUID((string) reader["UUID"]);
  382. user.firstName = (string) reader["username"];
  383. user.lastName = (string) reader["lastname"];
  384. returnlist.Add(user);
  385. }
  386. reader.Dispose();
  387. result.Dispose();
  388. }
  389. catch (Exception e)
  390. {
  391. dbm.Manager.Reconnect();
  392. m_log.Error(e.ToString());
  393. return returnlist;
  394. }
  395. finally
  396. {
  397. dbm.Release();
  398. }
  399. }
  400. else
  401. {
  402. MySQLSuperManager dbm = GetLockedConnection("GeneratePickerResults");
  403. try
  404. {
  405. Dictionary<string, object> param = new Dictionary<string, object>();
  406. param["?first"] = objAlphaNumericPattern.Replace(querysplit[0], String.Empty) + "%";
  407. IDbCommand result =
  408. dbm.Manager.Query(
  409. "SELECT UUID,username,lastname FROM " + m_usersTableName +
  410. " WHERE username like ?first OR lastname like ?first LIMIT 100",
  411. param);
  412. IDataReader reader = result.ExecuteReader();
  413. while (reader.Read())
  414. {
  415. AvatarPickerAvatar user = new AvatarPickerAvatar();
  416. user.AvatarID = new UUID((string) reader["UUID"]);
  417. user.firstName = (string) reader["username"];
  418. user.lastName = (string) reader["lastname"];
  419. returnlist.Add(user);
  420. }
  421. reader.Dispose();
  422. result.Dispose();
  423. }
  424. catch (Exception e)
  425. {
  426. dbm.Manager.Reconnect();
  427. m_log.Error(e.ToString());
  428. return returnlist;
  429. }
  430. finally
  431. {
  432. dbm.Release();
  433. }
  434. }
  435. return returnlist;
  436. }
  437. /// <summary>
  438. /// See IUserDataPlugin
  439. /// </summary>
  440. /// <param name="uuid">User UUID</param>
  441. /// <returns>User profile data</returns>
  442. public override UserProfileData GetUserByUUID(UUID uuid)
  443. {
  444. MySQLSuperManager dbm = GetLockedConnection("GetUserByUUID");
  445. try
  446. {
  447. Dictionary<string, object> param = new Dictionary<string, object>();
  448. param["?uuid"] = uuid.ToString();
  449. IDbCommand result = dbm.Manager.Query("SELECT * FROM " + m_usersTableName + " WHERE UUID = ?uuid", param);
  450. IDataReader reader = result.ExecuteReader();
  451. UserProfileData row = dbm.Manager.readUserRow(reader);
  452. reader.Dispose();
  453. result.Dispose();
  454. return row;
  455. }
  456. catch (Exception e)
  457. {
  458. dbm.Manager.Reconnect();
  459. m_log.Error(e.ToString());
  460. return null;
  461. }
  462. finally
  463. {
  464. dbm.Release();
  465. }
  466. }
  467. /// <summary>
  468. /// Returns a user session searching by name
  469. /// </summary>
  470. /// <param name="name">The account name : "Username Lastname"</param>
  471. /// <returns>The users session</returns>
  472. public override UserAgentData GetAgentByName(string name)
  473. {
  474. return GetAgentByName(name.Split(' ')[0], name.Split(' ')[1]);
  475. }
  476. /// <summary>
  477. /// Returns a user session by account name
  478. /// </summary>
  479. /// <param name="user">First part of the users account name</param>
  480. /// <param name="last">Second part of the users account name</param>
  481. /// <returns>The users session</returns>
  482. public override UserAgentData GetAgentByName(string user, string last)
  483. {
  484. UserProfileData profile = GetUserByName(user, last);
  485. return GetAgentByUUID(profile.ID);
  486. }
  487. /// <summary>
  488. /// </summary>
  489. /// <param name="AgentID"></param>
  490. /// <param name="WebLoginKey"></param>
  491. /// <remarks>is it still used ?</remarks>
  492. public override void StoreWebLoginKey(UUID AgentID, UUID WebLoginKey)
  493. {
  494. Dictionary<string, string> param = new Dictionary<string, string>();
  495. param["?UUID"] = AgentID.ToString();
  496. param["?webLoginKey"] = WebLoginKey.ToString();
  497. MySQLSuperManager dbm = GetLockedConnection("StoreWebLoginKey");
  498. try
  499. {
  500. dbm.Manager.ExecuteParameterizedSql(
  501. "update " + m_usersTableName + " SET webLoginKey = ?webLoginKey " +
  502. "where UUID = ?UUID",
  503. param);
  504. }
  505. catch (Exception e)
  506. {
  507. dbm.Manager.Reconnect();
  508. m_log.Error(e.ToString());
  509. return;
  510. }
  511. finally
  512. {
  513. dbm.Release();
  514. }
  515. }
  516. /// <summary>
  517. /// Returns an agent session by account UUID
  518. /// </summary>
  519. /// <param name="uuid">The accounts UUID</param>
  520. /// <returns>The users session</returns>
  521. public override UserAgentData GetAgentByUUID(UUID uuid)
  522. {
  523. MySQLSuperManager dbm = GetLockedConnection("GetAgentByUUID");
  524. try
  525. {
  526. Dictionary<string, object> param = new Dictionary<string, object>();
  527. param["?uuid"] = uuid.ToString();
  528. IDbCommand result = dbm.Manager.Query("SELECT * FROM " + m_agentsTableName + " WHERE UUID = ?uuid",
  529. param);
  530. IDataReader reader = result.ExecuteReader();
  531. UserAgentData row = dbm.Manager.readAgentRow(reader);
  532. reader.Dispose();
  533. result.Dispose();
  534. return row;
  535. }
  536. catch (Exception e)
  537. {
  538. dbm.Manager.Reconnect();
  539. m_log.Error(e.ToString());
  540. return null;
  541. }
  542. finally
  543. {
  544. dbm.Release();
  545. }
  546. }
  547. /// <summary>
  548. /// Creates a new users profile
  549. /// </summary>
  550. /// <param name="user">The user profile to create</param>
  551. public override void AddNewUserProfile(UserProfileData user)
  552. {
  553. UUID zero = UUID.Zero;
  554. if (user.ID == zero)
  555. {
  556. return;
  557. }
  558. MySQLSuperManager dbm = GetLockedConnection("AddNewUserProfile");
  559. try
  560. {
  561. dbm.Manager.insertUserRow(user.ID, user.FirstName, user.SurName, user.Email, user.PasswordHash, user.PasswordSalt,
  562. user.HomeRegion, user.HomeRegionID, user.HomeLocation.X, user.HomeLocation.Y,
  563. user.HomeLocation.Z,
  564. user.HomeLookAt.X, user.HomeLookAt.Y, user.HomeLookAt.Z, user.Created,
  565. user.LastLogin, user.UserInventoryURI, user.UserAssetURI,
  566. user.CanDoMask, user.WantDoMask,
  567. user.AboutText, user.FirstLifeAboutText, user.Image,
  568. user.FirstLifeImage, user.WebLoginKey, user.UserFlags, user.GodLevel, user.CustomType, user.Partner);
  569. }
  570. catch (Exception e)
  571. {
  572. dbm.Manager.Reconnect();
  573. m_log.Error(e.ToString());
  574. }
  575. finally
  576. {
  577. dbm.Release();
  578. }
  579. }
  580. /// <summary>
  581. /// Creates a new agent
  582. /// </summary>
  583. /// <param name="agent">The agent to create</param>
  584. public override void AddNewUserAgent(UserAgentData agent)
  585. {
  586. UUID zero = UUID.Zero;
  587. if (agent.ProfileID == zero || agent.SessionID == zero)
  588. return;
  589. MySQLSuperManager dbm = GetLockedConnection("AddNewUserAgent");
  590. try
  591. {
  592. dbm.Manager.insertAgentRow(agent);
  593. }
  594. catch (Exception e)
  595. {
  596. dbm.Manager.Reconnect();
  597. m_log.Error(e.ToString());
  598. }
  599. finally
  600. {
  601. dbm.Release();
  602. }
  603. }
  604. /// <summary>
  605. /// Updates a user profile stored in the DB
  606. /// </summary>
  607. /// <param name="user">The profile data to use to update the DB</param>
  608. public override bool UpdateUserProfile(UserProfileData user)
  609. {
  610. MySQLSuperManager dbm = GetLockedConnection("UpdateUserProfile");
  611. try
  612. {
  613. dbm.Manager.updateUserRow(user.ID, user.FirstName, user.SurName, user.Email, user.PasswordHash, user.PasswordSalt,
  614. user.HomeRegion, user.HomeRegionID, user.HomeLocation.X, user.HomeLocation.Y,
  615. user.HomeLocation.Z, user.HomeLookAt.X,
  616. user.HomeLookAt.Y, user.HomeLookAt.Z, user.Created, user.LastLogin,
  617. user.UserInventoryURI,
  618. user.UserAssetURI, user.CanDoMask, user.WantDoMask, user.AboutText,
  619. user.FirstLifeAboutText, user.Image, user.FirstLifeImage, user.WebLoginKey,
  620. user.UserFlags, user.GodLevel, user.CustomType, user.Partner);
  621. }
  622. finally
  623. {
  624. dbm.Release();
  625. }
  626. return true;
  627. }
  628. /// <summary>
  629. /// Performs a money transfer request between two accounts
  630. /// </summary>
  631. /// <param name="from">The senders account ID</param>
  632. /// <param name="to">The receivers account ID</param>
  633. /// <param name="amount">The amount to transfer</param>
  634. /// <returns>Success?</returns>
  635. public override bool MoneyTransferRequest(UUID from, UUID to, uint amount)
  636. {
  637. return false;
  638. }
  639. /// <summary>
  640. /// Performs an inventory transfer request between two accounts
  641. /// </summary>
  642. /// <remarks>TODO: Move to inventory server</remarks>
  643. /// <param name="from">The senders account ID</param>
  644. /// <param name="to">The receivers account ID</param>
  645. /// <param name="item">The item to transfer</param>
  646. /// <returns>Success?</returns>
  647. public override bool InventoryTransferRequest(UUID from, UUID to, UUID item)
  648. {
  649. return false;
  650. }
  651. /// <summary>
  652. /// Appearance
  653. /// TODO: stubs for now to get us to a compiling state gently
  654. /// override
  655. /// </summary>
  656. public override AvatarAppearance GetUserAppearance(UUID user)
  657. {
  658. MySQLSuperManager dbm = GetLockedConnection("GetUserAppearance");
  659. try
  660. {
  661. Dictionary<string, object> param = new Dictionary<string, object>();
  662. param["?owner"] = user.ToString();
  663. IDbCommand result = dbm.Manager.Query(
  664. "SELECT * FROM " + m_appearanceTableName + " WHERE owner = ?owner", param);
  665. IDataReader reader = result.ExecuteReader();
  666. AvatarAppearance appearance = dbm.Manager.readAppearanceRow(reader);
  667. reader.Dispose();
  668. result.Dispose();
  669. if (null == appearance)
  670. {
  671. m_log.WarnFormat("[USER DB] No appearance found for user {0}", user.ToString());
  672. return null;
  673. }
  674. appearance.SetAttachments(GetUserAttachments(user));
  675. return appearance;
  676. }
  677. catch (Exception e)
  678. {
  679. dbm.Manager.Reconnect();
  680. m_log.Error(e.ToString());
  681. return null;
  682. }
  683. finally
  684. {
  685. dbm.Release();
  686. }
  687. }
  688. /// <summary>
  689. /// Updates an avatar appearence
  690. /// </summary>
  691. /// <param name="user">The user UUID</param>
  692. /// <param name="appearance">The avatar appearance</param>
  693. // override
  694. public override void UpdateUserAppearance(UUID user, AvatarAppearance appearance)
  695. {
  696. MySQLSuperManager dbm = GetLockedConnection("UpdateUserAppearance");
  697. try
  698. {
  699. appearance.Owner = user;
  700. dbm.Manager.insertAppearanceRow(appearance);
  701. UpdateUserAttachments(user, appearance.GetAttachments());
  702. }
  703. catch (Exception e)
  704. {
  705. dbm.Manager.Reconnect();
  706. m_log.Error(e.ToString());
  707. }
  708. finally
  709. {
  710. dbm.Release();
  711. }
  712. }
  713. /// <summary>
  714. /// Database provider name
  715. /// </summary>
  716. /// <returns>Provider name</returns>
  717. public override string Name
  718. {
  719. get { return "MySQL Userdata Interface"; }
  720. }
  721. /// <summary>
  722. /// Database provider version
  723. /// </summary>
  724. /// <returns>provider version</returns>
  725. public override string Version
  726. {
  727. get { return "0.1"; }
  728. }
  729. public Hashtable GetUserAttachments(UUID agentID)
  730. {
  731. Dictionary<string, object> param = new Dictionary<string, object>();
  732. param["?uuid"] = agentID.ToString();
  733. MySQLSuperManager dbm = GetLockedConnection("GetUserAttachments");
  734. try
  735. {
  736. IDbCommand result = dbm.Manager.Query(
  737. "SELECT attachpoint, item, asset from " + m_attachmentsTableName + " WHERE UUID = ?uuid", param);
  738. IDataReader reader = result.ExecuteReader();
  739. Hashtable ret = dbm.Manager.readAttachments(reader);
  740. reader.Dispose();
  741. result.Dispose();
  742. return ret;
  743. }
  744. catch (Exception e)
  745. {
  746. dbm.Manager.Reconnect();
  747. m_log.Error(e.ToString());
  748. return null;
  749. }
  750. finally
  751. {
  752. dbm.Release();
  753. }
  754. }
  755. public void UpdateUserAttachments(UUID agentID, Hashtable data)
  756. {
  757. MySQLSuperManager dbm = GetLockedConnection("UpdateUserAttachments");
  758. try
  759. {
  760. dbm.Manager.writeAttachments(agentID, data);
  761. }
  762. finally
  763. {
  764. dbm.Release();
  765. }
  766. }
  767. public override void ResetAttachments(UUID userID)
  768. {
  769. Dictionary<string, string> param = new Dictionary<string, string>();
  770. param["?uuid"] = userID.ToString();
  771. MySQLSuperManager dbm = GetLockedConnection("ResetAttachments");
  772. try
  773. {
  774. dbm.Manager.ExecuteParameterizedSql(
  775. "UPDATE " + m_attachmentsTableName +
  776. " SET asset = '00000000-0000-0000-0000-000000000000' WHERE UUID = ?uuid",
  777. param);
  778. }
  779. finally
  780. {
  781. dbm.Release();
  782. }
  783. }
  784. public override void LogoutUsers(UUID regionID)
  785. {
  786. Dictionary<string, string> param = new Dictionary<string, string>();
  787. param["?regionID"] = regionID.ToString();
  788. MySQLSuperManager dbm = GetLockedConnection("LogoutUsers");
  789. try
  790. {
  791. dbm.Manager.ExecuteParameterizedSql(
  792. "update " + m_agentsTableName + " SET agentOnline = 0 " +
  793. "where currentRegion = ?regionID",
  794. param);
  795. }
  796. catch (Exception e)
  797. {
  798. dbm.Manager.Reconnect();
  799. m_log.Error(e.ToString());
  800. return;
  801. }
  802. finally
  803. {
  804. dbm.Release();
  805. }
  806. }
  807. }
  808. }